Game Development Community

Code Bits #2 - TGB + PSK specifc.

by Ian Smith · 06/21/2009 (6:14 pm) · 0 comments

What happens when you want your PC to be able to fire in 8 directions? Lots of animations! Here's something to cut down on the amount of custom animation state functions you'll need to write.

What this code-bit should allow you to do is simple: Write ONE set of animation states for each possible state; Standing, Running, Jumping, Falling and Crouching.

What this does Mean? For each one of those states your PC could be doing one of 3 additional things: Nothing, Aiming or Attacking.

The function below takes animation about the current aim direction and basic motion status and decides the appropriate animation datablock name. Then all you have to do is call that function in your enterMyAnimationState functions and you're all set.

First, for the purposes of posterity, I'll list the following changes to ControllerBehavior.cs:
if (%keyDown $= "AimUp")
	{
	   %actorObject.Aim = -1;
	}

	if (%keyDown $= "AimDown")
	{
	   %actorObject.Aim = 1;
	}

The obvious complement is present in the keyUp function. I also added the following line to the bottom of both functions:

if (%actorObject.isMethod("updateAnimation")) %actorObject.updateAnimation();

Now here's the fun bit. The direction part of the animation name can be - UP - Aiming/attacking upwards
- DN - Aiming/attacking downwards
- UF - Aiming/attacking upwards and forwards (diagonal)
- DF - Aiming/attacking downwards and forwards (diagonal)

Here is a general description of the animation name format I've derived:

Status(Action(Direction)) - which is [Idle|Crouch|Run|Jump|Fall] + [Aim|Shoot|<null>] + [UP|UF|DN|DF|<null>] where <null> is an empty string.

Example: if the player is standing still and aiming
up and forward, the action would be ActorTypeIdleAimUFAnimation.

DISCLAIMER: It should be noted that this is for a game I'm working on where the control scheme is nigh-identical to the Metroid series; so the logic is written accordingly. However, it should not be too difficult to tweak this function to your game's needs.

function PlayerClass::getAnimationName(%this)
{
   // Get status
   if (%this.OnGround)
   {
      if (%this.Direction.X == 0) // Player is standing still
         %status = %this.getPhysicsState() $= "Crouch" ? "Crouch" : "Idle";
      else 
         %status = "Run";
   }
   else
   {
      %vel = %this.getLinearVelocity();
      if (%vel.Y <= 0) // still moving upwards
         %status = "Jump";
      else 
         %status = "Fall";
   }
   
   // Get action
   if (%this.Attack) 
      %action = "Attack";
   else if (%this.Aim != 0 || %this.Direction.Y != 0)
      %action = "Aim";
   else
      %action = "";
 
   // Get aim direction
   %dir = "";
   if (%action !$= "")
   {
      if (%status $= "Idle" || %status $= "Crouch")
      {
         if (%status $= "Idle" && %this.Direction.Y < 0)
            %dir = "UP";
         else if (%this.Aim < 0) 
            %dir = "UF";
         else if (%this.Aim > 0)
            %dir = "DF";
      }
      else if (%status $= "Jump" || %status $= "Fall")
      {
         %vel = %this.getLinearVelocity();
         if (%vel.Y < 0 && %this.Direction.X == 0)
            %dir = "UP";
         else if (%this.Aim < 0)
            %dir = "UF";
         else if (%this.Aim > 0)
            %dir = "DF";
      }
      else if (%status $= "Run")
      {
         if (%this.Direction.Y < 0 || %this.Aim < 0) 
            %dir = "UF";
         else if (%this.Direction.Y > 0 || %this.Aim > 0)
            %dir = "DF";
      }
   }
   
   return %this.ActorType @ %status @ %action @ %dir @ "Animation";
}

// Changes the current animation state if required
function PlayerClass::updateAnimation(%this)
{
   if (%this.Direction.X != 0)
   {
      //%this.setFlipX(0);
      if (%this.OnGround)
         %this.setAnimationState("Run");
      else
         %this.setAnimationState("Jump");
   }
   else if (%this.Direction.X == 0 && %this.OnGround)
   {
      %this.setAnimationState("Idle");
   }
   else if (%this.getPhysicsState() $= "Crouch")
   {
      %this.setAnimationState("Crouch");
   }
}

How do you use that giant function? Easy! See below:
function PlayerClass::enterIdleAnimationState(%this)
{
   %name = %this.getAnimationName();
   echo("Using:" SPC %name);
   return %name;
}

function PlayerClass::executeIdleAnimationState(%this)
{
   // insert your logic to determine the next animation state here.
   return NULL;
}

As well as the extra code for my crouch physics state:

function PlayerClass::crouch(%this)
{
   if (!%this.onGround) return;
   if (%this.Direction.X != 0) return;
   %this.setPhysicsState("Crouch");
}

function PlayerClass::executeCrouchPhysicsState(%this)
{
   if (%this.Direction.Y < 0 || %this.Direction.X != 0) return "OnGround";
   if (%this.Jump) return "InAir";
   return NULL;
}