or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

actions.mdanimation.mdaudio.mdcameras.mddata-management.mdevents.mdgame-objects.mdindex.mdinput.mdloading.mdmath-geometry.mdphysics.mdrendering.mdscenes.mdtweens.mdutilities.md

input.mddocs/

0

# Input Handling

1

2

Phaser provides comprehensive input handling for keyboard, mouse, touch, and gamepad input across desktop and mobile platforms. The input system supports both polling and event-driven approaches for maximum flexibility.

3

4

## Input Manager

5

6

### Scene Input Plugin

7

Each scene has its own input manager accessible via `this.input`:

8

9

```javascript { .api }

10

class InputScene extends Phaser.Scene {

11

create() {

12

const input = this.input;

13

14

// Input properties

15

console.log('Active pointer count:', input.activePointer);

16

console.log('Mouse enabled:', input.mouse.enabled);

17

console.log('Touch enabled:', input.touch.enabled);

18

console.log('Gamepad enabled:', input.gamepad.enabled);

19

20

// Global input events

21

input.on('pointerdown', this.handlePointerDown, this);

22

input.on('pointermove', this.handlePointerMove, this);

23

input.on('pointerup', this.handlePointerUp, this);

24

input.on('gameout', () => console.log('Pointer left game area'));

25

input.on('gameover', () => console.log('Pointer entered game area'));

26

}

27

28

handlePointerDown(pointer) {

29

console.log('Pointer down at:', pointer.x, pointer.y);

30

console.log('Left button:', pointer.leftButtonDown());

31

console.log('Right button:', pointer.rightButtonDown());

32

console.log('Middle button:', pointer.middleButtonDown());

33

}

34

}

35

```

36

37

### Pointer Objects

38

Pointers represent mouse cursors or touch points:

39

40

```javascript { .api }

41

class PointerScene extends Phaser.Scene {

42

create() {

43

this.input.on('pointerdown', (pointer) => {

44

// Pointer properties

45

console.log('Position:', pointer.x, pointer.y);

46

console.log('World position:', pointer.worldX, pointer.worldY);

47

console.log('Previous position:', pointer.prevPosition.x, pointer.prevPosition.y);

48

console.log('Velocity:', pointer.velocity.x, pointer.velocity.y);

49

console.log('Distance:', pointer.distance);

50

console.log('Duration:', pointer.getDuration());

51

console.log('Angle:', pointer.angle);

52

53

// Pointer identification

54

console.log('Pointer ID:', pointer.id);

55

console.log('Is primary pointer:', pointer.primaryDown);

56

console.log('Active buttons:', pointer.buttons);

57

58

// Touch-specific properties

59

console.log('Touch ID:', pointer.identifier);

60

console.log('Touch pressure:', pointer.pressure);

61

console.log('Touch size:', pointer.touchSizeX, pointer.touchSizeY);

62

});

63

64

// Multi-touch support

65

this.input.on('pointerdown', (pointer) => {

66

if (pointer.id === 0) {

67

console.log('First finger down');

68

} else if (pointer.id === 1) {

69

console.log('Second finger down - pinch gesture possible');

70

}

71

});

72

}

73

}

74

```

75

76

## Keyboard Input

77

78

### Cursor Keys

79

Quick access to arrow keys:

80

81

```javascript { .api }

82

class KeyboardScene extends Phaser.Scene {

83

create() {

84

// Create cursor keys object

85

this.cursors = this.input.keyboard.createCursorKeys();

86

}

87

88

update() {

89

// Polling approach

90

if (this.cursors.left.isDown) {

91

this.player.x -= 200 * this.game.loop.delta / 1000;

92

}

93

if (this.cursors.right.isDown) {

94

this.player.x += 200 * this.game.loop.delta / 1000;

95

}

96

if (this.cursors.up.isDown) {

97

this.player.y -= 200 * this.game.loop.delta / 1000;

98

}

99

if (this.cursors.down.isDown) {

100

this.player.y += 200 * this.game.loop.delta / 1000;

101

}

102

103

// Check for just pressed/released

104

if (Phaser.Input.Keyboard.JustDown(this.cursors.space)) {

105

this.playerJump();

106

}

107

if (Phaser.Input.Keyboard.JustUp(this.cursors.space)) {

108

this.playerLand();

109

}

110

}

111

}

112

```

113

114

### Individual Keys

115

Create and manage individual key objects:

116

117

```javascript { .api }

118

class IndividualKeysScene extends Phaser.Scene {

119

create() {

120

// Create individual keys

121

this.wasdKeys = this.input.keyboard.addKeys('W,S,A,D');

122

this.spaceKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);

123

this.escKey = this.input.keyboard.addKey('ESC');

124

this.enterKey = this.input.keyboard.addKey(13); // Key code

125

126

// Key events

127

this.spaceKey.on('down', () => {

128

console.log('Space pressed');

129

});

130

131

this.spaceKey.on('up', () => {

132

console.log('Space released');

133

});

134

135

// Global keyboard events

136

this.input.keyboard.on('keydown', (event) => {

137

console.log('Key pressed:', event.code);

138

});

139

140

this.input.keyboard.on('keyup-ESC', () => {

141

this.scene.pause();

142

});

143

}

144

145

update() {

146

// WASD movement

147

const speed = 200;

148

const delta = this.game.loop.delta / 1000;

149

150

if (this.wasdKeys.A.isDown) {

151

this.player.x -= speed * delta;

152

}

153

if (this.wasdKeys.D.isDown) {

154

this.player.x += speed * delta;

155

}

156

if (this.wasdKeys.W.isDown) {

157

this.player.y -= speed * delta;

158

}

159

if (this.wasdKeys.S.isDown) {

160

this.player.y += speed * delta;

161

}

162

}

163

}

164

```

165

166

### Key Combinations

167

Handle complex key combinations:

168

169

```javascript { .api }

170

class KeyCombinationsScene extends Phaser.Scene {

171

create() {

172

// Create key combinations

173

this.keys = this.input.keyboard.addKeys({

174

'up': Phaser.Input.Keyboard.KeyCodes.W,

175

'down': Phaser.Input.Keyboard.KeyCodes.S,

176

'left': Phaser.Input.Keyboard.KeyCodes.A,

177

'right': Phaser.Input.Keyboard.KeyCodes.D,

178

'shift': Phaser.Input.Keyboard.KeyCodes.SHIFT,

179

'ctrl': Phaser.Input.Keyboard.KeyCodes.CTRL,

180

'alt': Phaser.Input.Keyboard.KeyCodes.ALT

181

});

182

183

// Key combo events

184

this.input.keyboard.createCombo([

185

Phaser.Input.Keyboard.KeyCodes.CTRL,

186

Phaser.Input.Keyboard.KeyCodes.S

187

], {

188

resetOnMatch: true,

189

maxKeyDelay: 0,

190

resetOnWrongKey: true,

191

deleteOnMatch: false

192

});

193

194

this.input.keyboard.on('keycombomatch', (combo) => {

195

console.log('Key combo matched!');

196

this.saveGame();

197

});

198

}

199

200

update() {

201

const speed = this.keys.shift.isDown ? 400 : 200; // Run when shift held

202

const delta = this.game.loop.delta / 1000;

203

204

// Modifier key combinations

205

if (this.keys.ctrl.isDown && this.keys.up.isDown) {

206

this.player.jump();

207

} else if (this.keys.up.isDown) {

208

this.player.y -= speed * delta;

209

}

210

211

if (this.keys.alt.isDown && this.keys.left.isDown) {

212

this.player.strafe(-1);

213

} else if (this.keys.left.isDown) {

214

this.player.x -= speed * delta;

215

}

216

}

217

}

218

```

219

220

### Key Codes

221

Common key code constants:

222

223

```javascript { .api }

224

const KeyCodes = Phaser.Input.Keyboard.KeyCodes;

225

226

// Letter keys

227

KeyCodes.A // 65

228

KeyCodes.B // 66

229

// ... through Z

230

231

// Number keys

232

KeyCodes.ZERO // 48

233

KeyCodes.ONE // 49

234

// ... through NINE (57)

235

236

// Function keys

237

KeyCodes.F1 // 112

238

KeyCodes.F2 // 113

239

// ... through F12 (123)

240

241

// Special keys

242

KeyCodes.SPACE // 32

243

KeyCodes.ENTER // 13

244

KeyCodes.ESC // 27

245

KeyCodes.TAB // 9

246

KeyCodes.SHIFT // 16

247

KeyCodes.CTRL // 17

248

KeyCodes.ALT // 18

249

250

// Arrow keys

251

KeyCodes.LEFT // 37

252

KeyCodes.UP // 38

253

KeyCodes.RIGHT // 39

254

KeyCodes.DOWN // 40

255

```

256

257

## Mouse and Touch Input

258

259

### Basic Mouse/Touch Events

260

Handle mouse and touch uniformly through pointers:

261

262

```javascript { .api }

263

class MouseTouchScene extends Phaser.Scene {

264

create() {

265

// Basic pointer events

266

this.input.on('pointerdown', (pointer, gameObject) => {

267

console.log('Pointer down at:', pointer.x, pointer.y);

268

this.createClickEffect(pointer.x, pointer.y);

269

});

270

271

this.input.on('pointermove', (pointer) => {

272

if (pointer.isDown) {

273

console.log('Dragging at:', pointer.x, pointer.y);

274

this.drawTrail(pointer.x, pointer.y);

275

}

276

});

277

278

this.input.on('pointerup', (pointer) => {

279

console.log('Pointer released after:', pointer.getDuration(), 'ms');

280

});

281

282

// Mouse-specific events

283

this.input.on('wheel', (pointer, gameObjects, deltaX, deltaY, deltaZ) => {

284

console.log('Mouse wheel:', deltaY);

285

this.cameras.main.zoom += deltaY > 0 ? -0.1 : 0.1;

286

});

287

288

// Right-click context menu

289

this.input.on('pointerdown', (pointer) => {

290

if (pointer.rightButtonDown()) {

291

this.showContextMenu(pointer.x, pointer.y);

292

}

293

});

294

}

295

296

createClickEffect(x, y) {

297

const effect = this.add.circle(x, y, 20, 0xffffff, 0.5);

298

this.tweens.add({

299

targets: effect,

300

scaleX: 2,

301

scaleY: 2,

302

alpha: 0,

303

duration: 300,

304

onComplete: () => effect.destroy()

305

});

306

}

307

}

308

```

309

310

### Interactive Objects

311

Make game objects respond to input:

312

313

```javascript { .api }

314

class InteractiveScene extends Phaser.Scene {

315

create() {

316

// Basic interactive object

317

const button = this.add.rectangle(400, 300, 200, 100, 0x00ff00);

318

button.setInteractive();

319

320

button.on('pointerdown', () => {

321

console.log('Button clicked!');

322

});

323

324

button.on('pointerover', () => {

325

button.setFillStyle(0x00aa00);

326

});

327

328

button.on('pointerout', () => {

329

button.setFillStyle(0x00ff00);

330

});

331

332

// Custom hit areas

333

const sprite = this.add.sprite(200, 200, 'player');

334

sprite.setInteractive(new Phaser.Geom.Circle(25, 25, 25), Phaser.Geom.Circle.Contains);

335

336

// Rectangle hit area

337

const image = this.add.image(600, 200, 'logo');

338

image.setInteractive(new Phaser.Geom.Rectangle(0, 0, 100, 50), Phaser.Geom.Rectangle.Contains);

339

340

// Pixel-perfect hit detection

341

const pixelSprite = this.add.sprite(400, 500, 'character');

342

pixelSprite.setInteractive({

343

pixelPerfect: true,

344

alphaTolerance: 1

345

});

346

}

347

}

348

```

349

350

### Drag and Drop

351

Implement drag and drop functionality:

352

353

```javascript { .api }

354

class DragDropScene extends Phaser.Scene {

355

create() {

356

// Create draggable objects

357

const box1 = this.add.rectangle(200, 200, 100, 100, 0xff0000);

358

const box2 = this.add.rectangle(400, 200, 100, 100, 0x00ff00);

359

const box3 = this.add.rectangle(600, 200, 100, 100, 0x0000ff);

360

361

// Make objects draggable

362

box1.setInteractive({ draggable: true });

363

box2.setInteractive({ draggable: true });

364

box3.setInteractive({ draggable: true });

365

366

// Drag events

367

this.input.on('dragstart', (pointer, gameObject) => {

368

console.log('Drag started:', gameObject);

369

gameObject.setTint(0x888888);

370

});

371

372

this.input.on('drag', (pointer, gameObject, dragX, dragY) => {

373

gameObject.x = dragX;

374

gameObject.y = dragY;

375

});

376

377

this.input.on('dragend', (pointer, gameObject) => {

378

console.log('Drag ended:', gameObject);

379

gameObject.clearTint();

380

});

381

382

// Drop zones

383

const dropZone = this.add.zone(400, 500, 200, 100);

384

dropZone.setRectangleDropZone(200, 100);

385

386

// Visual feedback for drop zone

387

const dropZoneGraphic = this.add.graphics();

388

dropZoneGraphic.lineStyle(2, 0xffffff);

389

dropZoneGraphic.strokeRect(300, 450, 200, 100);

390

391

// Drop events

392

this.input.on('drop', (pointer, gameObject, dropZone) => {

393

console.log('Object dropped in zone!');

394

gameObject.x = dropZone.x;

395

gameObject.y = dropZone.y;

396

});

397

398

this.input.on('dragenter', (pointer, gameObject, dropZone) => {

399

dropZoneGraphic.clear();

400

dropZoneGraphic.lineStyle(2, 0x00ff00);

401

dropZoneGraphic.strokeRect(300, 450, 200, 100);

402

});

403

404

this.input.on('dragleave', (pointer, gameObject, dropZone) => {

405

dropZoneGraphic.clear();

406

dropZoneGraphic.lineStyle(2, 0xffffff);

407

dropZoneGraphic.strokeRect(300, 450, 200, 100);

408

});

409

}

410

}

411

```

412

413

## Gamepad Input

414

415

### Gamepad Setup

416

Support for multiple gamepads:

417

418

```javascript { .api }

419

class GamepadScene extends Phaser.Scene {

420

create() {

421

// Enable gamepad input

422

this.input.gamepad.start();

423

424

// Listen for gamepad connection

425

this.input.gamepad.on('connected', (pad) => {

426

console.log('Gamepad connected:', pad.index, pad.id);

427

this.setupGamepad(pad);

428

});

429

430

this.input.gamepad.on('disconnected', (pad) => {

431

console.log('Gamepad disconnected:', pad.index);

432

});

433

434

// Get existing gamepads

435

if (this.input.gamepad.total > 0) {

436

this.gamepad = this.input.gamepad.pad1; // First gamepad

437

this.setupGamepad(this.gamepad);

438

}

439

}

440

441

setupGamepad(pad) {

442

// Button events

443

pad.on('down', (index, value, button) => {

444

console.log('Button pressed:', index, button.id);

445

});

446

447

pad.on('up', (index, value, button) => {

448

console.log('Button released:', index);

449

});

450

451

// Specific button events

452

if (pad.A) {

453

pad.A.on('down', () => {

454

this.playerJump();

455

});

456

}

457

458

if (pad.B) {

459

pad.B.on('down', () => {

460

this.playerAttack();

461

});

462

}

463

}

464

465

update() {

466

if (this.gamepad) {

467

// Left stick movement

468

const leftStick = this.gamepad.leftStick;

469

if (leftStick.length > 0.1) { // Deadzone

470

this.player.x += leftStick.x * 200 * (this.game.loop.delta / 1000);

471

this.player.y += leftStick.y * 200 * (this.game.loop.delta / 1000);

472

}

473

474

// Right stick camera

475

const rightStick = this.gamepad.rightStick;

476

if (rightStick.length > 0.1) {

477

this.cameras.main.scrollX += rightStick.x * 100 * (this.game.loop.delta / 1000);

478

this.cameras.main.scrollY += rightStick.y * 100 * (this.game.loop.delta / 1000);

479

}

480

481

// D-pad

482

if (this.gamepad.left) {

483

this.selectMenuItem(-1);

484

}

485

if (this.gamepad.right) {

486

this.selectMenuItem(1);

487

}

488

489

// Triggers

490

if (this.gamepad.L2 > 0.5) {

491

this.aimWeapon();

492

}

493

if (this.gamepad.R2 > 0.5) {

494

this.fireWeapon(this.gamepad.R2); // Pressure sensitive

495

}

496

}

497

}

498

}

499

```

500

501

### Gamepad Button Mapping

502

Access gamepad buttons by name or index:

503

504

```javascript { .api }

505

class GamepadMappingScene extends Phaser.Scene {

506

update() {

507

const pad = this.input.gamepad.pad1;

508

509

if (pad) {

510

// Face buttons (Xbox layout)

511

if (pad.A && pad.A.pressed) { console.log('A pressed'); }

512

if (pad.B && pad.B.pressed) { console.log('B pressed'); }

513

if (pad.X && pad.X.pressed) { console.log('X pressed'); }

514

if (pad.Y && pad.Y.pressed) { console.log('Y pressed'); }

515

516

// Shoulder buttons

517

if (pad.L1 && pad.L1.pressed) { console.log('Left bumper'); }

518

if (pad.R1 && pad.R1.pressed) { console.log('Right bumper'); }

519

520

// Triggers (analog values)

521

if (pad.L2 > 0) { console.log('Left trigger:', pad.L2); }

522

if (pad.R2 > 0) { console.log('Right trigger:', pad.R2); }

523

524

// D-pad

525

if (pad.up) { console.log('D-pad up'); }

526

if (pad.down) { console.log('D-pad down'); }

527

if (pad.left) { console.log('D-pad left'); }

528

if (pad.right) { console.log('D-pad right'); }

529

530

// Stick buttons

531

if (pad.L3 && pad.L3.pressed) { console.log('Left stick pressed'); }

532

if (pad.R3 && pad.R3.pressed) { console.log('Right stick pressed'); }

533

534

// System buttons

535

if (pad.select && pad.select.pressed) { console.log('Select/Back'); }

536

if (pad.start && pad.start.pressed) { console.log('Start/Menu'); }

537

}

538

}

539

}

540

```

541

542

## Advanced Input Techniques

543

544

### Input Sequences

545

Detect complex input patterns:

546

547

```javascript { .api }

548

class InputSequenceScene extends Phaser.Scene {

549

create() {

550

// Fighting game combo system

551

this.comboSequence = [];

552

this.comboTimer = 0;

553

this.maxComboDelay = 1000; // 1 second between inputs

554

555

// Define combos

556

this.combos = {

557

'hadoken': ['down', 'down-forward', 'forward', 'punch'],

558

'shoryuken': ['forward', 'down', 'down-forward', 'punch'],

559

'spin-kick': ['back', 'back', 'forward', 'kick']

560

};

561

562

// Input detection

563

this.input.keyboard.on('keydown-S', () => this.addToCombo('down'));

564

this.input.keyboard.on('keydown-W', () => this.addToCombo('up'));

565

this.input.keyboard.on('keydown-A', () => this.addToCombo('back'));

566

this.input.keyboard.on('keydown-D', () => this.addToCombo('forward'));

567

this.input.keyboard.on('keydown-J', () => this.addToCombo('punch'));

568

this.input.keyboard.on('keydown-K', () => this.addToCombo('kick'));

569

}

570

571

addToCombo(input) {

572

this.comboSequence.push(input);

573

this.comboTimer = this.time.now;

574

575

// Check for combo matches

576

this.checkCombos();

577

578

// Clear old inputs

579

if (this.comboSequence.length > 10) {

580

this.comboSequence.shift();

581

}

582

}

583

584

checkCombos() {

585

const sequence = this.comboSequence.join('-');

586

587

for (let [comboName, comboInputs] of Object.entries(this.combos)) {

588

const comboString = comboInputs.join('-');

589

if (sequence.includes(comboString)) {

590

this.executeCombo(comboName);

591

this.comboSequence = [];

592

break;

593

}

594

}

595

}

596

597

update(time) {

598

// Clear combo if too much time has passed

599

if (time - this.comboTimer > this.maxComboDelay) {

600

this.comboSequence = [];

601

}

602

}

603

}

604

```

605

606

### Gesture Recognition

607

Basic gesture detection for touch input:

608

609

