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

physics.mddocs/

0

# Physics Systems

1

2

Phaser provides two powerful physics engines: Arcade Physics for fast, simple 2D collision detection, and Matter.js for realistic physics simulation. Choose the system that best fits your game's requirements.

3

4

## Arcade Physics

5

6

### World Setup

7

Arcade Physics provides a lightweight system perfect for most 2D games:

8

9

```javascript { .api }

10

// Game configuration with Arcade Physics

11

const config = {

12

type: Phaser.AUTO,

13

width: 800,

14

height: 600,

15

physics: {

16

default: 'arcade',

17

arcade: {

18

gravity: { x: 0, y: 300 },

19

debug: false,

20

debugShowBody: true,

21

debugShowStaticBody: true,

22

debugShowVelocity: true,

23

debugVelocityColor: 0x00ff00,

24

debugBodyColor: 0xff0000,

25

debugStaticBodyColor: 0x0000ff

26

}

27

},

28

scene: GameScene

29

};

30

31

class GameScene extends Phaser.Scene {

32

create() {

33

// Access physics world

34

const world = this.physics.world;

35

36

// World properties

37

console.log('Gravity:', world.gravity.x, world.gravity.y);

38

console.log('Bounds:', world.bounds);

39

console.log('Bodies count:', world.bodies.size);

40

41

// World bounds collision

42

world.setBoundsCollision(true, true, true, false); // left, right, top, bottom

43

44

// Custom world bounds

45

world.setBounds(0, 0, 1200, 800);

46

47

// Pause/resume physics

48

world.pause();

49

world.resume();

50

}

51

}

52

```

53

54

### Physics Bodies

55

Add physics to game objects:

56

57

```javascript { .api }

58

class PhysicsBodiesScene extends Phaser.Scene {

59

create() {

60

// Create physics-enabled sprites

61

this.player = this.physics.add.sprite(100, 100, 'player');

62

this.enemy = this.physics.add.sprite(300, 100, 'enemy');

63

64

// Static bodies (don't move)

65

this.platform = this.physics.add.staticSprite(400, 500, 'platform');

66

67

// Add physics to existing sprite

68

this.existingSprite = this.add.sprite(200, 200, 'item');

69

this.physics.add.existing(this.existingSprite);

70

71

// Body configuration

72

this.player.setCollideWorldBounds(true);

73

this.player.setBounce(0.2);

74

this.player.setDrag(100);

75

76

// Body size and offset

77

this.player.body.setSize(20, 30); // Custom collision size

78

this.player.body.setOffset(6, 2); // Offset from sprite origin

79

this.player.body.setCircle(15); // Circular collision shape

80

81

// Velocity

82

this.player.setVelocity(100, -300);

83

this.player.setVelocityX(150);

84

this.player.setVelocityY(-200);

85

86

// Acceleration

87

this.player.setAcceleration(50, 0);

88

this.player.setMaxVelocity(200, 400);

89

90

// Angular motion

91

this.player.setAngularVelocity(90); // degrees per second

92

this.player.setAngularAcceleration(45);

93

this.player.setAngularDrag(30);

94

95

// Mass and immovable

96

this.player.body.mass = 2;

97

this.platform.body.immovable = true;

98

}

99

100

update() {

101

// Check body properties

102

console.log('Player velocity:', this.player.body.velocity);

103

console.log('On floor:', this.player.body.onFloor());

104

console.log('On wall:', this.player.body.onWall());

105

console.log('Blocked down:', this.player.body.blocked.down);

106

107

// Manual velocity control

108

if (this.cursors.left.isDown) {

109

this.player.setVelocityX(-160);

110

} else if (this.cursors.right.isDown) {

111

this.player.setVelocityX(160);

112

} else {

113

this.player.setVelocityX(0);

114

}

115

116

// Jumping

117

if (this.cursors.up.isDown && this.player.body.touching.down) {

118

this.player.setVelocityY(-330);

119

}

120

}

121

}

122

```

123

124

### Collision Detection

125

Handle collisions between physics objects:

126

127

```javascript { .api }

128

class CollisionScene extends Phaser.Scene {

129

create() {

130

// Create game objects

131

this.player = this.physics.add.sprite(100, 450, 'player');

132

this.platforms = this.physics.add.staticGroup();

133

this.enemies = this.physics.add.group();

134

this.collectibles = this.physics.add.group();

135

136

// Add platforms

137

this.platforms.create(400, 568, 'ground').setScale(2).refreshBody();

138

this.platforms.create(600, 400, 'platform');

139

this.platforms.create(50, 250, 'platform');

140

141

// Basic collision

142

this.physics.add.collider(this.player, this.platforms);

143

144

// Collision with callback

145

this.physics.add.collider(this.player, this.enemies, this.hitEnemy, null, this);

146

147

// Overlap detection (no collision response)

148

this.physics.add.overlap(this.player, this.collectibles, this.collectItem, null, this);

149

150

// Collision with process callback (return true to separate)

151

this.physics.add.collider(this.player, this.enemies,

152

this.hitEnemy, // Collision callback

153

this.processHit, // Process callback (can prevent collision)

154

this

155

);

156

157

// Group vs group collisions

158

this.physics.add.collider(this.enemies, this.platforms);

159

this.physics.add.collider(this.enemies, this.enemies);

160

161

// World bounds collision

162

this.physics.add.collider(this.player, this.physics.world.bounds);

163

}

164

165

hitEnemy(player, enemy) {

166

console.log('Player hit enemy!');

167

enemy.setTint(0xff0000);

168

169

// Bounce player away

170

if (player.x < enemy.x) {

171

player.setVelocityX(-200);

172

} else {

173

player.setVelocityX(200);

174

}

175

176

// Damage player

177

this.playerHealth -= 10;

178

}

179

180

processHit(player, enemy) {

181

// Only allow collision if player is attacking

182

return this.playerIsAttacking;

183

}

184

185

collectItem(player, item) {

186

item.destroy();

187

this.score += 10;

188

189

// Play collection effect

190

this.tweens.add({

191

targets: player,

192

scaleX: 1.2,

193

scaleY: 1.2,

194

duration: 100,

195

yoyo: true

196

});

197

}

198

}

199

```

200

201

### Groups and Physics

202

Manage collections of physics objects:

203

204

```javascript { .api }

205

class PhysicsGroupsScene extends Phaser.Scene {

206

create() {

207

// Static group (platforms, walls)

208

this.platforms = this.physics.add.staticGroup();

209

this.platforms.create(400, 568, 'ground');

210

this.platforms.create(600, 400, 'platform');

211

212

// Dynamic group (moving objects)

213

this.enemies = this.physics.add.group({

214

key: 'enemy',

215

repeat: 5,

216

setXY: { x: 100, y: 0, stepX: 100 }

217

});

218

219

// Group with physics configuration

220

this.bullets = this.physics.add.group({

221

defaultKey: 'bullet',

222

maxSize: 20,

223

runChildUpdate: true,

224

createCallback: (bullet) => {

225

bullet.body.onWorldBounds = true;

226

bullet.body.world.on('worldbounds', (event, body) => {

227

if (body.gameObject === bullet) {

228

bullet.destroy();

229

}

230

});

231

}

232

});

233

234

// Group operations

235

this.enemies.children.entries.forEach(enemy => {

236

enemy.setBounce(1);

237

enemy.setCollideWorldBounds(true);

238

enemy.setVelocity(Phaser.Math.Between(-200, 200), 20);

239

});

240

241

// Batch physics properties

242

Phaser.Actions.Call(this.enemies.children.entries, (enemy) => {

243

enemy.setTint(Math.random() * 0xffffff);

244

});

245

246

// Create objects in group

247

const newEnemy = this.enemies.create(300, 200, 'enemy');

248

newEnemy.setVelocity(100, -100);

249

250

// Get objects from group

251

const firstEnemy = this.enemies.getFirst();

252

const randomEnemy = this.enemies.getRandom();

253

254

// Remove from group

255

this.enemies.remove(newEnemy);

256

this.enemies.killAndHide(randomEnemy);

257

}

258

}

259

```

260

261

### Advanced Arcade Features

262

Additional Arcade Physics capabilities:

263

264

```javascript { .api }

265

class AdvancedArcadeScene extends Phaser.Scene {

266

create() {

267

this.player = this.physics.add.sprite(100, 450, 'player');

268

this.platforms = this.physics.add.staticGroup();

269

270

// One-way platforms

271

const oneWayPlatform = this.platforms.create(400, 400, 'platform');

272

oneWayPlatform.body.checkCollision.down = false;

273

oneWayPlatform.body.checkCollision.left = false;

274

oneWayPlatform.body.checkCollision.right = false;

275

276

// Moving platforms

277

const movingPlatform = this.physics.add.image(200, 300, 'platform');

278

movingPlatform.setImmovable(true);

279

movingPlatform.body.kinematic = true;

280

movingPlatform.setVelocityX(50);

281

282

// Conveyor belt effect

283

const conveyorBelt = this.platforms.create(600, 500, 'conveyor');

284

this.physics.add.collider(this.player, conveyorBelt, (player, belt) => {

285

player.setVelocityX(player.body.velocity.x + 50);

286

});

287

288

// Slopes (requires custom collision handling)

289

this.slope = this.add.rectangle(400, 350, 200, 20, 0x00ff00);

290

this.physics.add.existing(this.slope, true); // Static body

291

292

// Custom separation

293

this.physics.add.overlap(this.player, this.slope, this.handleSlope, null, this);

294

295

// Body events

296

this.physics.world.on('worldbounds', (event, body) => {

297

console.log('Body hit world bounds:', body.gameObject);

298

if (body.gameObject === this.player) {

299

this.playerFellOff();

300

}

301

});

302

303

// Custom physics step

304

this.physics.world.on('worldstep', () => {

305

// Custom physics logic runs every step

306

this.applyCustomForces();

307

});

308

}

309

310

handleSlope(player, slope) {

311

// Custom slope physics

312

const slopeAngle = Math.PI / 6; // 30 degrees

313

const gravity = this.physics.world.gravity.y;

314

315

if (player.body.touching.down) {

316

const slopeForce = Math.sin(slopeAngle) * gravity;

317

player.setAccelerationX(slopeForce);

318

}

319

}

320

321

applyCustomForces() {

322

// Apply wind force

323

if (this.windActive) {

324

this.player.body.velocity.x += this.windStrength;

325

}

326

327

// Apply water resistance

328

if (this.playerInWater) {

329

this.player.body.velocity.x *= 0.95;

330

this.player.body.velocity.y *= 0.95;

331

}

332

}

333

}

334

```

335

336

## Matter.js Physics

337

338

### Matter World Setup

339

Matter.js provides realistic physics simulation:

340

341

```javascript { .api }

342

// Game configuration with Matter.js

343

const config = {

344

type: Phaser.AUTO,

345

width: 800,

346

height: 600,

347

physics: {

348

default: 'matter',

349

matter: {

350

gravity: { x: 0, y: 1 },

351

debug: {

352

showAxes: false,

353

showAngleIndicator: false,

354

angleColor: 0xe81153,

355

showBody: true,

356

showStaticBody: true,

357

showVelocity: true,

358

bodyColor: 0xffffff,

359

bodyFillColor: 0xffffff,

360

bodyLineWidth: 1,

361

staticBodyColor: 0x0d177b,

362

velocityColor: 0x00aeef,

363

velocityLineWidth: 1,

364

velocityLineLength: 20

365

}

366

}

367

},

368

scene: MatterScene

369

};

370

371

class MatterScene extends Phaser.Scene {

372

create() {

373

// Access Matter world

374

const world = this.matter.world;

375

376

// World configuration

377

world.setBounds(0, 0, 800, 600);

378

world.disableGravity(); // Disable gravity

379

world.setGravity(0, 0.8); // Custom gravity

380

381

// Engine properties

382

const engine = world.engine;

383

engine.world.gravity.scale = 0.001; // Gravity scale

384

engine.timing.timeScale = 1; // Time scale

385

}

386

}

387

```

388

389

### Matter Bodies

390

Create various physics bodies:

391

392

```javascript { .api }

393

class MatterBodiesScene extends Phaser.Scene {

394

create() {

395

// Rectangle body

396

this.box = this.matter.add.rectangle(400, 200, 80, 80, {

397

frictionAir: 0.01,

398

friction: 0.1,

399

frictionStatic: 0.5,

400

restitution: 0.8,

401

density: 0.001

402

});

403

404

// Circle body

405

this.ball = this.matter.add.circle(100, 200, 30, {

406

restitution: 0.9,

407

density: 0.002

408

});

409

410

// Polygon body

411

this.triangle = this.matter.add.polygon(600, 200, 3, 40, {

412

angle: Math.PI / 6

413

});

414

415

// Trapezoid

416

this.trapezoid = this.matter.add.trapezoid(300, 300, 80, 50, 0.5);

417

418

// Complex shapes from vertices

419

const star = this.matter.add.fromVertices(500, 300, [

420

{ x: 0, y: -20 },

421

{ x: 6, y: -6 },

422

{ x: 20, y: -6 },

423

{ x: 10, y: 2 },

424

{ x: 16, y: 16 },

425

{ x: 0, y: 8 },

426

{ x: -16, y: 16 },

427

{ x: -10, y: 2 },

428

{ x: -20, y: -6 },

429

{ x: -6, y: -6 }

430

]);

431

432

// Sprite with Matter body

433

this.player = this.matter.add.sprite(200, 100, 'player', null, {

434

shape: {

435

type: 'circle',

436

radius: 16

437

}

438

});

439

440

// Image with physics

441

this.crate = this.matter.add.image(150, 300, 'crate');

442

443

// Static bodies

444

this.ground = this.matter.add.rectangle(400, 580, 800, 40, {

445

isStatic: true

446

});

447

448

// Sensors (trigger areas)

449

this.sensor = this.matter.add.rectangle(400, 100, 100, 50, {

450

isSensor: true,

451

render: {

452

fillStyle: 'rgba(255, 255, 0, 0.5)'

453

}

454

});

455

}

456

}

457

```

