Skip to content

How to : Inputs

Julien Pires edited this page Nov 8, 2013 · 2 revisions

HomeHow to ▸ How to Inputs

How to get input service?

All games using Pulsar should inherits the GameApplication class. This class has a static property storing all game services. You can find the InputService instance from this property.

InputService inputService = (InputService)GameApplication.GameServices.GetService(typeof(IInputProvider));

InputService class allows to retrieve the InputManager instance. InputManager class is the main class for the Input module.


How inputs are handled in the input module?

The Input module provides two ways to work with inputs.

  • Direct access : Direct access means you directly use hardware classes such as Mouse, Keyboard or Gamepad. When you use direct access method you doesn't have to create a virtual player.

  • Virtual input : Virtual input allows to add an abstract layer on top of the hardware. Developers doesn't care what type of hardware used. It only know there is a button or an axis and in which state is it. Each players have its own virtual input.


How to create a virtual player?

For each real players you have to create virtual players. A virtual player allows to find inputs for a specific player. The PlayerInput class represents a virtual player.

InputManager input = inputService.Input;
PlayerInput playerOne = input.CreatePlayer(0);

You can create as many player as you want. Player index starts at 0 so the player one will have the index 0, the player two the index 1, etc.


How to create/remove a player context?

A context is a virtual input associated with a name. For example, in a GTA-like, you can have a "Car" context with inputs dedicated to car driving and a "Walk" context when you are off a car. A player can have multiple context at a time but only one is active, you can easily switch between them. Context are useful when the game have multiple inputs configuration depending on the situation.

PlayerInput playerOne = inputManager.GetPlayer(0);
playerOne.CreateContext("Walk");
playerOne.CreateContext("Car");
playerOne.CreateContext("Fly");

// Get a context by its name
VirtualInput walkInput = playerOne.GetContext("Walk");

By default a player has its CurrentContext property set to null. You have to change it yourself.

playerOne.SetCurrentContext("Walk");

Removing a context is easy.

playerOne.RemoveContext("Walk");
playerOne.RemoveContext("Car");

How to create button/axis in a virtual input

The magic with virtual input takes place in the AbstractButton struct. This struct is responsible for checking the state of a button for a mouse, a keyboard or a gamepad. It can return the value of a button and we can know if the button is active or not. You don't have to care about which hardware is used, AbstractButton does it for you. You only have to get the value of AbstractButton.

AbstractButton upMouse = new AbstractButton(MouseButtons.Left);
AbstractButton upKeyboard = new AbstractButton(Buttons.DPadUp);

You can use an AbstractButton for an analog or digital button. For a digital button, value will be 0 or 1 and for an analog button, value will be between 0 and 1 or -1 and 1. Analog button range of values will depends on the type of button, for gamepad triggers the range of values goes from 0 to 1 while for Thumbstick X or Y the range of values goes from -1 to 1. Button and Axis rely on AbstractButton struct for update their states.

A Button can be up or down (at each frame), pressed or released (one frame). Button has a Value property going from 0 to 1, this is useful when you bind an analog button and you need a precise value. You can bind one or more AbstractButton on a Button instance to allow you to trigger it from different source.

Button jump = new Button() { Name = "Up" };
AbstractButton jumpKey = new AbstractButton(Keys.Space);
up.AddButton(jumpKey, 0);

An axis has a Value property going from -1 to 1. There is a slight difference from a Button when you want to bind AbstractButton on an Axis. If the AbstractButton is an analog button you just have to bind one AbstractButton instance because most analog button goes from -1 to 1. But if you want to bind digital button you have to bind two instances because digital goes from 0 to 1. The first digital button will represents the negative range (-1 to 0) and the second will represents the positive range(0 to 1). Remember that if the AbstractButton has a range of -1 to 1 only one instance is needed otherwise two.

Axis forwardAxis = new Axis() { Name = "Forward" };

// Bind analog button
AbstractButton leftXThumb = new AbstractButton(AnalogButtons.LeftThumbStickX);
forwardAxis.AddButton(leftXThumb, 0)

// Bind digital buttons
AbstractButton upPad = new AbstractButton(Buttons.DPadUp);
AbstractButton downPad = new AbstractButton(Buttons.DPadDown);
forwardAxis.AddButton(downPad, upPad, 1);

Now you just have to add them to a virtual input.

VirtualInput walk = playerOne.GetContext("Walk");
walk.AddAxis(forwardAxis);
walk.AddButton(jump);

And to remove them it's easy.

VirtualInput walk = playerOne.GetContext("Walk");
walk.RemoveAxis("Forward");
walk.RemoveButton("Jump");

How to check inputs with a virtual input?

With a virtual input you have two ways to check inputs:

  • Polling : You check yourself the value of a button or an axis.
  • Event : You create a command which is the association of a button or an axis with a type of event and you will get notified when all commands are executed. A command is executed when the button or axis is in a state corresponding to the type of event.

How to create and use event with virtual input

InputEvent class allows you to use event-driven input. You don't have to check yourself the state or value of a button or an axis. An InputEvent is composed of multiple command and a command is the association of a button or axis with a specific event. You can create event with complex rule by combining multiple commands.

When all commands are executed the InputEvent is fired and it will execute delegates that you need to provide.

public delegate void InputEventFired(InputAction action);

Create an event from a VirtualInput is simple.

// Somewhere in your code
public void DoJump(InputEvent sender)
{
    // Jump
}

// Elsewhere in your code
// playerOne is an instance of Player
VirtualInput walk = playerOne.GetContext("Walk");
InputEvent jumpEvent = walk.CreateEvent("Jump", DoJump);

You can create a command for a button or an axis. Since an InputEvent instance is linked to a VirtualInput instance, when you want to create a command you don't need a button or an axis instance but only its name.

// Command for a button
jumpEvent.CreateCommand("JumpButton", ButtonEventType.IsPressed);

// or

//Command for an axis
jumpEvent.CreateCommand("JumpAxis", AxisEventType.IsActive);

Now every time the command is executed the delegate provided for creating the event will be executed.

You can create multiple commands for one event.

VirtualInput walk = playerOne.GetContext("Walk");
InputEvent megaJump = walk.CreateEvent("MegaJump", DoMegaJump);
megaJump.CreateCommand("JumpButton", ButtonEventType.IsPressed);
megaJump.CreateCommand("PowerButton", ButtonEventType.IsDown);

InputEvent doesn't allow to remove one command, you can only remove all at once.

jumpEvent.Destroy();

How to check if any key is pressed

You have two ways to check if any key is pressed. You can check directly hardware classes or through virtual input.

Most AnyKeyPressed methods are statics.

Keyboard.AnyKeyPressed();
Mouse.AnyKeyPressed();
GamePad.AnyKeyPressed();

Before checking if any key is pressed with a virtual input you have to bind it to one or more device. The InputDevice enum is a flag enum so you can use it to represent many devices.

VirtualInput walkInput = playerOne.GetContext("Walk");
walkInput.AssociatedDevice = InputDevice.Mouse | InputDevice.Keyboard;

The InputDevice has two values for gamepad, one called GamePad and another one called AllGamePad. The first, GamePad, means that the virtual input will only checks the gamepad corresponding to the index player. AllGamePad means that the virtual input will checks for all gamepad.

Now you can check directly with the virtual input.

walkInput.AnyKeyPressed();