Friday, June 22, 2012

Platformer Kit: SPG_PlayerController class (UnrealScript)

The SPG_PlayerController class is responsible for adapting the commands of the player to the platform style.

If you do not know about the Controller class, first read the article: "Controller Class (UnrealScript)".

One of the functions that is overridden is the UpdateRotation() whose code is below.
function UpdateRotation(float DeltaTime)
{
    local Rotator DeltaRot;

    // Set the delta rotation to that of the desired rotation, as the desired rotation represents
    // the rotation derived from the acceleration of the pawn
    DeltaRot = DesiredRotation;

    // Set the delta pitch to read from the look up input
    DeltaRot.Pitch = PlayerInput.aLookUp;

    // Never need to roll the delta rotation
    DeltaRot.Roll = 0;

    // Shake the camera if necessary
    ViewShake(DeltaTime);

    // If we have a pawn, update its facing rotation
    if (Pawn != None)
    {
        Pawn.FaceRotation(DeltaRot, DeltaTime);
    }
}

There are two types of rotations that occur in the Platformer Kit. One is the rotation that occurs when the player changes the direction he is moving. The other is the rotation of the aim that changes the direction of the fire.

The rotation of the player is manipulated through the use of the variable DesiredRotation. The rotation of the aim is obtained from the variable aLookUp of the PlayerInput class. The variable aLookUp maps the forward and backward movement of the Mouse. The image below shows the player looking upwards.

The FaceRotation() function which will be called from the Pawn object, is that defined in the SPG_PlayerPawn class.


In the PlayerMove() function an acceleration is calculated based on the variable "PlayerInput.aStrafe" which represents the horizontal movement. This acceleration is stored in the variable of type Vector "NewAccel". The function code is below.
state PlayerWalking
{
    function PlayerMove(float DeltaTime)
    {
        local Vector X, Y, Z, NewAccel, CameraLocation;
        local Rotator OldRotation, CameraRotation;
        local bool bSaveJump;

        // If we don't have a pawn to control, then we should go to the dead state
        if (Pawn == None)
        {
            GotoState('Dead');
        }
        else
        {
            // Grab the camera view point as we want to have movement aligned to the camera
            PlayerCamera.GetCameraViewPoint(CameraLocation, CameraRotation);

            // Get the individual axes of the rotation
            GetAxes(CameraRotation, X, Y, Z);

            // Update acceleration
            NewAccel = PlayerInput.aStrafe * Y;
            NewAccel.Z = 0;
            NewAccel = Pawn.AccelRate * Normal(NewAccel);

            // Set the desired rotation
            DesiredRotation = Rotator(NewAccel);

            // Update rotation
            OldRotation = Rotation;
            UpdateRotation(DeltaTime);

            // Update crouch
            Pawn.ShouldCrouch(bool(bDuck));

            // Handle jumping
            if (bPressedJump && Pawn.CannotJumpNow())
            {
                bSaveJump = true;
                bPressedJump = false;
            }
            else
            {
                bSaveJump = false;
            }

            // Update the movement, either replicate it or process it
            if (Role < ROLE_Authority)
            {
                ReplicateMove(DeltaTime, NewAccel, DCLICK_None, OldRotation - Rotation);
            }
            else
            {
                ProcessMove(DeltaTime, NewAccel, DCLICK_None, OldRotation - Rotation);
            }

            bPressedJump = bSaveJump;
        }
    }
}

At the end of the PlayerMove() function there is the following test: "if (Role < ROLE_Authority)". This is used to check if the game is a client that is using a server. If this code is running on a server or in a single player game then the value of the "Role" variable will be equal to "ROLE_Authority."