This time with a pretty requested feature, rotating enemies to face the player (or any other node) and move towards it.
Well let's get started
1) Turning the node(The function is not mine. I found it while searching the forums)
Code: Select all
vector3df getTargetAngle(vector3df v, vector3df r)
{
//v -current node position
//r -target node position
vector3df angle;
float x,y,z;
x = r.X - v.X;
y = r.Y - v.Y;
z = r.Z - v.Z;
//angle in X-Z plane
angle.Y = atan2 (x, z);
angle.Y *= (180 / PI); //converting from rad to degrees
//just making sure angle is somewhere between 0-360 degrees
if(angle.Y < 0) angle.Y += 360;
if(angle.Y >= 360) angle.Y -= 360;
//angle in Y-Z plane while Z and X axes are already rotated around Y
float z1 = sqrt(x*x + z*z);
angle.X = atan2 (z1, y);
angle.X *= (180 / PI); //converting from rad to degrees
angle.X -= 90;
//just making sure angle is somewhere between 0-360 degrees
if(angle.X < 0) angle.X += 360;
if(angle.X >= 360) angle.X -= 360;
return angle;
}
Code: Select all
f64 getDistance(ISceneNode* sn1 ,ISceneNode* sn2)
{
vector3df pos = sn1->getPosition();
return pos.getDistanceFrom(sn2->getPosition());
}
do something like:
Code: Select all
core::vector3df facing( sin( enemyNode->getRotation().Y * PI/180.0f ), 0, cos( enemyNode->getRotation().Y * PI/180.0f ) );
facing.normalize();
[your enemy node]->setPosition([your enemy node]->getPosition()+(facing*[movement speed]));
1) if (getDistance(Spider1 ,Player)<50). In this state the enemy faces the target, showing that it's aware of his presence.
2) if (getDistance(Spider1 ,Player)<30). In this state the enemy advances towards the player, until...
3) if (getDistance(Spider1 ,Player)<15). The enemy attacks the player!
Of course this type of behaviour is good only for animals and crappy monsters.
A human enemy should also try to dodge any ranged weapons.
To dodge or strafe modify the "facing.X" or "facing.Z" values ("facing" is the vector in the code).
Also, keep in mind that Irrlicht does NOT time events, so you must do it manually.
A good & simple example is Emil_halim's CTimer class for BCX.
Here's its adaptation for C++:
CTime.cpp
Code: Select all
#include <irrlicht.h>
using namespace irr;
using namespace core;
static u32 _Basetime;
void TimeInit(IrrlichtDevice* device)
{
_Basetime = device->getTimer()->getTime();
}
class TTime
{
u32 startTime;
u32 endTime;
bool Active;
public:
TTime(u32 start,u32 duration)
{
startTime = start + _Basetime ;
endTime = startTime + duration;
Active = true;
}
~TTime () {}
bool CheckTime(IrrlichtDevice* device)
{
if (!Active)return false;
u32 tick = device->getTimer()->getTime();
if (tick > startTime && tick < endTime)
return true;
else
return false;
}
bool CheckStartTime(IrrlichtDevice* device)
{
if (!Active)return false;
u32 tick = device->getTimer()->getTime();
if (tick > startTime)
return true;
else
return false;
}
bool CheckEndTime(IrrlichtDevice* device)
{
if (!Active)return false;
u32 tick = device->getTimer()->getTime();
if (tick > endTime)
return true;
else
return false;
}
void UpdateTime(u32 start,u32 duration)
{
startTime = start + _Basetime;
endTime = startTime + duration;
}
void Enable()
{
Active = true;
}
void Disable()
{
Active = false;
}
void setAfter(TTime& other ,u32 period)
{
startTime = other.startTime + period;
endTime = other.endTime + period;
}
void setAS(TTime& other)
{
startTime = other.startTime;
endTime = other.endTime;
}
};