State Pattern Using Unity

Learn all about the Finite State Machine design pattern in Unity. Then implement it to control the movement of your own character! By Najmm Shora.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 3 of 3 of this article. Click here to view the first page.

Sneaking Under the Table

Open Ducking.cs. Notice Ducking also inherits from the Grounded class for the same reasons Standing does. Add the following override methods and save the script:

public override void Enter()
{
    base.Enter();
    character.SetAnimationBool(character.crouchParam, true);
    speed = character.CrouchSpeed;
    rotationSpeed = character.CrouchRotationSpeed;
    character.ColliderSize = character.CrouchColliderHeight;
    belowCeiling = false;
}

public override void Exit()
{
    base.Exit();
    character.SetAnimationBool(character.crouchParam, false);
    character.ColliderSize = character.NormalColliderHeight;
}

public override void HandleInput()
{
    base.HandleInput();
    crouchHeld = Input.GetButton("Fire3");
}

public override void LogicUpdate()
{
    base.LogicUpdate();
    if (!(crouchHeld || belowCeiling))
    {
        stateMachine.ChangeState(character.standing);
    }
}

public override void PhysicsUpdate()
{
    base.PhysicsUpdate();
    belowCeiling = character.CheckCollisionOverlap(character.transform.position +
        Vector3.up * character.NormalColliderHeight);
}
  • Inside Enter, the parameter to trigger the crouch animation is set to true which enables the crouch animation. The character.CrouchSpeed and character.CrouchRotationSpeed properties set the speed and rotation which return the intended translation and angular speed of the character while crouching.
    Next, character.CrouchColliderHeight sets the collider size of the character, which returns the intended collider height while crouching. Finally, belowCeiling is reset to false.
  • Inside Exit, the parameter for crouch animation is set to false. This would disable the crouch animation. Afterwards the collider height is set to normal intended height returned by character.NormalColliderHeight.
  • Inside HandleInput, crouchHeld is set to accept the user input. In the Main scene, holding down Shift will set crouchHeld to true.
  • Inside PhysicsUpdate, the belowCeiling variable is set by passing in the Vector3 point near the Character GameObject’s head to CheckCollisionOverlap by. If there is a collision around that point, it means the Character is below a ceiling of some sort.
  • Inside LogicUpdate, you check to see if either crouchHeld or belowCeiling is true. If neither of them is true, movementSM.CurrentState changes to character.standing.

Build and click Play. Now you should be able to move around. If you press Shift, the Character will crouch and you can move around while crouching.

You should also be able to go under the platforms. If you release Shift while underneath the platforms, the Character will continue crouching until you leave its cover.

Play the ducking state

Up, Up and Away!

Open Jumping.cs. You’ll see a method named Jump. Don’t worry about its specifics but understand it’s used to make the Character jump with physics, animation and magic! :]

Now add the usual override methods and save the script

public override void Enter()
{
    base.Enter();
    SoundManager.Instance.PlaySound(SoundManager.Instance.jumpSounds);
    grounded = false;
    Jump();
}

public override void LogicUpdate()
{
    base.LogicUpdate();
    if (grounded)
    {
        character.TriggerAnimation(landParam);
        SoundManager.Instance.PlaySound(SoundManager.Instance.landing);
        stateMachine.ChangeState(character.standing);
    }
}

public override void PhysicsUpdate()
{
    base.PhysicsUpdate();
    grounded = character.CheckCollisionOverlap(character.transform.position);
}
  • Inside Enter, the SoundManager singleton plays the jump sound. Afterwards, grounded is reset to its default value. Finally Jump gets called.
  • Inside PhysicsUpdate, the Vector3 point near the Character’s feet is sent to CheckCollisionOverlap, which means grounded will be set to true if the Character is on ground.
  • In LogicUpdate when grounded is true, you call TriggerAnimation for the landing animation, a landing audio plays and movementSM.CurrentState changes to character.standing.

Finally, with this, you’ve fully implemented the movement FSM using the State Pattern. Build and play. Use Space to make the character jump.

Play the jumping state
Now you can say, “my code is in a state!” with a smile on your face! :]

Where to Go From Here?

You can use the Download Materials button at the top and bottom of this tutorial to download both the starter and final projects.

While state machines are useful they come with their own limitations. Concurrent State Machines and Pushdown Automata tackle some of those limitations. You can read more about them in the book Game Programming Patterns by R.Nystrom.

You can also delve deeper by exploring behavioral trees for making advanced in-game entities.

I hope you found this tutorial useful and enjoyed learning the topic. Please feel free to join the forum below for any questions or comments.