458

459

### Matter Constraints

460

Connect bodies with constraints:

461

462

```javascript { .api }

463

class MatterConstraintsScene extends Phaser.Scene {

464

create() {

465

// Create bodies

466

const bodyA = this.matter.add.rectangle(300, 200, 50, 50);

467

const bodyB = this.matter.add.rectangle(450, 200, 50, 50);

468

const anchor = this.matter.add.rectangle(400, 100, 20, 20, { isStatic: true });

469

470

// Basic constraint (rope/string)

471

this.matter.add.constraint(bodyA, bodyB, 100, 0.7);

472

473

// Constraint to world point

474

this.matter.add.worldConstraint(anchor, 0, 0, {

475

pointA: { x: 0, y: 0 },

476

pointB: { x: 0, y: 0 },

477

length: 200,

478

stiffness: 0.8

479

});

480

481

// Spring constraint

482

this.matter.add.constraint(bodyA, bodyB, 150, 0.1, {

483

damping: 0.1,

484

angularStiffness: 0,

485

render: {

486

lineWidth: 5,

487

strokeStyle: '#90C695',

488

type: 'spring'

489

}

490

});

491

492

// Pin constraint (fixed point)

493

this.matter.add.constraint(bodyA, anchor, 0, 1, {

494

pointA: { x: 0, y: 0 },

495

pointB: { x: 0, y: 0 }

496

});

497

498

// Mouse constraint (drag with mouse)

499

this.matter.add.mouseSpring({

500

length: 0.01,

501

stiffness: 0.1

502

});

503

504

// Chain of bodies

505

const chain = [];

506

for (let i = 0; i < 5; i++) {

507

chain.push(this.matter.add.rectangle(100 + i * 60, 300, 40, 40));

508

}

509

510

// Connect chain links

511

for (let i = 0; i < chain.length - 1; i++) {

512

this.matter.add.constraint(chain[i], chain[i + 1], 60, 0.9);

513

}

514

}

515

}

516

```

517

518

### Matter Events

519

Handle collision and constraint events:

520

521

```javascript { .api }

522

class MatterEventsScene extends Phaser.Scene {

523

create() {

524

// Create objects

525

this.ball = this.matter.add.circle(400, 100, 30);

526

this.ground = this.matter.add.rectangle(400, 580, 800, 40, { isStatic: true });

527

528

// Collision events

529

this.matter.world.on('collisionstart', (event) => {

530

event.pairs.forEach((pair) => {

531

const { bodyA, bodyB } = pair;

532

console.log('Collision started between:', bodyA.label, bodyB.label);

533

534

// Check specific collision

535

if ((bodyA === this.ball.body && bodyB === this.ground.body) ||

536

(bodyB === this.ball.body && bodyA === this.ground.body)) {

537

this.ballHitGround();

538

}

539

});

540

});

541

542

this.matter.world.on('collisionactive', (event) => {

543

// Collision is ongoing

544

event.pairs.forEach((pair) => {

545

console.log('Collision active');

546

});

547

});

548

549

this.matter.world.on('collisionend', (event) => {

550

// Collision ended

551

event.pairs.forEach((pair) => {

552

console.log('Collision ended');

553

});

554

});

555

556

// Constraint events

557

this.matter.world.on('constraintbreak', (event) => {

558

console.log('Constraint broke:', event.constraint);

559

});

560

561

// Before/after update events

562

this.matter.world.on('beforeupdate', () => {

563

// Custom physics logic before engine update

564

});

565

566

this.matter.world.on('afterupdate', () => {

567

// Custom physics logic after engine update

568

});

569

570

// Sleep events

571

this.matter.world.on('sleepstart', (event) => {

572

console.log('Body went to sleep:', event.source);

573

});

574

575

this.matter.world.on('sleepend', (event) => {

576

console.log('Body woke up:', event.source);

577

});

578

}

579

580

ballHitGround() {

581

// Create impact effect

582

this.tweens.add({

583

targets: this.ball,

584

scaleX: 1.2,

585

scaleY: 0.8,

586

duration: 100,

587

yoyo: true

588

});

589

}

590

}

591

```

