I think we abused the topic in Beginners Help long enough
![Very Happy :D](./images/smilies/icon_biggrin.gif)
I created a shield effect:
edit In Action: http://www.youtube.com/watch?v=MMFfVfzthP0&fmt=18
![Image](http://img40.imageshack.us/img40/5063/shieldsl.jpg)
Fast Download: http://www.file-upload.net/download-254 ... ct.7z.html
edit
Put a "permanent" link on my website: http://www.freetimestudio.de/index.php? ... tware&id=9
This is the code:
CShieldManager.h
Code: Select all
#ifndef CSHIELDMANAGER_H_INCLUDED
#define CSHIELDMANAGER_H_INCLUDED
#include <irrlicht.h>
using namespace irr;
//! The Shield Manager manages shields, impacts and rendering those.
/** All shields and impacts are structs sorted in an array. The shields
are managed in an array attribute of the manager and the impact in an array of
the respective shield.
The manager also has a drawAll method like the scene manager. It is used the same way.
You can add any mesh node as a shield. However, it is recomended that you use nodes that are
transparent with EMT_TRANSPARENT_ADD_COLOR or EMT_TRANSPARENT_ALPHA_CHANNEL. \n
The first texture of the node should be completely transparent (layer 0). \n
The second will be used as a base color map by the shader (layer 1). \n
The third texture will be used for a gradient effect (layer 2). \n*/
class CShieldManager: public video::IShaderConstantSetCallBack
{
private:
//!Struct to handle the impacts
struct SImpact
{
//Position of the impact in local node space
core::vector3df pos;
//Color of the impact
video::SColorf color;
//Maximum radius
f32 radius;
//To determine when to delete the impact from the shield's array
u32 startTime;
u32 endTime;
};
//!Struct to handle the shield nodes
struct SShield
{
//The node
scene::ISceneNode *shieldNode;
//The array of impacts on this shield
core::array<SImpact> array_Impacts;
};
public:
//!Constructor
/**Sets up the manager and creates the shader
\param psmgr SceneManager of the device
\param ptimer Timer of the device*/
CShieldManager(scene::ISceneManager* psmgr, irr::ITimer *ptimer);
//!Destructor
~CShieldManager();
//!Renders the shields
void drawAll();
//!Sets the uniform variables for the shader
virtual void OnSetConstants(video::IMaterialRendererServices* services,s32 userData);
//!Add a new shield
/**\return true if it is a new shield, false if the shield already exists
\param node The node that shall act as a shield */
bool addShield(scene::ISceneNode *node);
//!Remove a shield
/**\return true if it shield was removed, false if the shield was not found
\param node The shield that shall be removed */
bool removeShield(scene::ISceneNode *node);
//!Add an impact in object space to the shield
/**\return true if the shield exists and the impact has been added
\param node The node that acts as a shield
\param position The position of the impact on the shield in the shieldnode's local space
\param radius The maximum radius of the impact
\param duration The impact's lifespan
\param color The Color of the impact*/
bool addLocalImpact(const scene::ISceneNode *node, const core::vector3df position,const f32 radius=1, const u32 duration=500, const video::SColorf color = video::SColorf(1,1,1,1));
//!Add an impact in global space to the shield
/**\return true if the shield exists and the impact has been added
\param node The node that acts as a shield
\param position The position of the impact on the shield in global space
\param radius The maximum radius of the impact
\param duration The impact's lifespan
\param color The Color of the impact*/
bool addGlobalImpact(const scene::ISceneNode *node, core::vector3df &position,const f32 radius=1, const u32 duration=500, const video::SColorf color = video::SColorf(1,1,1,1));
//!Let the manager determine the impact position by using a given ray
/**\return the local position of the impact when successful, the ray's end otherwise
\param node The node that acts as a shield
\param ray The ray that hits the shield
\param radius The maximum radius of the impact
\param duration The impact's lifespan
\param color The Color of the impact*/
core::vector3df addImpact(const scene::ISceneNode *node, const core::line3df ray, const f32 radius=1, const u32 duration=500, const video::SColorf color = video::SColorf(1,1,1,1));
private:
//To check if the shields are currently visible
scene::ISceneManager* smgr;
//To draw the shields/impacts
video::IVideoDriver* driver;
//To erase impacts after their lifetime
irr::ITimer *timer;
//Manage the shields
core::array<SShield> array_Shields;
//The shield shader
int shaderMaterial;
//For compatibility
//no shader: -1
//arb shader 0;
//glsl shader 1;
int ShaderType;
//The following attributes parameters for the OnSetConstants method
//Radius of the current impact
f32 tmp_radius;
//Position of the current impact
core::vector3df tmp_position;
//Color of the current impact
video::SColorf tmp_color;
};
#endif // CSHIELDMANAGER_H_INCLUDED
edit Added Viz_fuerte's arb shader
CShieldManager.cpp
Code: Select all
#include "CShieldManager.h"
CShieldManager::CShieldManager(scene::ISceneManager* psmgr, irr::ITimer *ptimer){
//Assign all parameters
smgr = psmgr;
driver=psmgr->getVideoDriver();
timer = ptimer;
ShaderType=-1;
shaderMaterial = video::EMT_SOLID;
//Witout OpenGL these shaders won't work
if(!driver->getDriverType()==video::EDT_OPENGL)
return;
if(driver->queryFeature(video::EVDF_ARB_GLSL)){
///GLSL Shader Code
//Vertex Shader
const c8 *vertShader = "varying vec3 vertpos; \n\
\n\
void main(void) \n\
{ \n\
vertpos = gl_Vertex.xyz; \n\
\n\
gl_TexCoord[0] = gl_MultiTexCoord0; \n\
gl_Position = ftransform(); \n\
} \n\
";
//Fragment Shader
const c8 *fragShader = "uniform sampler2D ColorMap; \n\
uniform sampler2D GradientTexture; \n\
uniform float radius; \n\
uniform vec4 color; \n\
uniform vec3 current_position; \n\
\n\
varying vec3 vertpos; \n\
\n\
void main(void) \n\
{ \n\
vec3 dif = vertpos - current_position; \n\
float dist = dif.x*dif.x + dif.y*dif.y + dif.z*dif.z; \n\
\n\
float intensity=1/dist*radius*0.01; \n\
if(intensity>0.9) \n\
intensity=0.9; \n\
if(intensity<0) \n\
intensity=0; \n\
\n\
vec4 diffuse = texture2D(ColorMap, vec2(gl_TexCoord[0])); \n\
vec4 gradient = vec4(texture2D(GradientTexture,vec2(intensity,1))); \n\
\n\
vec4 final_color = gradient*diffuse*intensity*color; \n\
\n\
gl_FragColor=final_color; \n\
} \n\
";
ShaderType = 1;
//Create the shader material
shaderMaterial = driver->getGPUProgrammingServices()->addHighLevelShaderMaterial(
vertShader, "main", video::EVST_VS_1_1,
fragShader, "main", video::EPST_PS_1_1,
this, video::EMT_ONETEXTURE_BLEND);
}else{
if(driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1) && driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
//ARB Shader for compatibility from Viz_fuerte
const c8 *vertShader = "!!ARBvp1.0\n\
\n\
PARAM c[5] = { program.local[0],\n\
state.matrix.mvp };\n\
\n\
MOV result.texcoord[0], vertex.texcoord[0];\n\
MOV result.texcoord[1].xyz, vertex.position;\n\
DP4 result.position.w, vertex.position, c[4];\n\
DP4 result.position.z, vertex.position, c[3];\n\
DP4 result.position.y, vertex.position, c[2];\n\
DP4 result.position.x, vertex.position, c[1];\n\
END\n\
";
const c8 *fragShader = "!!ARBfp1.0\n\
OPTION ARB_precision_hint_nicest;\n\
\n\
# texture ColorMap -> index 0\n\
# texture GradientTexture -> index 1\n\
\n\
# float radius -> 0\n\
# float[4] color -> 1\n\
# float[3] current_position -> 2\n\
\n\
\n\
PARAM c[4] = { program.local[0..2],\n\
{ 0.0099999998, 0.89999998, 0, 1 } };\n\
TEMP R0;\n\
TEMP R1;\n\
TEMP R2;\n\
ADD R0.xyz, fragment.texcoord[1], -c[2];\n\
MUL R0.y, R0, R0;\n\
MAD R0.x, R0, R0, R0.y;\n\
MAD R0.x, R0.z, R0.z, R0;\n\
RSQ R0.x, R0.x;\n\
RCP R0.x, R0.x;\n\
MUL R0.x, R0, R0;\n\
RCP R0.x, R0.x;\n\
MUL R0.x, R0, c[0];\n\
MUL R0.x, R0, c[3];\n\
ADD R0.y, R0.x, -c[3];\n\
CMP R0.x, -R0.y, c[3].y, R0;\n\
CMP R2.x, R0, c[3].z, R0;\n\
MOV R2.y, c[3].w;\n\
TEX R1, fragment.texcoord[0], texture[0], 2D;\n\
TEX R0, R2, texture[1], 2D;\n\
MUL R0, R0, R1;\n\
MUL R0, R0, R2.x;\n\
MUL result.color, R0, c[1];\n\
END\n\
";
ShaderType=0;
shaderMaterial = driver->getGPUProgrammingServices()->addShaderMaterial(
vertShader,fragShader,this, video::EMT_ONETEXTURE_BLEND);
}
}
}
CShieldManager::~CShieldManager(){
//Erase everything
for(u32 i=0; i<array_Shields.size();i++){
while(!array_Shields[i].array_Impacts.empty()){
array_Shields[i].array_Impacts.erase(0);
}
}
while(!array_Shields.empty()){
array_Shields.erase(0);
}
}
bool CShieldManager::addShield(scene::ISceneNode *node){
//Check if shield already exists
for(u32 i=0; i<array_Shields.size();i++){
if(array_Shields[i].shieldNode == node){
//Shield already exists
return false;
}
}
//Create a new shield
SShield tmpShield;
tmpShield.shieldNode = node;
array_Shields.push_back(tmpShield);
return true;
}
bool CShieldManager::removeShield(scene::ISceneNode *node){
//Check if shield exists
for(u32 i=0; i<array_Shields.size();i++){
if(array_Shields[i].shieldNode == node){
//Erase all impacts of the shield
while(!array_Shields[i].array_Impacts.empty()){
array_Shields[i].array_Impacts.erase(0);
}
array_Shields.erase(i);
return true;
}
}
return false;
}
bool CShieldManager::addLocalImpact(const scene::ISceneNode *node, const core::vector3df position,const f32 radius, const u32 duration, const video::SColorf color)
{
//Find the shield
for(u32 i=0; i<array_Shields.size();i++){
if(array_Shields[i].shieldNode == node){
//Create a new impact
SImpact tmpImpact;
tmpImpact.pos = position;
tmpImpact.startTime = timer->getTime();
tmpImpact.endTime = timer->getTime()+duration;
tmpImpact.radius = radius;
tmpImpact.color = color;
array_Shields[i].array_Impacts.push_back(tmpImpact);
return true;
}
}
//Shield was not found
return false;
}
bool CShieldManager::addGlobalImpact(const scene::ISceneNode *node, core::vector3df &position,const f32 radius, const u32 duration, const video::SColorf color)
{
//Find the shield
for(u32 i=0; i<array_Shields.size();i++){
if(array_Shields[i].shieldNode == node){
//Transform the position to local space
core::matrix4 trans = node->getAbsoluteTransformation();
trans.makeInverse();
trans.transformVect(position);
//Create a new impact
SImpact tmpImpact;
tmpImpact.pos = position;
tmpImpact.startTime = timer->getTime();
tmpImpact.endTime = timer->getTime()+duration;
tmpImpact.radius = radius;
tmpImpact.color = color;
array_Shields[i].array_Impacts.push_back(tmpImpact);
return true;
}
}
//Shield was not found
return false;
}
core::vector3df CShieldManager::addImpact(const scene::ISceneNode *node, const core::line3df ray, const f32 radius, const u32 duration, const video::SColorf color){
//Check if node pointer is given, otherwise the collision point routine will crash
if(!node)
return ray.end;
//Check for intersection
core::vector3df colPoint;
core::triangle3df colTris;
const scene::ISceneNode* outNode;
if(smgr->getSceneCollisionManager()->getCollisionPoint(ray,
node->getTriangleSelector(), colPoint,
colTris, outNode))
{
//Intersection found
//Transform position to local space
core::vector3df tmpPoint = core::vector3df(colPoint);
core::matrix4 trans = node->getAbsoluteTransformation();
trans.makeInverse();
trans.transformVect(colPoint);
//Add impact
addLocalImpact(node,colPoint,radius,duration,color);
return tmpPoint;
}
//No intersection
return ray.end;
}
void CShieldManager::drawAll(){
for(u32 i=0; i<array_Shields.size();i++)
{
array_Shields[i].shieldNode->updateAbsolutePosition();
//Check for dead impacts and delete them
for(u32 j=0; j<array_Shields[i].array_Impacts.size();){
if(timer->getTime()>array_Shields[i].array_Impacts[j].endTime){ //If impact is dead
array_Shields[i].array_Impacts.erase(j);
}else{
++j;
}
}
//I learned this meshbuffer trick from Viz_Fuerte's "Simple but useful projects"
//Draw shield only when node is visible
if(!smgr->isCulled(array_Shields[i].shieldNode))
{
//Reset the transformation
driver->setTransform(video::ETS_WORLD,array_Shields[i].shieldNode->getAbsoluteTransformation());
//Draw all impacts
for(u32 j=0; j<array_Shields[i].array_Impacts.size();j++){
tmp_position = array_Shields[i].array_Impacts[j].pos;
//Calculate the impact's radius dependant on time
u32 dif1 = array_Shields[i].array_Impacts[j].endTime-array_Shields[i].array_Impacts[j].startTime;
u32 dif2 = timer->getTime()-array_Shields[i].array_Impacts[j].startTime;
//Range from start (0.0) to end (1.0)
f32 dif = (dif2/(dif1*1.0));
///Different effects for the shield:
///You can calculate the impacts radius with a function that uses "dif" as an argument. dif is betweeen 0.0 (life start) and 1.0 (life end)
///\n These are two preset effects:
/**1. Absorbing effect:
\code
tmp_radius = array_Shields[i].array_Impacts[j].radius*(0.25 - pow((dif-0.5),2));
tmp_color = array_Shields[i].array_Impacts[j].color;
\endcode
*/
/**2. Fade-out effect:
\code
tmp_radius = array_Shields[i].array_Impacts[j].radius*dif;
tmp_color = array_Shields[i].array_Impacts[j].color;
tmp_color.a = 1-dif;
\endcode
*/
//Using effect 2
tmp_radius = array_Shields[i].array_Impacts[j].radius*dif;
tmp_color = array_Shields[i].array_Impacts[j].color;
tmp_color.a = 1-dif;
//Draw the impact on all materials of the shield node
for(u32 k=0; k<array_Shields[i].shieldNode->getMaterialCount(); ++k)
{
video::SMaterial material = array_Shields[i].shieldNode->getMaterial(k);
material.MaterialType = (video::E_MATERIAL_TYPE)shaderMaterial;
material.MaterialTypeParam = pack_texureBlendFunc(video::EBF_SRC_ALPHA,video::EBF_ONE);
//Prevent transparency issues
material.setFlag(video::EMF_ZWRITE_ENABLE,false);
driver->setMaterial(material);
switch(array_Shields[i].shieldNode->getType()){
case scene::ESNT_ANIMATED_MESH:
driver->drawMeshBuffer(((scene::IAnimatedMeshSceneNode*)array_Shields[i].shieldNode)->getMesh()->getMeshBuffer(k));
break;
default:
driver->drawMeshBuffer(((scene::IMeshSceneNode*)array_Shields[i].shieldNode)->getMesh()->getMeshBuffer(k));
break;
};
}
}
}
}
}
//This is called for each impact render
void CShieldManager::OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
{
switch(ShaderType){
case 0:
// Color
services->setPixelShaderConstant((float*)(&tmp_color),1, 4);
// Radius
services->setPixelShaderConstant((float*)(&tmp_radius),0, 1);
// Current position
services->setPixelShaderConstant((float*)(&tmp_position),2, 3);
break;
case 1:
// Color
services->setPixelShaderConstant("color", (float*)(&tmp_color ), 4);
// Radius
services->setPixelShaderConstant("radius", (float*)(&tmp_radius ), 1);
// Current position
services->setPixelShaderConstant("current_position", (float*)(&tmp_position ), 3);
//Set the texture layers
int var0=0;
services->setPixelShaderConstant("ColorMap", (float*)(&var0), 1);
int var1=1;
services->setPixelShaderConstant("GradientTexture", (float*)(&var1), 1);
break;
};
}
Code: Select all
/** \mainpage Irrlicht Shield Effect
Creating a shield is easy. \n
First you have to create a shield manager:
\code
CShieldManager *shieldmanager = new CShieldManager(smgr,device->getTimer());
\endcode
This manager works like the ISceneManger from irrlicht, just for shields.\n
To add a shield, first create a scene node that you want to use as a shield e.g.
\code
scene::IMeshSceneNode shield_node = smgr->addSphereSceneNode(5);
\endcode
Next configure the material of the node, to make the shield visible from in- and outside
\code
shield_node->setMaterialFlag(video::EMF_BACK_FACE_CULLING,false);
\endcode
\n
Then you make the node invisible, so that it does not interfere with the shield render pass
\code
shield_node->setbVisible(false);
\endcode
\n
In case you want to use rays to let the manager calculate impacts, you have to create a triangle selector for the node:
\code
scene::ITriangleSelector *selector = smgr->createTriangleSelector(shield_node->getMesh(),shield_node);
shield_node->setTriangleSelector(selector);
selector->drop();
\endcode
At last you add the shield:
\code
shieldmanager->addShield(shield_node);
\endcode
To add impacts you have to call the addImpact/addLocalImpact/addGlobalImpact function.
To render the shields, call drawAll after the drawAll of the scene manager, otherwise the shields will be overdrawn by the rest of the scenery.
\n
\n
So thats that, have fun! \n
<a href="http://www.freetimestudio.de">www.freetimestudio.de</a>
*/
#include <irrlicht.h>
using namespace irr;
#include "CShieldManager.h"
//What shield type should be displayed
int shield_config = 3;
//The two shield nodes
scene::IMeshSceneNode *shield_node1;
scene::IAnimatedMeshSceneNode *shield_node2;
//Other attributes of the impacts
f32 radius = 1;
u32 duration = 500;
video::SColorf impact_color(1,1,1,1);
video::IVideoDriver *driver;
//!Simple Event receiver to process the space key and change the configuration
class myEventReceiver : public IEventReceiver{
public:
myEventReceiver(){};
~myEventReceiver(){};
virtual bool OnEvent(const SEvent& event)
{
if(event.EventType == EET_KEY_INPUT_EVENT){
if(!event.KeyInput.PressedDown){
if(event.KeyInput.Key == KEY_SPACE){
//Change the shield textures based on the configuration number
shield_config++;
shield_config = shield_config%5;
switch(shield_config){
case 0:
impact_color = video::SColorf(0,1,2,1);
duration = 500;
radius=60;
shield_node1->setMaterialTexture(0,driver->getTexture("Data/textures/shield_tex.png"));
shield_node1->setMaterialTexture(1,driver->getTexture("Data/textures/gradient.png"));
shield_node2->setMaterialTexture(0,driver->getTexture("Data/textures/shield_tex.png"));
shield_node2->setMaterialTexture(1,driver->getTexture("Data/textures/gradient.png"));
break;
case 1:
radius=10;
impact_color = video::SColorf(1,1,0,1);
duration = 1000;
shield_node1->setMaterialTexture(0,driver->getTexture("Data/textures/detailmap3.jpg"));
shield_node1->setMaterialTexture(1,driver->getTexture("Data/textures/gradient_color.png"));
shield_node2->setMaterialTexture(0,driver->getTexture("Data/textures/detailmap3.jpg"));
shield_node2->setMaterialTexture(1,driver->getTexture("Data/textures/gradient_color.png"));
break;
case 2:
radius=20;
impact_color = video::SColorf(0,1,0.5,1);
duration = 450;
shield_node1->setMaterialTexture(0,driver->getTexture("Data/textures/water.jpg"));
shield_node1->setMaterialTexture(1,driver->getTexture("Data/textures/gradient_blinds.png"));
shield_node2->setMaterialTexture(0,driver->getTexture("Data/textures/water.jpg"));
shield_node2->setMaterialTexture(1,driver->getTexture("Data/textures/gradient_blinds.png"));
break;
case 3:
radius=10;
impact_color = video::SColorf(3,1,0,1);
duration = 500;
shield_node1->setMaterialTexture(0,driver->getTexture("Data/textures/wall.jpg"));
shield_node1->setMaterialTexture(1,driver->getTexture("Data/textures/gradient_two.png"));
shield_node2->setMaterialTexture(0,driver->getTexture("Data/textures/wall.jpg"));
shield_node2->setMaterialTexture(1,driver->getTexture("Data/textures/gradient_two.png"));
break;
case 4:
radius=5;
impact_color = video::SColorf(3,1,0,1);
duration = 500;
shield_node1->setMaterialTexture(0,driver->getTexture("Data/textures/blank.png"));
shield_node1->setMaterialTexture(1,driver->getTexture("Data/textures/blank.png"));
shield_node2->setMaterialTexture(0,driver->getTexture("Data/textures/blank.png"));
shield_node2->setMaterialTexture(1,driver->getTexture("Data/textures/blank.png"));
break;
};
return true;
}
}
}
return false;
}
};
int main(int argc, char** argv)
{
//Set up device and receiver
myEventReceiver *receiver = new myEventReceiver();
IrrlichtDevice *device = createDevice(video::EDT_OPENGL, core::dimension2d<u32>(640,480), 32,false,false,false,receiver);
driver = device->getVideoDriver();
scene::ISceneManager *smgr = device->getSceneManager();
//Create the camera
SKeyMap keyMap[8];
keyMap[0].Action = EKA_MOVE_FORWARD;
keyMap[0].KeyCode = KEY_UP;
keyMap[1].Action = EKA_MOVE_FORWARD;
keyMap[1].KeyCode = KEY_KEY_W;
keyMap[2].Action = EKA_MOVE_BACKWARD;
keyMap[2].KeyCode = KEY_DOWN;
keyMap[3].Action = EKA_MOVE_BACKWARD;
keyMap[3].KeyCode = KEY_KEY_S;
keyMap[4].Action = EKA_STRAFE_LEFT;
keyMap[4].KeyCode = KEY_LEFT;
keyMap[5].Action = EKA_STRAFE_LEFT;
keyMap[5].KeyCode = KEY_KEY_A;
keyMap[6].Action = EKA_STRAFE_RIGHT;
keyMap[6].KeyCode = KEY_RIGHT;
keyMap[7].Action = EKA_STRAFE_RIGHT;
keyMap[7].KeyCode = KEY_KEY_D;
scene::ICameraSceneNode *camera = smgr->addCameraSceneNodeFPS(0,100,0.03,-1,keyMap,8);
camera->setPosition(core::vector3df(0,10,-40));
camera->setTarget(core::vector3df(10,5,0));
//Add a light
smgr->addLightSceneNode(0,core::vector3df(0,20,0),
video::SColorf(1.0f, 1.0f, 1.0f),
500.0f);
//Neccessary for textur coordinates changes of the shield nodes
scene::IMeshManipulator *manipulator = smgr->getMeshManipulator();
///Create the shield manager
CShieldManager *shieldmanager = new CShieldManager(smgr,device->getTimer());
//Add the first battle turtle
scene::IAnimatedMeshSceneNode *battle_turtle1 = smgr->addAnimatedMeshSceneNode(smgr->getMesh("Data/turtle.b3d"));
battle_turtle1->setMaterialTexture(0,driver->getTexture("Data/turtle_green.jpg"));
battle_turtle1->setScale(core::vector3df(0.25,0.25,0.25));
battle_turtle1->setPosition(core::vector3df(0,0,0));
battle_turtle1->setFrameLoop(0,10);
battle_turtle1->setAnimationSpeed(15);
//Add the battle turtle's shield
shield_node1 = smgr->addSphereSceneNode(1,32,battle_turtle1);
manipulator->scaleTCoords(shield_node1->getMesh(),core::vector2df(6,6),1);
shield_node1->setMaterialFlag(video::EMF_BACK_FACE_CULLING,false);
shield_node1->setScale(core::vector3df(20,20,20));
shield_node1->setVisible(false);
scene::ITriangleSelector *selector = smgr->createTriangleSelector(shield_node1->getMesh(),shield_node1);
shield_node1->setTriangleSelector(selector);
selector->drop();
shieldmanager->addShield(shield_node1);
//Add the second battle turtle
scene::IAnimatedMeshSceneNode *battle_turtle2 = smgr->addAnimatedMeshSceneNode(smgr->getMesh("Data/turtle.b3d"));
battle_turtle2->setMaterialTexture(0,driver->getTexture("Data/turtle_red.jpg"));
battle_turtle2->setScale(core::vector3df(0.25,0.25,0.25));
battle_turtle2->setPosition(core::vector3df(10,0,0));
battle_turtle2->setRotation(core::vector3df(0,180,0));
battle_turtle2->setFrameLoop(0,10);
battle_turtle2->setAnimationSpeed(15);
//Add the battle turtle's shield
shield_node2 = smgr->addAnimatedMeshSceneNode(smgr->getMesh("Data/turtle2.b3d"),battle_turtle2);
shield_node2->setFrameLoop(0,10);
shield_node2->setAnimationSpeed(15);
manipulator->scaleTCoords(shield_node2->getMesh(),core::vector2df(6,6),1);
shield_node2->setMaterialFlag(video::EMF_BACK_FACE_CULLING,false);
shield_node2->setScale(core::vector3df(1.1,1.1,1.1));
shield_node2->setVisible(false);
selector = smgr->createTriangleSelector(shield_node2->getMesh(),shield_node2);
shield_node2->setTriangleSelector(selector);
selector->drop();
shieldmanager->addShield(shield_node2);
//To draw the shooting rays
core::array<core::vector3df> battle_rays_1;
core::array<u32> battle_rays_time_1;
core::array<core::vector3df> battle_rays_2;
core::array<u32> battle_rays_time_2;
//Little workaround to set up the first shield configuration
SEvent nEvent;
nEvent.EventType = EET_KEY_INPUT_EVENT;
nEvent.KeyInput.Key = KEY_SPACE;
nEvent.KeyInput.PressedDown = false;
receiver->OnEvent(nEvent);
//FPS measurement
int lastFPS = -1;
u32 lastMS = device->getTimer()->getRealTime();
while(device->run())
{
//Frameindipendence
u32 difMs = device->getTimer()->getRealTime()-lastMS;
lastMS = device->getTimer()->getRealTime();
f32 alignSpeed = difMs/16.0;
//Move the turtles
battle_turtle1->setPosition(battle_turtle1->getPosition()+battle_turtle1->getRotation().rotationToDirection()*0.1*alignSpeed);
battle_turtle1->setRotation(battle_turtle1->getRotation()+core::vector3df(0,0.85,0)*alignSpeed);
battle_turtle2->setPosition(battle_turtle2->getPosition()+battle_turtle2->getRotation().rotationToDirection()*0.1*alignSpeed);
battle_turtle2->setRotation(battle_turtle2->getRotation()+core::vector3df(0,-0.85,0)*alignSpeed);
//Create new rays and impacts randomly
if(lastMS%(rand()%200+300)==0){
core::vector3df source = battle_turtle1->getPosition()+core::vector3df(0,5,0);
core::vector3df target = battle_turtle2->getPosition()+core::vector3df(2-rand()%3,5-rand()%4,2-rand()%3)*0.6;
const core::line3df ray(source,target);
core::vector3df result = shieldmanager->addImpact(shield_node2, ray,radius*250,duration,impact_color);
core::matrix4 trans = shield_node2->getAbsoluteTransformation();
trans.makeInverse();
trans.transformVect(result);
battle_rays_1.push_back(result);
battle_rays_time_1.push_back(device->getTimer()->getTime()+500);
}
if(lastMS%(rand()%200+300)==0){
core::vector3df source = battle_turtle2->getPosition()+core::vector3df(0,5,0);
core::vector3df target = battle_turtle1->getPosition()+core::vector3df(4-rand()%9,4-rand()%9,4-rand()%9);
const core::line3df ray(source,target);
core::vector3df result = shieldmanager->addImpact(shield_node1, ray,radius,duration,impact_color);
core::matrix4 trans = shield_node1->getAbsoluteTransformation();
trans.makeInverse();
trans.transformVect(result);
battle_rays_2.push_back(result);
battle_rays_time_2.push_back(device->getTimer()->getTime()+500);
}
//Draw the scene
driver->beginScene(true, true, video::SColor(50,50,50,50));
smgr->drawAll();
///Draw the shields afterwards, otherwise the regular nodes will overdraw them
shieldmanager->drawAll();
//Draw the rays
video::SMaterial material;
material.Lighting = false;
material.Thickness = 1;
material.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
driver->setMaterial(material);
driver->setTransform(video::ETS_WORLD,core::matrix4());
for(int i = 0;i<battle_rays_1.size();){
if(battle_rays_time_1[i]<device->getTimer()->getTime()){
battle_rays_time_1.erase(i);
battle_rays_1.erase(i);
}else{
u32 time = device->getTimer()->getTime();
f32 dif = (battle_rays_time_1[i]-time)/500.0f;
core::vector3df result1 = battle_rays_1[i];
core::matrix4 trans1 = shield_node2->getAbsoluteTransformation();
trans1.transformVect(result1);
driver->draw3DLine(battle_turtle1->getPosition()+core::vector3df(0,5,0),result1,video::SColor(255*dif,0,255*dif,0));
i++;
}
}
for(int i = 0;i<battle_rays_2.size();){
if(battle_rays_time_2[i]<device->getTimer()->getTime()){
battle_rays_time_2.erase(i);
battle_rays_2.erase(i);
}else{
u32 time = device->getTimer()->getTime();
f32 dif = (battle_rays_time_2[i]-time)/500.0f;
core::vector3df result2 = battle_rays_2[i];
core::matrix4 trans2 = shield_node1->getAbsoluteTransformation();
trans2.transformVect(result2);
driver->draw3DLine(battle_turtle2->getPosition()+core::vector3df(0,5,0),result2,video::SColor(255*dif,255*dif,0,0));
i++;
}
}
driver->endScene();
//Display the FPS
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"Shielding - Move with Mouse and WASD/Arrow Keys - Change Shield with Space - FPS:";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
//Cleanup
device->drop();
delete shieldmanager;
return 0;
}
![Image](http://img179.imageshack.us/img179/4015/unbenanntva.png)
You can also see it in action in this video.
The source code can be found here.
greetings