terça-feira, 6 de março de 2012

Classe Vehicle (UnrealScript)

A classe Vehicle é uma subclasse de Pawn. O sistema de veículos no UDK é bem complexo e permite a criação de diferentes tipos de veículos. A imagem abaixo mostra as subclasses de Vehicle existentes no UDK:


Podemos ver quatro tipo de veículos definidos que são: UTVehicle_Cicada, UTVehicle_Hoverboard, UTVehicle_Manta e UTVehicle_Scorpion. Entretanto, todas essas classes possuem o modificador abstract. Isto indica que não podem ser criados objetos dessas classes. A principal idéia das classes abstratas é criar uma classe base com diversas funcionalidades para servir como modelo. As classes que realmente definem os veículos são as que terminam com o nome "_Content".

Para disponibilizar veículos no cenário é preciso utilizar a classe UDKVehicleFactory que é uma subclasse de "Actor->NavigationPoint". A imagem abaixo mostra os tipos existentes no UDK:


Existem apenas três Factory. O veículo que está faltando é o Hoverboard porque ele já está disponível automaticamente para o jogador no tipo de jogo "Vehicle Capture The Flag". Para testá-lo no editor defina o Game Type como UTVehicleCTFGame_Content e após iniciar o jogo pressione a tecla "Q" para usar o Hoverboard que é uma espécie de skate sem rodas como pode ser visto na imagem abaixo.


Para entrar em um veículo que esteja disponível no cenário, chegue perto dele e pressione a tecla "E". Se for possível entrar no veículo, umas das funções da classe Vehicle que será chamada é a "DriverEnter(Pawn P)" cujo código se encontra abaixo.
//Extraído da classe Vehicle (pacote Engine)

/** DriverEnter()
 * Make Pawn P the new driver of this vehicle
 * Changes controller ownership across pawns
 */
function bool DriverEnter(Pawn P)
{
    local Controller C;

    // Set pawns current controller to control the vehicle pawn instead
    C = P.Controller;
    Driver = P;
    Driver.StartDriving( self );
    if ( Driver.Health <= 0 )
    {
        Driver = None;
        return false;
    }
    SetDriving(true);

    // Disconnect PlayerController from Driver and connect to Vehicle.
    C.Unpossess();
    Driver.SetOwner( Self ); // This keeps the driver relevant.
    C.Possess( Self, true );

    if( PlayerController(C) != None && !C.IsChildState(C.GetStateName(), LandMovementState) )
    {
        PlayerController(C).GotoState( LandMovementState );
    }

    WorldInfo.Game.DriverEnteredVehicle(self, P);
    return true;
}

Esta função pega a referência do objeto Pawn que entrou no veículo e guarda na variável Driver para que possa restaurá-lo quando ele sair do veículo. O Controller deixa de referenciar o Pawn através da função "Unpossess()" e passa agora a referenciar o veículo através da função "Possess( Self, true )". O objeto Self é a referência ao veículo e o segundo parâmetro com o valor true indica que é uma transição para um veículo. É feito um teste para verificar se o Controller se trata de um PlayerController e se ainda não se encontra no estado LandMovementState. LandMovementState é uma variável do tipo name definida na classe Pawn. Esse tipo de variável é usada para armazenar o nome de um item em UnrealScript como o nome de classes, funções e estados. Na classe Pawn ela recebe o valor PlayerWalking no DefaultProperties. Na classe Vehicle essa variável recebe o valor PlayerDriving. Isto significa que ao entrar em um veículo o PlayerController passará para o estado PlayerDriving.

No PlayerController podemos ver um bom exemplo do uso de estados. A cada frame é executada a função "PlayerMove()", se estiver no estado PlayerWalking a função "PlayerMove()" chamará a função "ProcessMove()", mas se estiver no estado PlayerDriving a função "PlayerMove()" chamará a função "ProcessDrive()". O código abaixo mostra as funções definidas para o estado PlayerDriving na classe PlayerController.
//Extraído da classe PlayerController (pacote Engine)

// Player Driving a vehicle.
state PlayerDriving
{
ignores SeePlayer, HearNoise, Bump;

    function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot);

    // Set the throttle, steering etc. for the vehicle based on the input provided
    function ProcessDrive(float InForward, float InStrafe, float InUp, bool InJump)
    {
        local Vehicle CurrentVehicle;

        CurrentVehicle = Vehicle(Pawn);
        if (CurrentVehicle != None)
        {            
            bPressedJump = InJump;
            CurrentVehicle.SetInputs(InForward, -InStrafe, InUp);
            CheckJumpOrDuck();
        }
    }

    function PlayerMove( float DeltaTime )
    {        
        UpdateRotation(DeltaTime);
      
        ProcessDrive(PlayerInput.RawJoyUp, PlayerInput.RawJoyRight, PlayerInput.aUp, bPressedJump);
        if (Role < ROLE_Authority)
        {
            ServerDrive(PlayerInput.RawJoyUp, PlayerInput.RawJoyRight, PlayerInput.aUp, bPressedJump, ((Rotation.Yaw & 65535) << 16) + (Rotation.Pitch & 65535));
        }

        bPressedJump = false;
    }

    unreliable server function ServerUse()
    {
        local Vehicle CurrentVehicle;

        CurrentVehicle = Vehicle(Pawn);
        CurrentVehicle.DriverLeave(false);
    }

    event BeginState(Name PreviousStateName)
    {
        CleanOutSavedMoves();
    }

    event EndState(Name NextStateName)
    {
        CleanOutSavedMoves();
    }
}

Para mais informações sobre a Classe Vehicle: