📄 steering.cpp
字号:
(
void
)
{
seek.DrawForces();
}
qboolean FollowPath::DoneWithPath
(
Actor &self
)
{
if ( !path )
{
return true;
}
return ( currentNode == NULL );
}
void FollowPath::ShowInfo
(
Actor &self
)
{
Steering::ShowInfo( self );
if ( path )
{
gi.printf( "\npath : ( %f, %f, %f ) to ( %f, %f, %f )\n",
path->Start()->worldorigin.x, path->Start()->worldorigin.y, path->Start()->worldorigin.z,
path->End()->worldorigin.x, path->End()->worldorigin.y, path->End()->worldorigin.z );
}
else
{
gi.printf( "\npath : NULL\n" );
}
gi.printf( "seek:\n" );
seek.ShowInfo( self );
if ( currentNode )
{
gi.printf( "currentNode: ( %f, %f, %f )\n",
currentNode->worldorigin.x, currentNode->worldorigin.y, currentNode->worldorigin.z );
}
else
{
gi.printf( "currentNode: NULL\n" );
}
}
void FollowPath::Begin
(
Actor &self
)
{
seek.Begin( self );
}
qboolean FollowPath::Evaluate
(
Actor &self
)
{
PathNode *lastnode;
Vector delta;
Vector targetpos;
ResetForces();
if ( !path )
{
return false;
}
// the first time we come through here with a path, currentNode is NULL.
if ( !currentNode )
{
FindCurrentNode( self );
if ( !currentNode )
{
delete path;
path = NULL;
return false;
}
}
targetpos = currentNode->worldorigin;
// check if the remaining distance is less than the
// distance we'll travel this frame.
delta = targetpos - self.worldorigin;
// check if the squared distance remaining is less than
// the squared distance we'll travel
if ( delta * delta <= self.frame_delta * self.frame_delta )
{
lastnode = currentNode;
currentNode = path->NextNode();
// check if we should jump to our next node
if ( currentNode && ( lastnode->nodeflags & AI_JUMP ) && ( currentNode->targetname == lastnode->target ) )
{
if ( self.last_jump_time < level.time )
{
self.SetVariable( "jumptarget", lastnode->target.c_str() );
self.ForceAction( "jump" );
}
return true;
}
// if we're not done with the path, steer toward the next node
if ( currentNode )
{
targetpos = currentNode->worldorigin;
}
else
{
delete path;
path = NULL;
return false;
}
}
// steer toward our next path node
seek.SetTargetPosition( targetpos );
seek.SetTargetVelocity( vec_zero );
seek.SetMaxSpeed( self.movespeed );
seek.SetPosition( origin );
seek.SetDir( self.movedir );
seek.Evaluate( self );
steeringforce = seek.steeringforce;
return ( currentNode != NULL );
}
void FollowPath::End
(
Actor &self
)
{
seek.End( self );
}
/****************************************************************************
Turn Class Definition
****************************************************************************/
CLASS_DECLARATION( Steering, Turn, NULL );
ResponseDef Turn::Responses[] =
{
{ NULL, NULL }
};
Turn::Turn()
{
dir = Vector( 1, 0, 0 );
mode = 0;
ent = NULL;
}
void Turn::SetDirection
(
float yaw
)
{
Vector ang;
ang = Vector( 0, yaw, 0 );
this->yaw = anglemod( yaw );
ang.AngleVectors( &dir, NULL, NULL );
mode = 1;
}
void Turn::SetTarget
(
Entity *ent
)
{
this->ent = ent;
mode = 2;
}
void Turn::ShowInfo
(
Actor &self
)
{
Steering::ShowInfo( self );
gi.printf( "\nseek:\n" );
seek.ShowInfo( self );
if ( ent )
{
gi.printf( "\nent: #%d '%s'\n", ent->entnum, ent->targetname.c_str() );
}
else
{
gi.printf( "\nent: NULL\n" );
}
gi.printf( "dir: ( %f, %f, %f )\n", dir.x, dir.y, dir.z );
gi.printf( "yaw: %f\n", yaw );
gi.printf( "mode: %d\n", mode );
}
void Turn::Begin
(
Actor &self
)
{
seek.Begin( self );
}
extern float angledist( float ang );
qboolean Turn::Evaluate
(
Actor &self
)
{
Vector delta;
float ang;
switch( mode )
{
case 1 :
ang = angledist( yaw - self.angles.yaw() );
if ( fabs( ang ) < 1 )
{
steeringforce = Vector( 0, ang, 0 );
return false;
}
seek.SetTargetPosition( self.worldorigin + dir );
seek.SetTargetVelocity( vec_zero );
break;
case 2 :
if ( !ent )
{
return false;
}
delta = ent->worldorigin - self.worldorigin;
yaw = delta.toYaw();
//if ( self.angles.yaw() == yaw )
// {
// return false;
// }
seek.SetTargetPosition( ent->worldorigin );
seek.SetTargetVelocity( vec_zero );
break;
default :
return false;
}
seek.SetPosition( self.worldorigin );
seek.SetDir( self.movedir );
seek.SetMaxSpeed( self.movespeed );
seek.Evaluate( self );
//seek.DrawForces();
steeringforce = seek.steeringforce;
return true;
}
void Turn::End
(
Actor &self
)
{
seek.End( self );
}
/****************************************************************************
Chase Class Definition
****************************************************************************/
CLASS_DECLARATION( Steering, Chase, NULL );
ResponseDef Chase::Responses[] =
{
{ NULL, NULL }
};
Chase::Chase()
{
goalent = NULL;
goal = vec_zero;
goalnode = NULL;
usegoal = false;
newpathrate = 2;
}
void Chase::SetPath
(
Path *newpath
)
{
follow.SetPath( newpath );
path = newpath;
}
void Chase::SetGoalPos
(
Vector goalpos
)
{
goal = goalpos;
usegoal = true;
goalent = NULL;
goalnode = NULL;
}
void Chase::SetGoal
(
PathNode *node
)
{
goalnode = node;
usegoal = false;
goalent = NULL;
}
void Chase::SetTarget
(
Entity *ent
)
{
goalent = ent;
goalnode = NULL;
usegoal = false;
}
void Chase::SetPathRate
(
float rate
)
{
newpathrate = rate;
}
void Chase::ShowInfo
(
Actor &self
)
{
Steering::ShowInfo( self );
gi.printf( "\nseek:\n" );
seek.ShowInfo( self );
gi.printf( "\nfollow:\n" );
follow.ShowInfo( self );
gi.printf( "\nnextpathtime: %f\n", nextpathtime );
if ( path )
{
gi.printf( "\npath : ( %f, %f, %f ) to ( %f, %f, %f )\n",
path->Start()->worldorigin.x, path->Start()->worldorigin.y, path->Start()->worldorigin.z,
path->End()->worldorigin.x, path->End()->worldorigin.y, path->End()->worldorigin.z );
}
else
{
gi.printf( "\npath : NULL\n" );
}
gi.printf( "goal: ( %f, %f, %f )\n", goal.x, goal.y, goal.z );
if ( goalent )
{
gi.printf( "\ngoalent: #%d '%s'\n", goalent->entnum, goalent->targetname.c_str() );
}
else
{
gi.printf( "\ngoalent: NULL\n" );
}
if ( goalnode )
{
gi.printf( "\ngoalnode: #%d '%s' ( %f, %f, %f )\n", goalnode->nodenum, goalnode->targetname.c_str(),
goalnode->worldorigin.x, goalnode->worldorigin.y, goalnode->worldorigin.z );
}
else
{
gi.printf( "\ngoalnode: NULL\n" );
}
gi.printf( "avoid:\n" );
avoid.ShowInfo( self );
gi.printf( "\ntime: %f\n", avoidtime );
gi.printf( "usegoal: %d\n", usegoal );
gi.printf( "newpathrate: %f\n", newpathrate );
gi.printf( "wander: %d\n", wander );
gi.printf( "stuck: %d\n", stuck );
gi.printf( "avoidvec : ( %f, %f, %f )\n", avoidvec.x, avoidvec.y, avoidvec.z );
}
void Chase::Begin
(
Actor &self
)
{
nextpathtime = 0;
path = NULL;
seek.Begin( self );
follow.Begin( self );
avoid.AvoidWalls( false );
avoid.Begin( self );
turnto.Begin( self );
anim = self.animname;
stuck = 0;
wander = 0;
}
Vector Chase::ChooseRandomDirection
(
Actor &self
)
{
Vector dir;
Vector ang;
Vector bestdir;
float bestfraction;
trace_t trace;
trace_t groundtrace;
int i;
int j;
int t;
int u;
Vector s;
Vector start;
Vector end;
Vector groundend;
s = Vector( 0, 0, STEPSIZE );
start = self.worldorigin + s;
// quantize to nearest 45 degree
u = ( ( int )( self.worldangles.y * ( 1 / 45 ) + 22.5 ) ) * 45;
bestfraction = -1;
//
// in case we don't find anything!
//
bestdir = self.worldorigin - ( Vector( self.orientation[ 0 ] ) * 100 );
for( i = 0; i <= 180; i += 20 )
{
if ( rand() < 0.3 )
{
i += 20;
}
t = i;
if ( rand() < 0.5 )
{
// sometimes we choose left first, other times right.
t = -t;
}
for( j = -1; j < 2; j += 2 )
{
if ( ( j == 1 ) && ( i == 180 ) )
{
ang.y = self.worldangles.y + ( t * j );
}
else
{
ang.y = u + t * j;
}
ang.AngleVectors( &dir, NULL, NULL );
end = self.worldorigin + dir * 140 + s;
trace = G_Trace( start, self.mins, self.maxs, end, &self,
self.edict->clipmask, "Chase::ChooseRandomDirection 1" );
if ( ( trace.fraction > bestfraction ) && ( !trace.startsolid ) && !( trace.allsolid ) )
{
if ( trace.endpos != avoidvec )
{
// check if we're near the ground
end = self.worldorigin + dir * 32 + s;
groundend = end;
groundend.z -= STEPSIZE * 2;
groundtrace = G_Trace( end, self.mins, self.maxs, groundend, &self,
self.edict->clipmask, "Chase::ChooseRandomDirection 2" );
if ( groundtrace.fraction != 1 )
{
bestdir = trace.endpos;
bestfraction = trace.fraction;
}
}
}
if ( i == 0 )
{
break;
}
}
}
return bestdir;
}
qboolean Chase::Evaluate
(
Actor &self
)
{
qboolean result;
trace_t trace;
if ( !usegoal && !goalnode && ( !goalent || goalent->deadflag ) )
{
return false;
}
ResetForces();
if ( !wander )
{
if ( self.lastmove == STEPMOVE_OK )
{
stuck = 0;
}
else
{
stuck++;
if ( stuck >= 2 )
{
stuck = 3;
wander = 1;
}
}
}
switch( wander )
{
case 1 :
stuck--;
if ( !stuck )
{
wander = 0;
nextpathtime = 0;
path = NULL;
break;
}
wanderstart = self.worldorigin;
avoidvec = ChooseRandomDirection( self );
wandertime = level.time + 1;
wander = 2;
case 2 :
seek.SetTargetPosition( avoidvec );
seek.SetTargetVelocity( vec_zero );
seek.SetPosition( self.worldorigin );
seek.SetDir( self.movedir );
seek.SetMaxSpeed( self.movespeed );
result = seek.Evaluate( self );
if ( result )
{
if ( ( level.time > wandertime ) && ( self.lastmove != STEPMOVE_OK ) )
{
wander = 0;
stuck = 0;
}
self.Accelerate( seek.steeringforce );
return true;
}
wander = 0;
nextpathtime = 0;
path = NULL;
break;
//self.SetAnim( "idle" );
turnto.SetDirection( ( wanderstart - self.worldorigin ).toYaw() );
wander = 3;
wandertime = level.time + 1;
case 3 :
if ( level.time < wandertime )
{
turnto.Evaluate( self );
self.Accelerate( turnto.steeringforce );
return true;
}
//self.SetAnim( anim );
wander = 0;
nextpathtime = 0;
path = NULL;
break;
}
if ( path && follow.DoneWithPath( self ) )
{
path = NULL;
nextpathtime = 0;
}
if ( goalent && ( goalent->edict->solid != SOLID_NOT ) && ( goalent->edict->solid != SOLID_TRIGGER ) )
{
trace = G_Trace( self.worldorigin, self.mins, self.maxs, self.worldorigin +
Vector( self.orientation[ 0 ] ) * self.movespeed * 0.1, &self, self.edict->clipmask, "Chase" );
if ( trace.ent->entity == goalent )
{
return false;
}
}
if ( nextpathtime < level.time )
{
nextpathtime = level.time + newpathrate;
if ( goalnode )
{
path = follow.SetPath( self, self.worldorigin, goalnode->worldorigin );
}
else if ( goalent )
{
path = follow.SetPath( self, self.worldorigin, goalent->worldorigin );
}
else
{
path = follow.SetPath( self, self.worldorigin, goal );
}
}
if ( !path )
{
if ( goalnode )
{
seek.SetTargetPosition( goalnode->worldorigin );
seek.SetTargetVelocity( vec_zero );
}
else if ( goalent )
{
seek.SetTargetPosition( goalent->worldorigin );
seek.SetTargetVelocity( goalent->velocity );
}
else
{
seek.SetTargetPosition( goal );
seek.SetTargetVelocity( vec_zero );
}
seek.SetPosition( self.worldorigin );
seek.SetDir( self.movedir );
seek.SetMaxSpeed( self.movespeed );
result = seek.Evaluate( self );
//seek.DrawForces();
steeringforce = seek.steeringforce;
if ( !result )
{
return false;
}
}
else
{
follow.SetPosition( self.worldorigin );
follow.SetDir( self.movedir );
follow.SetMaxSpeed( self.movespeed );
if ( !follow.Evaluate( self ) )
{
nextpathtime = 0;
if ( goalnode )
{
self.frame_delta = goalnode->worldorigin - self.worldorigin;
return false;
}
}
//follow.DrawForces();
steeringforce = follow.steeringforce;
}
if ( avoidtime < level.time )
{
avoid.SetMaxSpeed( self.movespeed );
avoid.SetPosition( self.worldorigin );
avoid.SetDir( self.movedir );
avoid.Evaluate( self );
if ( avoid.steeringforce == vec_zero )
{
avoidtime = level.time + 0.1;
}
else
{
steeringforce += avoid.steeringforce;
}
}
self.Accelerate( steeringforce );
return true;
}
void Chase::End
(
Actor &self
)
{
//if ( wander && ( self.newanimnum != -1 ) )
//{
//self.SetAnim( anim );
//}
seek.End( self );
follow.End( self );
avoid.End( self );
path = NULL;
turnto.End( self );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -