📄 steering.cpp
字号:
//-----------------------------------------------------------------------------
//
// $Logfile:: /Quake 2 Engine/Sin/code/game/steering.cpp $
// $Revision:: 21 $
// $Author:: Markd $
// $Date:: 11/18/98 8:53p $
//
// Copyright (C) 1998 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// $Log:: /Quake 2 Engine/Sin/code/game/steering.cpp $
//
// 21 11/18/98 8:53p Markd
// backed out change for NearestNode
//
// 20 11/18/98 7:46p Markd
// made it so if path finding fails on the first node it will try without the
// current bounds and try again
//
// 19 10/26/98 2:19p Markd
// Only jump if last_jump_time is less than level.time
//
// 18 10/25/98 4:58a Jimdose
// added goalnode to chase so that when going to a pathnode we don't do a seek
// to the node after the path is done
// made chase's wander code check for ground
//
// 17 10/23/98 11:33p Markd
// fixed some chase code stuff
//
// 16 10/23/98 6:24p Jimdose
// FindCurrentNode wasn't advancing the node pointer, effectively duplicating
// the second node, causing the guys to sometimes spin on their path
//
// 15 10/23/98 5:13a Jimdose
// Fixed followpath so that they don't turn the wrong direction at the end of
// the path
//
// 14 10/19/98 11:45p Jimdose
// added FindCurrentNode to FollowPath
//
// 13 10/18/98 3:21a Jimdose
// Simplified FollowPath
//
// 12 10/17/98 4:43p Markd
// made ChooseRandomDirection choose backup as its default move
//
// 11 10/16/98 1:55a Jimdose
// Added another NextNode function for finding the next node after the
// specified node.
// Made FollowPath check the node following the jump node to see if it should
// jump
//
// 10 10/14/98 9:43p Markd
// Bullet proofed nextnode stuff in AI_JUMP for steering
//
// 9 10/14/98 9:03p Markd
// tweaked jumping stuff
//
// 8 10/14/98 5:21p Markd
// Added Jumping to the Chase steering method
//
// 7 10/10/98 5:01p Markd
// Changed trace masks to edict->clipmasks
//
// 6 10/10/98 4:35p Markd
// Fixed some avoidvec behavior for the characters
//
// 5 10/04/98 5:31p Markd
// Fixed chase problems
//
// 4 9/22/98 5:11p Jimdose
// Added Turn
// Added wander code to chase
//
// 3 9/22/98 1:56a Jimdose
// Added ShowInfo
// Added ObstacleAvoidance2 temporarily
//
// 2 9/18/98 10:57p Jimdose
// Separated from Behavior.cpp
//
// 1 9/18/98 5:01p Jimdose
//
// DESCRIPTION:
// Steering behaviors for AI.
//
#include "g_local.h"
#include "steering.h"
#include "actor.h"
/****************************************************************************
Steering Class Definition
****************************************************************************/
CLASS_DECLARATION( Listener, Steering, NULL );
ResponseDef Steering::Responses[] =
{
{ NULL, NULL }
};
Steering::Steering()
{
steeringforce = vec_zero;
origin = vec_zero;
movedir = vec_zero;
maxspeed = 320;
}
void Steering::ShowInfo
(
Actor &self
)
{
gi.printf( "steeringforce: ( %f, %f, %f )\n", steeringforce.x, steeringforce.y, steeringforce.z );
gi.printf( "origin: ( %f, %f, %f )\n", origin.x, origin.y, origin.z );
gi.printf( "movedir: ( %f, %f, %f )\n", movedir.x, movedir.y, movedir.z );
gi.printf( "maxspeed: %f\n", maxspeed );
}
void Steering::Begin
(
Actor &self
)
{
}
qboolean Steering::Evaluate
(
Actor &self
)
{
return false;
}
void Steering::End
(
Actor &self
)
{
}
void Steering::DrawForces
(
void
)
{
G_Color3f( 0.3, 0.5, 1 );
G_BeginLine();
G_Vertex( origin );
G_Vertex( origin + steeringforce * FRAMETIME );
G_EndLine();
G_Color3f( 1, 0, 1 );
G_BeginLine();
G_Vertex( origin );
G_Vertex( origin + movedir * maxspeed * FRAMETIME );
G_EndLine();
}
void Steering::SetPosition
(
Vector pos
)
{
origin = pos;
}
void Steering::SetDir
(
Vector dir
)
{
movedir = dir;
}
void Steering::SetMaxSpeed
(
float speed
)
{
maxspeed = speed;
}
void Steering::ResetForces
(
void
)
{
steeringforce = vec_zero;
}
/****************************************************************************
Seek Class Definition
****************************************************************************/
CLASS_DECLARATION( Steering, Seek, NULL );
ResponseDef Seek::Responses[] =
{
{ NULL, NULL }
};
Seek::Seek()
{
targetposition = vec_zero;
targetvelocity = vec_zero;
}
void Seek::SetTargetPosition
(
Vector pos
)
{
targetposition = pos;
}
void Seek::SetTargetVelocity
(
Vector vel
)
{
targetvelocity = vel;
}
void Seek::ShowInfo
(
Actor &self
)
{
Steering::ShowInfo( self );
gi.printf( "\ntargetposition: ( %f, %f, %f )\n", targetposition.x, targetposition.y, targetposition.z );
gi.printf( "targetvelocity: ( %f, %f, %f )\n", targetvelocity.x, targetvelocity.y, targetvelocity.z );
}
qboolean Seek::Evaluate
(
Actor &self
)
{
Vector predictedposition;
Vector dir;
Vector xydelta;
Vector delta;
Vector ang1;
Vector ang2;
float dist;
float xydist;
float l;
ResetForces();
delta = targetposition - origin;
dist = delta.length();
//
// null out z component
//
delta.z = 0;
xydist = delta.length();
predictedposition = targetposition + targetvelocity * ( dist / maxspeed );
dir = predictedposition - origin;
dir.normalize();
ang1 = dir.toAngles();
ang2 = movedir.toAngles();
steeringforce.x = ang1.x - ang2.x;
if ( steeringforce.x <= -180 )
{
steeringforce.x += 360;
}
if ( steeringforce.x >= 180 )
{
steeringforce.x -= 360;
}
steeringforce.y = ang1.y - ang2.y;
if ( steeringforce.y <= -180 )
{
steeringforce.y += 360;
}
if ( steeringforce.y >= 180 )
{
steeringforce.y -= 360;
}
// if we're nearly there, turn directly toward our goal
if ( xydist > self.movespeed )
{
if ( fabs( steeringforce.x ) > 1 )
{
steeringforce.x *= 0.4;
}
if ( fabs( steeringforce.y ) > 1 )
{
steeringforce.y *= 0.4;
}
}
else
{
l = self.total_delta.length();
if ( xydist <= l )
{
//steeringforce = vec_zero;
self.total_delta = self.animdir * xydist;
return false;
}
}
steeringforce.z = 0;
return true;
}
/****************************************************************************
ObstacleAvoidance Class Definition
****************************************************************************/
CLASS_DECLARATION( Steering, ObstacleAvoidance, NULL );
ResponseDef ObstacleAvoidance::Responses[] =
{
{ NULL, NULL }
};
ObstacleAvoidance::ObstacleAvoidance()
{
avoidwalls = true;
}
void ObstacleAvoidance::AvoidWalls
(
qboolean avoid
)
{
avoidwalls = avoid;
}
void ObstacleAvoidance::ShowInfo
(
Actor &self
)
{
Steering::ShowInfo( self );
gi.printf( "\navoidwalls: %d\n", avoidwalls );
}
qboolean ObstacleAvoidance::Evaluate
(
Actor &self
)
{
Vector predictedposition;
Vector normal;
Vector angles;
Vector dir;
Vector right;
Vector delta;
float urgency;
float dot;
trace_t tracef;
#if 0
trace_t tracel;
trace_t tracer;
Vector leftposition;
Vector rightposition;
#endif
Entity *ent;
ResetForces();
angles = self.movedir.toAngles();
angles.AngleVectors( NULL, &right, NULL );
origin = self.worldorigin;
origin.z += 1;
predictedposition = origin + self.movedir * self.movespeed;//maxspeed;
#if 0
leftposition = origin - right * 8;
rightposition = origin + right * 8;
#endif
#if 0
G_Color3f( 1, 1, 1 );
G_BeginLine();
G_Vertex( origin );
G_Vertex( predictedposition );
G_Vertex( origin );
G_Vertex( leftposition );
G_Vertex( origin );
G_Vertex( rightposition );
G_EndLine();
#endif
tracef = G_Trace( origin, self.mins, self.maxs, predictedposition, &self, self.edict->clipmask, "ObstacleAvoidance forward" );
#if 0
tracel = G_Trace( origin, self.mins, self.maxs, leftposition, &self, MASK_PLAYERSOLID, "ObstacleAvoidance left" );
tracer = G_Trace( origin, self.mins, self.maxs, rightposition, &self, MASK_PLAYERSOLID, "ObstacleAvoidance right" );
if ( tracel.fraction < 1 )
{
urgency = 1.1 - tracel.fraction;
normal = tracel.plane.normal;
ent = tracel.ent->entity;
steeringforce = Vector( 0, -90, 0 );;
}
else if ( tracer.fraction < 1 )
{
urgency = 1.1 - tracer.fraction;
normal = tracer.plane.normal;
ent = tracer.ent->entity;
steeringforce = Vector( 0, 90, 0 );;
}
else
#endif
if ( tracef.fraction < 1 )
{
urgency = 1.0 - tracef.fraction;
normal = tracef.plane.normal;
ent = tracef.ent->entity;
if ( ent->getSolidType() != SOLID_BSP )
{
dot = -( right * ( ent->worldorigin - self.worldorigin ) );
}
else
{
if ( !avoidwalls )
{
return true;
}
dot = right * normal;
}
if ( dot < 0 )
{
// turn left
steeringforce = Vector( 0, 90, 0 );;
}
else
{
// turn right
steeringforce = Vector( 0, -90, 0 );;
}
}
else
{
return true;
}
steeringforce *= urgency;
return true;
}
/****************************************************************************
ObstacleAvoidance2 Class Definition
****************************************************************************/
CLASS_DECLARATION( Steering, ObstacleAvoidance2, NULL );
ResponseDef ObstacleAvoidance2::Responses[] =
{
{ NULL, NULL }
};
ObstacleAvoidance2::ObstacleAvoidance2()
{
avoidwalls = true;
}
void ObstacleAvoidance2::AvoidWalls
(
qboolean avoid
)
{
avoidwalls = avoid;
}
void ObstacleAvoidance2::ShowInfo
(
Actor &self
)
{
Steering::ShowInfo( self );
gi.printf( "\navoidwalls: %d\n", avoidwalls );
}
qboolean ObstacleAvoidance2::Evaluate
(
Actor &self
)
{
Vector predictedposition;
Vector normal;
Vector angles;
Vector dir;
Vector right;
Vector delta;
float urgency;
float dot;
trace_t tracef;
#if 0
trace_t tracel;
trace_t tracer;
Vector leftposition;
Vector rightposition;
#endif
Entity *ent;
ResetForces();
angles = self.movedir.toAngles();
angles.AngleVectors( NULL, &right, NULL );
origin = self.worldorigin;
origin.z += 1;
predictedposition = origin + self.movedir * self.movespeed;//maxspeed;
#if 0
leftposition = origin - right * 8;
rightposition = origin + right * 8;
#endif
#if 0
G_Color3f( 1, 1, 1 );
G_BeginLine();
G_Vertex( origin );
G_Vertex( predictedposition );
G_Vertex( origin );
G_Vertex( leftposition );
G_Vertex( origin );
G_Vertex( rightposition );
G_EndLine();
#endif
tracef = G_Trace( origin, self.mins, self.maxs, predictedposition, &self, self.edict->clipmask, "ObstacleAvoidance2 forward" );
#if 0
tracel = G_Trace( origin, self.mins, self.maxs, leftposition, &self, MASK_PLAYERSOLID, "ObstacleAvoidance2 left" );
tracer = G_Trace( origin, self.mins, self.maxs, rightposition, &self, MASK_PLAYERSOLID, "ObstacleAvoidance2 right" );
if ( tracel.fraction < 1 )
{
urgency = 1.1 - tracel.fraction;
normal = tracel.plane.normal;
ent = tracel.ent->entity;
steeringforce = Vector( 0, -90, 0 );;
}
else if ( tracer.fraction < 1 )
{
urgency = 1.1 - tracer.fraction;
normal = tracer.plane.normal;
ent = tracer.ent->entity;
steeringforce = Vector( 0, 90, 0 );;
}
else
#endif
if ( tracef.fraction < 1 )
{
urgency = 1.0 - tracef.fraction;
normal = tracef.plane.normal;
ent = tracef.ent->entity;
if ( ent->getSolidType() != SOLID_BSP )
{
dot = -( right * ( ent->worldorigin - self.worldorigin ) );
}
else
{
if ( !avoidwalls )
{
return true;
}
dot = right * normal;
}
if ( dot < 0 )
{
// turn left
steeringforce = Vector( 0, 22, 0 ) * urgency;
}
else
{
// turn right
steeringforce = Vector( 0, 22, 0 ) * urgency;
}
}
else
{
return true;
}
steeringforce *= urgency;
return true;
}
/****************************************************************************
FollowPath Class Definition
****************************************************************************/
CLASS_DECLARATION( Steering, FollowPath, NULL );
ResponseDef FollowPath::Responses[] =
{
{ NULL, NULL }
};
FollowPath::FollowPath()
{
path = NULL;
currentNode = NULL;
}
FollowPath::~FollowPath()
{
currentNode = NULL;
if ( path )
{
delete path;
}
}
void FollowPath::FindCurrentNode
(
Actor &self
)
{
// Sometimes the second node on the path is the proper node to start from.
// This happens because instead of creating the shortest path from the actor,
// we create the shortest path from his nearest node. Often, this creates a
// path where he may already be further along the path than the first node,
// causing him to "go back" along the path. By checking if we can get to the
// second node, we get rid of the backtracking.
PathNode *node;
if ( !path )
{
currentNode = NULL;
return;
}
currentNode = path->NextNode();
if ( path->NumNodes() < 2 )
{
return;
}
node = path->GetNode( 2 );
if ( self.CanMoveTo( node->worldorigin ) )
{
currentNode = path->NextNode();
}
}
void FollowPath::SetPath
(
Path *newpath
)
{
if ( path )
{
delete path;
}
currentNode = NULL;
path = newpath;
}
Path *FollowPath::SetPath
(
Actor &self,
Vector from,
Vector to
)
{
PathNode *goal;
PathNode *node;
StandardMovePath find;
if ( path )
{
delete path;
path = NULL;
}
currentNode = NULL;
goal = PathManager.NearestNode( to, &self );
if ( !goal )
{
return NULL;
}
node = PathManager.NearestNode( from, &self );
if ( !node || ( goal == node ) )
{
return NULL;
}
find.heuristic.setSize( self.size );
find.heuristic.entnum = self.entnum;
path = find.FindPath( node, goal );
return path;
}
void FollowPath::DrawForces
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -