Player Input Brain

This brain controls the Character using Unity's inbuilt Input Manager to detect keyboard and mouse input.

If you want to use Unity's new Input System, you could make a copy of this script which uses that system instead but you wouldn't need to make any modifications elsewhere since the rest of the character doesn't care what's controlling it.


The PlayerInputBrain script has Serialized Fields to choose which buttons it will use. The Platformer Game Kit is currently only designed for a single Player, but this would allow it to support multiple players by simply giving them each different button names.

public sealed class PlayerInputBrain : CharacterBrain
    [Header("Input Names")]

    [Tooltip("Space by default")]
    private string _JumpButton = "Jump";

    [Tooltip("Left Click by default")]
    private string _PrimaryAttackButton = "Fire1";

    [Tooltip("Right Click by default")]
    private string _SecondaryAttackButton = "Fire2";

    [Tooltip("Left Shift by default")]
    private string _RunButton = "Fire3";

    [Tooltip("A/D and Left/Right Arrows by default")]
    private string _XAxisName = "Horizontal";

    [Tooltip("W/S and Up/Down Arrows by default")]
    private string _YAxisName = "Vertical";

The other fields are listed in each of their appropriate sections.


The Player has a Multi State assigned to the _Jump field so that when the _JumpButton button is pressed, the character will automatically activate the correct type of jump action depending on their circumstances:

  • Wall Jump if they are in the air next to a wall.
  • Air Jump if they are in the air and haven't already jumped too many times.
  • Hold Jump if they are on the ground.

Using a Multi State means that the PlayerInputBrain doesn't need to be aware of any of that logic, but since they all Inherit from Hold Jump the brain does need to end the state if the _JumpButton is released early so that the Player can quickly tap the button for a short jump or hold it to jump higher.

    [SerializeField] private CharacterState _Jump;
    private CharacterState _CurrentJumpState;
    private void Update()
        if (_Jump != null)

When the _JumpButton is pressed, try to enter the _Jump state, and if it was successful, store the state that was actually entered (because entering the Multi State immediately enters whichever one of its sub-states was actually allowed):

            if (Input.GetButtonDown(_JumpButton) &&
                _CurrentJumpState = Character.StateMachine.CurrentState;

Then if the character is still in that state and the _JumpButton is released, return to the Character's default state (Idle):

            if (_CurrentJumpState == Character.StateMachine.CurrentState &&

The Hold Jump State can be interrupted by anything, so returning to the Idle State simply causes it to stop applying its additional upwards acceleration.


Attacking is simple: if a state is assigned and the corresponding button is pressed, try to enter that state:

    [SerializeField] private CharacterState _PrimaryAttack;
    [SerializeField] private CharacterState _SecondaryAttack;
    private void Update()

        if (_PrimaryAttack != null && Input.GetButtonDown(_PrimaryAttackButton))

        if (_SecondaryAttack != null && Input.GetButtonDown(_SecondaryAttackButton))


Movement is also simple: just use the corresponding buttons to set the Character Movement properties:

        Character.Run = Input.GetButton(_RunButton);

        Character.MovementDirection = new Vector2(