domingo, 8 de abril de 2012

Navegação IA em UnrealScript

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:


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;
}

Para mais informações sobre Navegação IA:
AI & Navigation