Phaser AE

2D controls

Free packv3.0.0-02DLogic

Game code reads intents and axes, never keys. Name the actions your game has, fire, jump, dash, anything, and the pack drives them from the keyboard, gamepads and touch buttons, for up to four players, with rebinding built in.

This is a Free pack. Every phaser.io account can use it in their games.

Released October 19, 2026

2D controls: a screenshot of its demo
A note about these graphics

Expansion packs don't come with graphics. This screenshot is one way of drawing what the pack does, made for its demo: none of the sprites, tiles or backgrounds in it are in the pack.

That's by design. A pack is a game's logic, mechanics and effects, and it works with whatever art you give it. Some packs draw effects, backdrops or 3D scenes of their own, but none carries a game's sprites.

So the look is yours. Make the art on phaser.io, bring your own, or let your agent draw it in code: the same pack can look like anything.

What it does

An intent is an action named by your game and driven by any of its keys and pad buttons. pressed says it is held this step, justPressed is true for exactly one fixed step, and justReleased for the step after it is let go. A key tapped down and up between two steps still counts as a press, so fast taps are never lost. Asking about an intent the player has no binding for throws, naming the ones that exist, so a typo surfaces at once.

axis('move') comes from the move keys or, when none is held, the move stick, normalised to a length of at most 1, so the game cannot tell which was used. axis('aim') comes from the other stick while it is pushed, and otherwise is a unit vector from the player to the pointer once you call aimFrom(player). The pointer is also available in world units, with its press and release held for a step, so a click shorter than a frame is never missed.

Each of up to four players has their own move keys, intents and pad. bind, bindMove and usePad change them while the game runs, and bindings() returns a copy for a settings screen or a save. Touch controls join in by pressing codes such as 'Touch:fire', which an intent binds alongside its keys, so on-screen buttons need no second code path.

Features

  • Named intents — any action name, each driven by any of its keys and pad buttons.
  • Latched presses — justPressed and justReleased for exactly one step, even for a tap shorter than a frame.
  • Move and aim axes — keys or a stick for movement, a stick or the pointer for aim, both normalised.
  • Aim from the player — aimFrom measures pointer aim from any object, with a dead zone around it.
  • One to four players — each with their own keys, intents, pad and stick.
  • Rebinding at run time — bind, bindMove, usePad and bindings for a settings screen.
  • Touch codes — on-screen buttons press codes that intents bind like keys.
  • Sensible defaults — WASD and the arrows move, Space, J or pad A fire, E, K or pad B act, Escape or Start pauses, left stick moves and right stick aims.

Good for

  • Twin-stick shooters — move with one stick or WASD, aim with the other stick or the mouse from the ship.
  • Platformers — jump and dash as named intents, with short taps never dropped.
  • Top-down adventures — move and action on keys or a pad, the same code for both.
  • Local multiplayer brawlers — two to four players on one keyboard and their own pads.
  • Games with a controls menu — rebinding at run time, and bindings to show and save.
  • Games for touch as well as keys — on-screen buttons that drive the same intents.

Make it yours

For one player, bindings overrides only what it names and keeps the defaults for the rest: new move keys, a jump intent, a different pad. For several, players binds each one in full, with nothing shared, and a player without a pad gets the pad in their own slot. aimDeadzone sets how close the pointer may come to the player before aim drops to nothing.

Two very different setups: a single-player twin-stick shooter on the defaults, moving with WASD or the left stick and aiming with the mouse or the right stick from the ship; and a two-player platformer where one player jumps with G on the left of the keyboard and the other with the slash key on the right, each with their own pad, and a pause menu that lets either rebind their jump.

A quick look

Moving, firing on a tap and aiming at the mouse from the player:

const m = game.controls.axis('move');               // {x, y}, length ≤ 1
player.x += m.x * speed * dt; player.y += m.y * speed * dt;
if (game.controls.justPressed('fire')) shoot();     // true for one step
game.controls.aimFrom(player);                      // aim from the player, not the screen centre
const aim = game.controls.axis('aim');              // right stick, or towards the mouse
game.controls.player(1).bind('jump', { keys: ['Enter'], pad: ['a'] });   // from a rebinding screen

Works with

Good to know

  • Four players at most, sharing one keyboard and one pointer; each player's aim falls back to that pointer while their aim stick is still.
  • Pad buttons are sampled once per step, so a pad press shorter than a step can be missed; keys are latched and are not.
  • The move stick is read only while no move key is held.
  • A pointer-only or touch-only game can read the engine's input directly instead.

More Logic packs

Show all →