You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
3.8 KiB
158 lines
3.8 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// tf_path_follower.cpp |
|
// Simplified path following for TF2 |
|
// Author: Michael Booth, November 2010 |
|
|
|
#include "cbase.h" |
|
|
|
#include "NextBotManager.h" |
|
#include "tf_path_follower.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------------- |
|
/** |
|
* Constructor |
|
*/ |
|
CTFPathFollower::CTFPathFollower( void ) |
|
{ |
|
m_goal = NULL; |
|
m_minLookAheadRange = 300.0f; |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------------- |
|
CTFPathFollower::~CTFPathFollower() |
|
{ |
|
// allow bots to detach pointer to me |
|
CUtlVector< INextBot * > botVector; |
|
TheNextBots().CollectAllBots( &botVector ); |
|
|
|
for( int i=0; i<botVector.Count(); ++i ) |
|
{ |
|
botVector[i]->NotifyPathDestruction( this ); |
|
} |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------------- |
|
/** |
|
* When the path is invalidated, the follower is also reset |
|
*/ |
|
void CTFPathFollower::Invalidate( void ) |
|
{ |
|
// extend |
|
Path::Invalidate(); |
|
|
|
m_goal = NULL; |
|
MoveCursorToStart(); |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------------- |
|
/** |
|
* Invoked when the path is (re)computed (path is valid at the time of this call) |
|
*/ |
|
void CTFPathFollower::OnPathChanged( INextBot *bot, Path::ResultType result ) |
|
{ |
|
// start from the beginning |
|
m_goal = FirstSegment(); |
|
MoveCursorToStart(); |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------------- |
|
/** |
|
* Move mover along path |
|
*/ |
|
void CTFPathFollower::Update( INextBot *bot ) |
|
{ |
|
VPROF_BUDGET( "CTFPathFollower::Update", "NextBot" ); |
|
ILocomotion *mover = bot->GetLocomotionInterface(); |
|
|
|
// track most recent path followed |
|
bot->SetCurrentPath( this ); |
|
|
|
if ( !IsValid() || m_goal == NULL ) |
|
{ |
|
return; |
|
} |
|
|
|
// check if we've reached the end of the path |
|
const float nearRange = 25.0f; |
|
if ( mover->IsOnGround() && ( GetEndPosition() - mover->GetFeet() ).AsVector2D().IsLengthLessThan( nearRange ) ) |
|
{ |
|
// the end of the path has been reached |
|
mover->GetBot()->OnMoveToSuccess( this ); |
|
|
|
if ( bot->IsDebugging( NEXTBOT_PATH ) ) |
|
{ |
|
DevMsg( "CTFPathFollower: OnMoveToSuccess\n" ); |
|
} |
|
|
|
// don't invalidate if OnMoveToSuccess just recomputed a new path |
|
if ( GetAge() > 0.0f ) |
|
{ |
|
Invalidate(); |
|
} |
|
|
|
return; |
|
} |
|
|
|
// move along the path |
|
MoveCursorToClosestPosition( mover->GetFeet(), SEEK_AHEAD ); |
|
float myCursorPosition = GetCursorPosition(); |
|
const Path::Data &data = GetCursorData(); |
|
|
|
if ( !data.segmentPrior ) |
|
{ |
|
// this shouldn't happen |
|
mover->GetBot()->OnMoveToFailure( this, FAIL_STUCK ); |
|
Invalidate(); |
|
return; |
|
} |
|
|
|
// set goal to be just ahead of wherever we happen to be on the path |
|
m_goal = NextSegment( data.segmentPrior ); |
|
|
|
if ( !m_goal ) |
|
{ |
|
m_goal = data.segmentPrior; |
|
} |
|
|
|
// find actual move-to position farther down the path |
|
Vector moveToPos = m_goal->pos; |
|
|
|
// follow point farther down the path to smooth out our movement |
|
for( float ahead = m_minLookAheadRange; ahead > 0.0f; ahead -= 50.0f ) |
|
{ |
|
MoveCursor( myCursorPosition, PATH_ABSOLUTE_DISTANCE ); |
|
MoveCursor( ahead, PATH_RELATIVE_DISTANCE ); |
|
|
|
// get path data at this lookahead point |
|
const Path::Data &data = GetCursorData(); |
|
|
|
if ( mover->IsPotentiallyTraversable( mover->GetFeet(), data.pos ) ) |
|
{ |
|
moveToPos = data.pos; |
|
break; |
|
} |
|
} |
|
|
|
// move bot along path |
|
mover->FaceTowards( moveToPos ); |
|
mover->Approach( moveToPos ); |
|
|
|
// debug display |
|
if ( bot->IsDebugging( NEXTBOT_PATH ) ) |
|
{ |
|
Path::Draw(); |
|
|
|
NDebugOverlay::Cross3D( moveToPos, 5.0f, 150, 150, 255, true, 0.1f ); |
|
NDebugOverlay::Line( bot->GetEntity()->WorldSpaceCenter(), moveToPos, 255, 255, 0, true, 0.1f ); |
|
} |
|
} |
|
|
|
|