```javascript { .api }

610

class GestureScene extends Phaser.Scene {

611

create() {

612

this.gesturePoints = [];

613

this.isRecording = false;

614

615

this.input.on('pointerdown', (pointer) => {

616

this.isRecording = true;

617

this.gesturePoints = [{ x: pointer.x, y: pointer.y, time: this.time.now }];

618

});

619

620

this.input.on('pointermove', (pointer) => {

621

if (this.isRecording) {

622

this.gesturePoints.push({

623

x: pointer.x,

624

y: pointer.y,

625

time: this.time.now

626

});

627

}

628

});

629

630

this.input.on('pointerup', () => {

631

this.isRecording = false;

632

this.recognizeGesture();

633

});

634

}

635

636

recognizeGesture() {

637

if (this.gesturePoints.length < 3) return;

638

639

const startPoint = this.gesturePoints[0];

640

const endPoint = this.gesturePoints[this.gesturePoints.length - 1];

641

642

const deltaX = endPoint.x - startPoint.x;

643

const deltaY = endPoint.y - startPoint.y;

644

const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);

645

646

if (distance > 100) { // Minimum swipe distance

647

const angle = Math.atan2(deltaY, deltaX);

648

const degrees = Phaser.Math.RadToDeg(angle);

649

650

if (degrees > -45 && degrees <= 45) {

651

this.onSwipeRight();

652

} else if (degrees > 45 && degrees <= 135) {

653

this.onSwipeDown();

654

} else if (degrees > 135 || degrees <= -135) {

655

this.onSwipeLeft();

656

} else {

657

this.onSwipeUp();

658

}

659

} else if (this.gesturePoints.length < 10) {

660

this.onTap();

661

}

662

}

663

664

onSwipeLeft() { console.log('Swiped left'); }

665

onSwipeRight() { console.log('Swiped right'); }

666

onSwipeUp() { console.log('Swiped up'); }

667

onSwipeDown() { console.log('Swiped down'); }

668

onTap() { console.log('Tapped'); }

669

}

670

```

671

672

### Multi-Touch Gestures

673

Handle complex multi-touch interactions:

674

675

```javascript { .api }

676

class MultiTouchScene extends Phaser.Scene {

677

create() {

678

this.pinchStart = null;

679

this.initialDistance = 0;

680

681

this.input.on('pointerdown', (pointer) => {

682

if (this.input.pointer1.isDown && this.input.pointer2.isDown) {

683

// Two fingers down - start pinch gesture

684

this.startPinch();

685

}

686

});

687

688

this.input.on('pointermove', () => {

689

if (this.input.pointer1.isDown && this.input.pointer2.isDown) {

690

this.updatePinch();

691

}

692

});

693

694

this.input.on('pointerup', () => {

695

if (!this.input.pointer1.isDown || !this.input.pointer2.isDown) {

696

this.endPinch();

697

}

698

});

699

}

700

701

startPinch() {

702

const pointer1 = this.input.pointer1;

703

const pointer2 = this.input.pointer2;

704

705

this.initialDistance = Phaser.Math.Distance.Between(

706

pointer1.x, pointer1.y,

707

pointer2.x, pointer2.y

708

);

709

710

this.pinchStart = {

711

zoom: this.cameras.main.zoom,

712

centerX: (pointer1.x + pointer2.x) / 2,

713

centerY: (pointer1.y + pointer2.y) / 2

714

};

715

}

716

717

updatePinch() {

718

if (!this.pinchStart) return;

719

720

const pointer1 = this.input.pointer1;

721

const pointer2 = this.input.pointer2;

722

723

const currentDistance = Phaser.Math.Distance.Between(

724

pointer1.x, pointer1.y,

725

pointer2.x, pointer2.y

726

);

727

728

const scale = currentDistance / this.initialDistance;

729

const newZoom = this.pinchStart.zoom * scale;

730

731

this.cameras.main.setZoom(Phaser.Math.Clamp(newZoom, 0.5, 3));

732

}

733

734

endPinch() {

735

this.pinchStart = null;

736

}

737

}

738

```

739

740

This comprehensive input system provides all the tools needed to create responsive, multi-platform games that work seamlessly across desktop and mobile devices.