Friday, June 8, 2012

Platformer Kit: SPG_Camera class (UnrealScript)


The Platformer Starter Kit uses a side view similar to the old 2D platform games. The SPG_Camera and SPG_CameraProperties classes are used to define the camera.

The SPG_CameraProperties class has only a Vector used to define the position of the camera relative to the player. The class code is below:
class SPG_CameraProperties extends Object
      HideCategories(Object);

// How much to offset the camera by
var(CameraProperties) const Vector CameraOffset;

defaultproperties
{
}

An Archetype was created based on this class in the package "StarterPlatformGameContent.Archetypes.CameraProperties" as shown in the image below.


The SPG_Camera class has an instance of the SPG_CameraProperties class that is loaded from the Archetype:
class SPG_Camera extends Camera;

var const archetype SPG_CameraProperties CameraProperties;

/**
 * Updates the camera's view target. Called once per tick
 *
 * @param    OutVT        Outputted camera view target
 * @param    DeltaTime    Time since the last tick was executed
 */
function UpdateViewTarget(out TViewTarget OutVT, float DeltaTime)
{
    // Early exit if:
    // - We have a pending view target
    // - OutVT currently equals ViewTarget
    // - Blending parameter is lock out going
    if (PendingViewTarget.Target != None && OutVT == ViewTarget && BlendParams.bLockOutgoing)
    {
        return;
    }

    // Add the camera offset to the target's location to get the location of the camera
    OutVT.POV.Location = OutVT.Target.Location + CameraProperties.CameraOffset;
    // Make the camera point towards the target's location
    OutVT.POV.Rotation = Rotator(OutVT.Target.Location - OutVT.POV.Location);
}

defaultproperties
{
    CameraProperties=SPG_CameraProperties'StarterPlatformGameContent.Archetypes.CameraProperties'
}

If you do not know anything about the Camera class, I recommend reading my article "Camera Class (UnrealScript)".

The SPG_Camera class modifies the camera in a very simple way, just overriding the UpdateViewTarget() function of the Camera class. This function receives as output parameter an variable of type TViewTarget, which is a structure (struct) defined in Camera class:
//Extract from Camera class...

/**
 * View Target definition
 * A View Target is responsible for providing the Camera with an ideal Point of View (POV)
 */
struct native TViewTarget
{
    /** Target Actor used to compute ideal POV */
    var()    Actor                   Target;

    /** Controller of Target (only for non Locally controlled Pawns) */
    var()    Controller              Controller;

    /** Point of View */
    var()    TPOV                    POV;

    /** Aspect ratio */
    var()    float                   AspectRatio;

    /** PlayerReplicationInfo (used to follow same player through pawn transitions, etc., when spectating) */
    var()    PlayerReplicationInfo   PRI;
};

Within the structure TViewTarget there is a variable called POV that represents the Point of View. It's of type TPOV which is a structure defined in Object class:
//Extract from Object class...

/**
 * Point Of View type.
 */
struct TPOV
{
    /** Location */
    var() Vector    Location;

    /** Rotation */
    var() Rotator    Rotation;

    /** FOV angle */
    var() float        FOV;

    structdefaultproperties
    {
        FOV=90.f
    }
};

Regarding the existing code in the UpdateViewTarget() function of the SPG_Camera class, the conditional test below was copied from the UpdateViewTarget() function of the Camera class and is used only to prevent the ViewTarget from being changed during an interpolation.
if (PendingViewTarget.Target != None && OutVT == ViewTarget && BlendParams.bLockOutgoing)

The camera setup is done in the two lines of code below, which defines the position of the Point of View as the player's position added with the existing Vector in the SPG_CameraProperties class. After that, it is defined the rotation needed to point the camera toward the player.
OutVT.POV.Location = OutVT.Target.Location + CameraProperties.CameraOffset;
OutVT.POV.Rotation = Rotator(OutVT.Target.Location - OutVT.POV.Location);