592

593

### Advanced Matter Features

594

Complex Matter.js functionality:

595

596

```javascript { .api }

597

class AdvancedMatterScene extends Phaser.Scene {

598

create() {

599

// Composite bodies (multiple shapes as one body)

600

const carBody = this.matter.add.rectangle(400, 200, 100, 50);

601

const wheelA = this.matter.add.circle(350, 225, 25);

602

const wheelB = this.matter.add.circle(450, 225, 25);

603

604

// Create car composite

605

const car = this.matter.body.create({

606

parts: [carBody, wheelA, wheelB]

607

});

608

this.matter.world.add(car);

609

610

// Body modification

611

this.matter.body.scale(this.ball.body, 1.5, 1.5);

612

this.matter.body.rotate(this.box.body, Math.PI / 4);

613

this.matter.body.translate(this.triangle.body, { x: 100, y: -50 });

614

615

// Apply forces

616

this.matter.body.applyForce(this.ball.body,

617

this.ball.body.position,

618

{ x: 0.05, y: -0.1 }

619

);

620

621

// Set velocity directly

622

this.matter.body.setVelocity(this.ball.body, { x: 5, y: -10 });

623

this.matter.body.setAngularVelocity(this.box.body, 0.1);

624

625

// Body properties

626

this.matter.body.setMass(this.ball.body, 10);

627

this.matter.body.setDensity(this.box.body, 0.002);

628

this.matter.body.setInertia(this.triangle.body, Infinity); // Prevent rotation

629

630

// Collision filtering

631

const categoryA = 0x0001;

632

const categoryB = 0x0002;

633

const categoryC = 0x0004;

634

635

// Bodies in category A collide with B and C

636

this.ball.body.collisionFilter = {

637

category: categoryA,

638

mask: categoryB | categoryC

639

};

640

641

// Bodies in category B only collide with A

642

this.box.body.collisionFilter = {

643

category: categoryB,

644

mask: categoryA

645

};

646

647

// Raycast

648

const rayCast = this.matter.world.raycast(

649

{ x: 100, y: 100 }, // Start point

650

{ x: 700, y: 500 } // End point

651

);

652

653

if (rayCast.length > 0) {

654

console.log('Ray hit:', rayCast[0].body);

655

}

656

657

// Query region

658

const bodiesInRegion = this.matter.world.query({

659

x: 300, y: 200,

660

width: 200, height: 100

661

});

662

663

console.log('Bodies in region:', bodiesInRegion);

664

}

665

}

666

```

667

668

## Performance Optimization

669

670

### Physics Performance Tips

671

Optimize physics performance:

672

673

```javascript { .api }

674

class PhysicsOptimizationScene extends Phaser.Scene {

675

create() {

676

// Limit physics bodies

677

const maxBodies = 100;

678

679

// Use object pooling for bullets/particles

680

this.bulletPool = this.physics.add.group({

681

maxSize: 20,

682

runChildUpdate: true

683

});

684

685

// Disable bodies when off-screen

686

this.physics.world.on('worldstep', () => {

687

this.enemies.children.entries.forEach(enemy => {

688

if (!this.cameras.main.worldView.contains(enemy.x, enemy.y)) {

689

enemy.body.enable = false;

690

} else {

691

enemy.body.enable = true;

692

}

693

});

694

});

695

696

// Use static bodies for non-moving objects

697

const staticPlatforms = this.physics.add.staticGroup();

698

699

// Reduce physics iterations for better performance

700

// (Matter.js only)

701

if (this.matter) {

702

this.matter.world.engine.positionIterations = 6; // Default: 6

703

this.matter.world.engine.velocityIterations = 4; // Default: 4

704

this.matter.world.engine.constraintIterations = 2; // Default: 2

705

}

706

707

// Use collision categories to reduce collision checks

708

// (Matter.js only)

709

const playerCategory = 0x0001;

710

const enemyCategory = 0x0002;

711

const platformCategory = 0x0004;

712

713

// Sleep inactive bodies (Matter.js)

714

if (this.matter) {

715

this.matter.world.engine.enableSleeping = true;

716

}

717

}

718

}

719

```

720

721

This comprehensive physics system provides both simple collision detection for arcade-style games and realistic physics simulation for more complex interactions, giving developers the flexibility to choose the right tool for their game's needs.