A movimentação em um cenário é um dos aspectos fundamentais da Inteligência Artificial em jogos. A forma mais comum de navegação IA é baseada em waypoints que são colocados no cenário para criar uma rede de caminhos. O UDK também suporta um sistema mais eficiente de navegação baseado em "Navigation Mesh" que resulta em uma movimentação mais natural.
Os waypoints são representados pela classe PathNode:
Os waypoints são representados pela classe PathNode:
Na classe AIController temos um exemplo de código que utiliza o sistema de waypoints:
//Extraído da classe AIController (pacote Engine)
state ScriptedMove
{
// state functions...
Begin:
// while we have a valid pawn and move target, and
// we haven't reached the target yet
while (Pawn != None &&
ScriptedMoveTarget != None &&
!Pawn.ReachedDestination(ScriptedMoveTarget))
{
// check to see if it is directly reachable
if (ActorReachable(ScriptedMoveTarget))
{
// then move directly to the actor
MoveToward(ScriptedMoveTarget, ScriptedFocus);
}
else
{
// attempt to find a path to the target
MoveTarget = FindPathToward(ScriptedMoveTarget);
if (MoveTarget != None)
{
// move to the first node on the path
MoveToward(MoveTarget, ScriptedFocus);
}
else
{
// abort the move
ScriptedMoveTarget = None;
}
}
}
}
No sistema baseado em "Navigation Mesh", o caminho é representado por um conjunto de polígonos convexos que são gerados automaticamente no cenário a partir de um Actor conhecido como Pylon:
As funções relacionadas ao PathFinding usando "Navigation Mesh" estão contidas em uma classe chamada NavigationHandle. Essa classe trabalha com o conceito de Path Constraints e Goal Evaluators. O uso de Path Constraints permite que sejam definidos critérios a serem levados em conta durante o PathFinding. O Path Constraint mais simples é o NavMeshPath_Toward. O Goal Evaluator é usado para definir o fim do PathFinding. O Goal Evaluator mais comum é o NavMeshGoal_At.
Procurando no código fonte que acompanha o UDK, encontrei um exemplo simples de PathFinding usando "Navigation Mesh". O código abaixo é da função GeneratePathToActor() da classe GameCrowdAgent:
//Extraído da classe GameCrowdAgent (pacote GameFramework)
/**
* Generate a path to Goal on behalf of the QueryingAgent
*/
event vector GeneratePathToActor( Actor Goal, optional float WithinDistance, optional bool bAllowPartialPath )
{
local vector NextDest;
LastPathingAttempt = WorldInfo.TimeSeconds;
NextDest = Goal.Location;
// make sure we have a valid navigation handle
if ( NavigationHandle == None )
{
InitNavigationHandle();
}
if( (NavigationHandle != None) && !NavigationHandle.ActorReachable(Goal) )
{
class'NavMeshPath_Toward'.static.TowardGoal( NavigationHandle, Goal );
class'NavMeshGoal_At'.static.AtActor( NavigationHandle, Goal, WithinDistance, bAllowPartialPath );
if ( NavigationHandle.FindPath() )
{
NavigationHandle.GetNextMoveLocation(NextDest, SearchExtent.X);
}
NavigationHandle.ClearConstraints();
}
return NextDest;
}