$npx -y skills add Yakoub-ai/phaser4-gamedev --skill phaser-inputThis skill should be used when the user asks to "handle input", "keyboard controls", "mouse click", "touch controls", "gamepad support", "drag and drop", "virtual joystick", "WASD movement", "detect click", "pointer events", "keyboard shortcut", or "input manager".
| 1 | # Phaser 4 Input |
| 2 | |
| 3 | Phaser 4's Input system supports keyboard, mouse/pointer, touch, and gamepad. All input is accessed through `this.input` inside a Scene. |
| 4 | |
| 5 | ## Keyboard Input |
| 6 | |
| 7 | ### Cursor Keys |
| 8 | |
| 9 | Create a cursor key set to track arrow keys, space, and shift in one call: |
| 10 | |
| 11 | ```typescript |
| 12 | private cursors!: Phaser.Types.Input.Keyboard.CursorKeys; |
| 13 | |
| 14 | create(): void { |
| 15 | this.cursors = this.input.keyboard!.createCursorKeys(); |
| 16 | } |
| 17 | |
| 18 | update(): void { |
| 19 | if (this.cursors.left.isDown) { /* move left */ } |
| 20 | if (this.cursors.right.isDown) { /* move right */ } |
| 21 | if (this.cursors.up.isDown) { /* move up / jump */ } |
| 22 | if (this.cursors.down.isDown) { /* move down / crouch */ } |
| 23 | if (this.cursors.space.isDown) { /* fire / action */ } |
| 24 | if (this.cursors.shift.isDown) { /* sprint / modifier */ } |
| 25 | } |
| 26 | ``` |
| 27 | |
| 28 | ### WASD Keys |
| 29 | |
| 30 | Use `addKeys` to bind arbitrary keys by name: |
| 31 | |
| 32 | ```typescript |
| 33 | private wasd!: { up: Phaser.Input.Keyboard.Key; left: Phaser.Input.Keyboard.Key; down: Phaser.Input.Keyboard.Key; right: Phaser.Input.Keyboard.Key }; |
| 34 | |
| 35 | create(): void { |
| 36 | this.wasd = this.input.keyboard!.addKeys({ up: 'W', left: 'A', down: 'S', right: 'D' }) as typeof this.wasd; |
| 37 | } |
| 38 | |
| 39 | update(): void { |
| 40 | if (this.wasd.left.isDown) { /* strafe left */ } |
| 41 | if (this.wasd.right.isDown) { /* strafe right */ } |
| 42 | } |
| 43 | ``` |
| 44 | |
| 45 | ### Single Key |
| 46 | |
| 47 | Bind a single key using `KeyCodes`: |
| 48 | |
| 49 | ```typescript |
| 50 | private spaceKey!: Phaser.Input.Keyboard.Key; |
| 51 | private shiftKey!: Phaser.Input.Keyboard.Key; |
| 52 | |
| 53 | create(): void { |
| 54 | this.spaceKey = this.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE); |
| 55 | this.shiftKey = this.input.keyboard!.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT); |
| 56 | } |
| 57 | ``` |
| 58 | |
| 59 | ### isDown vs JustDown vs JustUp |
| 60 | |
| 61 | | Method | Behavior | |
| 62 | |---|---| |
| 63 | | `key.isDown` | `true` every frame the key is held | |
| 64 | | `Phaser.Input.Keyboard.JustDown(key)` | `true` on the single frame the key is first pressed | |
| 65 | | `Phaser.Input.Keyboard.JustUp(key)` | `true` on the single frame the key is released | |
| 66 | |
| 67 | ```typescript |
| 68 | update(): void { |
| 69 | // Continuous — fires every frame while held |
| 70 | if (this.cursors.left.isDown) { |
| 71 | this.player.setVelocityX(-200); |
| 72 | } |
| 73 | |
| 74 | // One-shot — fires once per key press |
| 75 | if (Phaser.Input.Keyboard.JustDown(this.spaceKey)) { |
| 76 | this.fireBullet(); |
| 77 | } |
| 78 | |
| 79 | // Release — fires once per key release |
| 80 | if (Phaser.Input.Keyboard.JustUp(this.shiftKey)) { |
| 81 | this.stopSprint(); |
| 82 | } |
| 83 | } |
| 84 | ``` |
| 85 | |
| 86 | ### Key Combos (Konami Code, Cheat Codes) |
| 87 | |
| 88 | ```typescript |
| 89 | create(): void { |
| 90 | // Konami: Up Up Down Down Left Right Left Right A B |
| 91 | const combo = this.input.keyboard!.createCombo( |
| 92 | [38, 38, 40, 40, 37, 39, 37, 39, 65, 66], |
| 93 | { resetOnMatch: true } |
| 94 | ); |
| 95 | |
| 96 | this.input.keyboard!.on('keycombomatch', (combo: Phaser.Input.Keyboard.KeyCombo) => { |
| 97 | console.log('Konami code entered!'); |
| 98 | this.activateCheatMode(); |
| 99 | }); |
| 100 | } |
| 101 | ``` |
| 102 | |
| 103 | ### Disabling Browser Default Keys |
| 104 | |
| 105 | Prevent the browser from intercepting arrow keys (page scroll) and other keys: |
| 106 | |
| 107 | ```typescript |
| 108 | create(): void { |
| 109 | // Disable global capture — let browser handle keys normally |
| 110 | this.input.keyboard!.disableGlobalCapture(); |
| 111 | |
| 112 | // Enable global capture — Phaser intercepts keys before the browser |
| 113 | this.input.keyboard!.enableGlobalCapture(); |
| 114 | |
| 115 | // Capture only specific keys (recommended approach) |
| 116 | this.input.keyboard!.addCapture([ |
| 117 | Phaser.Input.Keyboard.KeyCodes.UP, |
| 118 | Phaser.Input.Keyboard.KeyCodes.DOWN, |
| 119 | Phaser.Input.Keyboard.KeyCodes.LEFT, |
| 120 | Phaser.Input.Keyboard.KeyCodes.RIGHT, |
| 121 | Phaser.Input.Keyboard.KeyCodes.SPACE, |
| 122 | ]); |
| 123 | } |
| 124 | ``` |
| 125 | |
| 126 | --- |
| 127 | |
| 128 | ## Pointer / Mouse Input |
| 129 | |
| 130 | ### Global Pointer Events |
| 131 | |
| 132 | Listen on `this.input` for events anywhere in the game canvas: |
| 133 | |
| 134 | ```typescript |
| 135 | create(): void { |
| 136 | this.input.on('pointerdown', (ptr: Phaser.Input.Pointer) => { |
| 137 | console.log(`Clicked at canvas: ${ptr.x}, ${ptr.y}`); |
| 138 | console.log(`World position: ${ptr.worldX}, ${ptr.worldY}`); |
| 139 | console.log(`Left button: ${ptr.leftButtonDown()}`); |
| 140 | console.log(`Right button: ${ptr.rightButtonDown()}`); |
| 141 | }); |
| 142 | |
| 143 | this.input.on('pointermove', (ptr: Phaser.Input.Pointer) => { |
| 144 | // ptr.velocity.x / ptr.velocity.y for movement delta |
| 145 | }); |
| 146 | |
| 147 | this.input.on('pointerup', (ptr: Phaser.Input.Pointer) => { |
| 148 | // handle release |
| 149 | }); |
| 150 | } |
| 151 | ``` |
| 152 | |
| 153 | Use `ptr.worldX` / `ptr.worldY` when the camera has moved — these give the world-space position rather than screen-space. |
| 154 | |
| 155 | ### Making Sprites Interactive |
| 156 | |
| 157 | Call `setInteractive()` before listening to pointer events on a specific object: |
| 158 | |
| 159 | ```typescript |
| 160 | create(): void { |
| 161 | const button = this.add.image(400, 300, 'button'); |
| 162 | button.setInteractive({ useHandCursor: true }); // shows pointer cursor on hover |
| 163 | |
| 164 | button.on('pointerdown', () => { |
| 165 | this.scene.start('GameScene'); |
| 166 | }); |
| 167 | |
| 168 | button.on('pointerover', () => { |
| 169 | button.setTint(0x |