Tuesday, March 6, 2012

Vehicle Class (UnrealScript)

The Vehicle class is a subclass of Pawn. The vehicle system in the UDK is quite complex and allows the creation of different types of vehicles. The image below shows the subclasses of the Vehicle class in the UDK:


We can see four types of vehicles defined that are: UTVehicle_Cicada, UTVehicle_Hoverboard, UTVehicle_Manta and UTVehicle_Scorpion. However, all of these classes have the abstract modifier. This indicates that objects of these classes cannot be created. The main idea of abstract classes is to create a base class with several features to serve as a model. The classes that really define the vehicles are those that end with the name "_Content".

To place vehicles in the level you have to use the UDKVehicleFactory class which is a subclass of "Actor->NavigationPoint". The image below shows the existing types in UDK:


There are only three Factory. The vehicle that is missing is the Hoverboard because it is already available to the player in the game type "Vehicle Capture The Flag". To test it in the editor set the Game Type to UTVehicleCTFGame_Content and after starting the game press the "Q" key to use the Hoverboard that is a sort of skateboard without wheels as seen in the image below.


To enter a vehicle that is available on the level, go near it and press the "E" key. If you can enter the vehicle, one of the functions of the Vehicle class that will be called is "DriverEnter(Pawn P)" whose code is below.
//Extract from Vehicle class (Engine package)

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

This function takes the object reference of the Pawn who entered the vehicle and keep in the variable Driver so it can be restored when leaves the vehicle. The Controller stops to reference the Pawn through the function "Unpossess()" and will now reference the vehicle through the function "Possess (Self, true)". The Self object is the reference to the vehicle and the second parameter with the value "true" indicates that it is a transition to a vehicle. A test is done to verify if the Controller is a PlayerController and if it is not in the state LandMovementState. LandMovementState is a variable of type name that was defined in the Pawn class. This type of variable is used to store the name of an item in UnrealScript such as names of classes, functions and states. In the Pawn class it receives the value PlayerWalking in the DefaultProperties. In the Vehicle class this variable receives the value PlayerDriving. This means that when entering a vehicle the PlayerController go to the state PlayerDriving.

In the PlayerController we can see a good example of the use of states. Each Tick the "PlayerMove()" function is called, if the state is PlayerWalking then the "PlayerMove()" function will call the "ProcessMove()" function, but if the state is PlayerDriving then the "PlayerMove()" function will call "ProcessDrive()". The code below shows the functions defined for the state PlayerDriving in the PlayerController class.
//Extract from PlayerController classe (Engine package)

// 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();
    }
}

For more information about the Vehicle class: