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

math-geometry.mddocs/

0

# Math and Geometry

1

2

Phaser provides an extensive mathematical library including vector operations, geometric shapes, intersection testing, interpolation functions, and mathematical utilities. These tools are essential for game physics, graphics, and general mathematical operations.

3

4

## Math Utilities

5

6

### Core Math Functions

7

Essential mathematical operations and utilities:

8

9

```javascript { .api }

10

// Basic mathematical functions

11

const result1 = Phaser.Math.Average([1, 2, 3, 4, 5]); // 3

12

const result2 = Phaser.Math.Clamp(150, 0, 100); // 100

13

const result3 = Phaser.Math.Distance.Between(0, 0, 100, 100); // 141.42...

14

const result4 = Phaser.Math.Linear(0, 10, 0.5); // 5

15

16

// Angle calculations

17

const angle1 = Phaser.Math.Angle.Between(0, 0, 100, 100); // π/4

18

const angle2 = Phaser.Math.DegToRad(90); // π/2

19

const angle3 = Phaser.Math.RadToDeg(Math.PI); // 180

20

21

// Random number generation

22

const random1 = Phaser.Math.Between(1, 10); // Random int 1-10

23

const random2 = Phaser.Math.FloatBetween(0, 1); // Random float 0-1

24

25

// Range and percentage

26

const percent = Phaser.Math.Percent(50, 0, 100); // 0.5

27

const value = Phaser.Math.FromPercent(0.75, 0, 200); // 150

28

29

// Wrapping and snapping

30

const wrapped = Phaser.Math.Wrap(270, 0, 360); // 270

31

const snapped = Phaser.Math.Snap.To(127, 50); // 150

32

```

33

34

### Vector Mathematics

35

Work with 2D, 3D, and 4D vectors:

36

37

```javascript { .api }

38

class VectorMathScene extends Phaser.Scene {

39

create() {

40

// Vector2 operations

41

const vec2a = new Phaser.Math.Vector2(3, 4);

42

const vec2b = new Phaser.Math.Vector2(1, 2);

43

44

// Basic vector operations

45

const sum = vec2a.clone().add(vec2b); // (4, 6)

46

const diff = vec2a.clone().subtract(vec2b); // (2, 2)

47

const scaled = vec2a.clone().scale(2); // (6, 8)

48

const normalized = vec2a.clone().normalize(); // Unit vector

49

50

// Vector properties

51

console.log('Length:', vec2a.length()); // 5

52

console.log('Angle:', vec2a.angle()); // 0.927... radians

53

console.log('Dot product:', vec2a.dot(vec2b)); // 11

54

console.log('Cross product:', vec2a.cross(vec2b)); // 2

55

56

// Vector manipulation

57

vec2a.setLength(10); // Set to specific length

58

vec2a.setAngle(Math.PI/4); // Set to specific angle

59

vec2a.rotate(Math.PI/6); // Rotate by angle

60

vec2a.lerp(vec2b, 0.5); // Linear interpolation

61

62

// Vector3 for 3D operations

63

const vec3 = new Phaser.Math.Vector3(1, 2, 3);

64

vec3.cross(new Phaser.Math.Vector3(4, 5, 6));

65

vec3.project(new Phaser.Math.Vector3(1, 0, 0));

66

67

// Vector4 for 4D operations (homogeneous coordinates)

68

const vec4 = new Phaser.Math.Vector4(1, 2, 3, 1);

69

vec4.transformMat4(transformMatrix);

70

}

71

}

72

```

73

74

### Matrix Operations

75

Handle transformation matrices:

76

77

```javascript { .api }

78

class MatrixMathScene extends Phaser.Scene {

79

create() {

80

// Matrix3 for 2D transformations

81

const matrix3 = new Phaser.Math.Matrix3();

82

83

// Matrix operations

84

matrix3.identity(); // Reset to identity

85

matrix3.translate(100, 50); // Translation

86

matrix3.rotate(Math.PI / 4); // Rotation

87

matrix3.scale(2, 1.5); // Scaling

88

89

// Transform points

90

const point = new Phaser.Math.Vector2(10, 20);

91

matrix3.transformPoint(point.x, point.y, point);

92

93

// Matrix combination

94

const transform1 = new Phaser.Math.Matrix3();

95

const transform2 = new Phaser.Math.Matrix3();

96

transform1.multiply(transform2); // Combine transformations

97

98

// Matrix4 for 3D transformations

99

const matrix4 = new Phaser.Math.Matrix4();

100

matrix4.perspective(75, 1.33, 0.1, 1000); // Perspective projection

101

matrix4.lookAt(

102

new Phaser.Math.Vector3(0, 0, 5), // Eye position

103

new Phaser.Math.Vector3(0, 0, 0), // Target

104

new Phaser.Math.Vector3(0, 1, 0) // Up vector

105

);

106

107

// Extract transformation components

108

const position = new Phaser.Math.Vector3();

109

const rotation = new Phaser.Math.Quaternion();

110

const scale = new Phaser.Math.Vector3();

111

matrix4.decompose(position, rotation, scale);

112

}

113

}

114

```

115

116

### Quaternions

117

Handle 3D rotations with quaternions:

118

119

```javascript { .api }

120

class QuaternionScene extends Phaser.Scene {

121

create() {

122

// Create quaternions

123

const quat1 = new Phaser.Math.Quaternion();

124

const quat2 = new Phaser.Math.Quaternion(0, 0, 0, 1);

125

126

// Set rotations

127

quat1.setFromEuler(Math.PI/4, 0, 0); // From Euler angles

128

quat2.setFromAxisAngle( // From axis-angle

129

new Phaser.Math.Vector3(0, 1, 0), // Axis

130

Math.PI / 2 // Angle

131

);

132

133

// Quaternion operations

134

const combined = quat1.clone().multiply(quat2); // Combine rotations

135

const interpolated = quat1.clone().slerp(quat2, 0.5); // Spherical interpolation

136

137

// Convert back to other formats

138

const eulerAngles = quat1.toEuler();

139

const rotationMatrix = new Phaser.Math.Matrix4();

140

rotationMatrix.fromQuat(quat1);

141

142

// Rotate vectors

143

const vector = new Phaser.Math.Vector3(1, 0, 0);

144

quat1.transformVector3(vector);

145

}

146

}

147

```

148

149

## Geometric Shapes

150

151

### Basic Shapes

152

Work with fundamental geometric shapes:

153

154

```javascript { .api }

155

class BasicShapesScene extends Phaser.Scene {

156

create() {

157

// Rectangle

158

const rect = new Phaser.Geom.Rectangle(50, 50, 100, 75);

159

160

// Rectangle operations

161

console.log('Area:', Phaser.Geom.Rectangle.Area(rect)); // 7500

162

console.log('Perimeter:', Phaser.Geom.Rectangle.Perimeter(rect)); // 350

163

console.log('Contains point:', Phaser.Geom.Rectangle.Contains(rect, 75, 75)); // true

164

165

// Rectangle manipulation

166

Phaser.Geom.Rectangle.CenterOn(rect, 400, 300); // Center at point

167

Phaser.Geom.Rectangle.Inflate(rect, 20, 10); // Increase size

168

169

// Circle

170

const circle = new Phaser.Geom.Circle(200, 200, 50);

171

172

// Circle operations

173

console.log('Circumference:', Phaser.Geom.Circle.Circumference(circle));

174

console.log('Area:', Phaser.Geom.Circle.Area(circle));

175

176

// Get points on circle

177

const point = Phaser.Geom.Circle.CircumferencePoint(circle, Math.PI/4);

178

const randomPoint = Phaser.Geom.Circle.Random(circle);

179

180

// Line

181

const line = new Phaser.Geom.Line(0, 0, 100, 100);

182

183

// Line operations

184

console.log('Length:', Phaser.Geom.Line.Length(line));

185

console.log('Angle:', Phaser.Geom.Line.Angle(line));

186

const midpoint = Phaser.Geom.Line.GetMidPoint(line);

187

188

// Triangle

189

const triangle = new Phaser.Geom.Triangle(100, 100, 150, 50, 200, 100);

190

191

// Triangle operations

192

console.log('Area:', Phaser.Geom.Triangle.Area(triangle));

193

const centroid = Phaser.Geom.Triangle.Centroid(triangle);

194

const circumcircle = Phaser.Geom.Triangle.CircumCircle(triangle);

195

196

// Polygon

197

const polygon = new Phaser.Geom.Polygon([

198

100, 100, // Point 1

199

150, 50, // Point 2

200

200, 100, // Point 3

201

175, 150, // Point 4

202

125, 150 // Point 5

203

]);

204

205

// Polygon operations

206

console.log('Contains point:', Phaser.Geom.Polygon.Contains(polygon, 150, 100));

207

const bounds = Phaser.Geom.Polygon.GetAABB(polygon);

208

const simplified = Phaser.Geom.Polygon.Simplify(polygon);

209

}

210

}

211

```

212

213

### Advanced Shape Operations

214

Complex geometric operations and transformations:

215

216

```javascript { .api }

217

class AdvancedShapesScene extends Phaser.Scene {

218

create() {

219

// Ellipse

220

const ellipse = new Phaser.Geom.Ellipse(300, 200, 120, 80);

221

222

// Get points on ellipse perimeter

223

const ellipsePoints = Phaser.Geom.Ellipse.GetPoints(ellipse, 32);

224

225

// Point utilities

226

const points = [

227

new Phaser.Geom.Point(100, 100),

228

new Phaser.Geom.Point(200, 150),

229

new Phaser.Geom.Point(300, 120),

230

new Phaser.Geom.Point(150, 200)

231

];

232

233

// Point operations

234

const centroid = Phaser.Geom.Point.GetCentroid(points);

235

const boundingRect = Phaser.Geom.Point.GetRectangleFromPoints(points);

236

237

// Interpolate between points

238

const interpolated = Phaser.Geom.Point.Interpolate(

239

points[0], points[1], 0.5

240

);

241

242

// Complex polygon from points

243

const complexPolygon = new Phaser.Geom.Polygon(points);

244

245

// Triangulate polygon (for rendering)

246

const triangles = Phaser.Geom.Polygon.Earcut(complexPolygon.points);

247

248

// Smooth polygon edges

249

const smoothed = Phaser.Geom.Polygon.Smooth(complexPolygon);

250

251

// Create shapes for rendering

252

this.createShapeVisuals(ellipse, complexPolygon, triangles);

253

}

254

255

createShapeVisuals(ellipse, polygon, triangles) {

256

const graphics = this.add.graphics();

257

258

// Draw ellipse

259

graphics.lineStyle(2, 0xff0000);

260

graphics.strokeEllipse(ellipse.x, ellipse.y, ellipse.width, ellipse.height);

261

262

// Draw polygon

263

graphics.lineStyle(2, 0x00ff00);

264

graphics.beginPath();

265

graphics.moveTo(polygon.points[0].x, polygon.points[0].y);

266

for (let i = 1; i < polygon.points.length; i++) {

267

graphics.lineTo(polygon.points[i].x, polygon.points[i].y);

268

}

269

graphics.closePath();

270

graphics.strokePath();

271

272

// Draw triangulated polygon

273

graphics.fillStyle(0x0000ff, 0.3);

274

for (let i = 0; i < triangles.length; i += 3) {

275

const p1 = polygon.points[triangles[i]];

276

const p2 = polygon.points[triangles[i + 1]];

277

const p3 = polygon.points[triangles[i + 2]];

278

279

graphics.fillTriangle(

280

p1.x, p1.y,

281

p2.x, p2.y,

282

p3.x, p3.y

283

);

284

}

285

}

286

}

287

```

288

289

## Intersection and Collision Testing

290

291

### Shape Intersection

292

Test intersections between various geometric shapes:

293

294

```javascript { .api }

295

class IntersectionScene extends Phaser.Scene {

296

create() {

297

// Create test shapes

298

const rect1 = new Phaser.Geom.Rectangle(100, 100, 100, 80);

299

const rect2 = new Phaser.Geom.Rectangle(150, 120, 100, 80);

300

const circle1 = new Phaser.Geom.Circle(250, 200, 50);

301

const circle2 = new Phaser.Geom.Circle(300, 180, 40);

302

const line = new Phaser.Geom.Line(50, 50, 350, 300);

303

304

// Rectangle vs Rectangle

305

const rectOverlap = Phaser.Geom.Intersects.RectangleToRectangle(rect1, rect2);

306

console.log('Rectangles overlap:', rectOverlap);

307

308

// Get intersection area

309

const intersection = Phaser.Geom.Intersects.GetRectangleIntersection(rect1, rect2);

310

if (intersection) {

311

console.log('Intersection area:', Phaser.Geom.Rectangle.Area(intersection));

312

}

313

314

// Circle vs Circle

315

const circleOverlap = Phaser.Geom.Intersects.CircleToCircle(circle1, circle2);

316

console.log('Circles overlap:', circleOverlap);

317

318

// Circle vs Rectangle

319

const circleRectOverlap = Phaser.Geom.Intersects.CircleToRectangle(circle1, rect1);

320

console.log('Circle and rectangle overlap:', circleRectOverlap);

321

322

// Line intersections

323

const lineCirclePoints = Phaser.Geom.Intersects.GetLineToCircle(line, circle1);

324

console.log('Line-circle intersection points:', lineCirclePoints);

325

326

const lineRectPoints = Phaser.Geom.Intersects.GetLineToRectangle(line, rect1);

327

console.log('Line-rectangle intersection points:', lineRectPoints);

328

329

// Point in shape testing

330

const pointInRect = Phaser.Geom.Rectangle.Contains(rect1, 150, 140);

331

const pointInCircle = Phaser.Geom.Circle.Contains(circle1, 260, 210);

332

333

// Triangle intersections

334

const triangle = new Phaser.Geom.Triangle(200, 50, 250, 25, 300, 75);

335

const triangleCircle = Phaser.Geom.Intersects.TriangleToCircle(triangle, circle1);

336

const triangleRect = Phaser.Geom.Intersects.TriangleToTriangle(triangle, triangle);

337

338

// Visualize intersections

339

this.visualizeIntersections(rect1, rect2, circle1, circle2, line, triangle);

340

}

341

342

visualizeIntersections(rect1, rect2, circle1, circle2, line, triangle) {

343

const graphics = this.add.graphics();

344

345

// Draw rectangles

346

graphics.lineStyle(2, 0xff0000);

347

graphics.strokeRectShape(rect1);

348

graphics.strokeRectShape(rect2);

349

350

// Draw circles

351

graphics.lineStyle(2, 0x00ff00);

352

graphics.strokeCircleShape(circle1);

353

graphics.strokeCircleShape(circle2);

354

355

// Draw line

356

graphics.lineStyle(2, 0x0000ff);

357

graphics.strokeLineShape(line);

358

359

// Draw triangle

360

graphics.lineStyle(2, 0xff00ff);

361

graphics.strokeTriangleShape(triangle);

362

363

// Highlight intersections

364

if (Phaser.Geom.Intersects.RectangleToRectangle(rect1, rect2)) {

365

const intersection = Phaser.Geom.Intersects.GetRectangleIntersection(rect1, rect2);

366

graphics.fillStyle(0xffff00, 0.5);

367

graphics.fillRectShape(intersection);

368

}

369

}

370

}

371

```

372

373

### Advanced Collision Detection

374

Implement more complex collision scenarios:

375

376

```javascript { .api }

377

class AdvancedCollisionScene extends Phaser.Scene {

378

create() {

379

// Moving objects for continuous collision detection

380

this.movingCircle = {

381

current: new Phaser.Geom.Circle(100, 100, 20),

382

previous: new Phaser.Geom.Circle(90, 90, 20),

383

velocity: new Phaser.Math.Vector2(5, 3)

384

};

385

386

this.staticRect = new Phaser.Geom.Rectangle(200, 150, 100, 80);

387

388

// Swept collision detection

389

this.checkSweptCollision();

390

391

// Polygon collision detection

392

this.polygon1 = new Phaser.Geom.Polygon([

393

100, 300, 150, 280, 200, 320, 150, 350

394

]);

395

396

this.polygon2 = new Phaser.Geom.Polygon([

397

180, 290, 230, 270, 280, 310, 230, 340

398

]);

399

400

const polyCollision = this.checkPolygonCollision(this.polygon1, this.polygon2);

401

console.log('Polygon collision:', polyCollision);

402

403

// Raycast collision detection

404

this.performRaycast();

405

}

406

407

checkSweptCollision() {

408

// Check if moving circle will collide with rectangle

409

const futurePosition = new Phaser.Geom.Circle(

410

this.movingCircle.current.x + this.movingCircle.velocity.x,

411

this.movingCircle.current.y + this.movingCircle.velocity.y,

412

this.movingCircle.current.radius

413

);

414

415

if (Phaser.Geom.Intersects.CircleToRectangle(futurePosition, this.staticRect)) {

416

console.log('Collision predicted!');

417

this.resolveCollision();

418

}

419

}

420

421

resolveCollision() {

422

// Simple collision response - bounce off rectangle

423

const rectCenter = Phaser.Geom.Rectangle.GetCenter(this.staticRect);

424

const circleCenter = new Phaser.Geom.Point(

425

this.movingCircle.current.x,

426

this.movingCircle.current.y

427

);

428

429

// Calculate collision normal

430

const normal = new Phaser.Math.Vector2(

431

circleCenter.x - rectCenter.x,

432

circleCenter.y - rectCenter.y

433

).normalize();

434

435

// Reflect velocity

436

const dot = this.movingCircle.velocity.dot(normal);

437

this.movingCircle.velocity.subtract(normal.clone().scale(2 * dot));

438

}

439

440

checkPolygonCollision(poly1, poly2) {

441

// Separating Axis Theorem (SAT) implementation

442

const getAxes = (polygon) => {

443

const axes = [];

444

for (let i = 0; i < polygon.points.length; i++) {

445

const p1 = polygon.points[i];

446

const p2 = polygon.points[(i + 1) % polygon.points.length];

447

const edge = new Phaser.Math.Vector2(p2.x - p1.x, p2.y - p1.y);

448

axes.push(new Phaser.Math.Vector2(-edge.y, edge.x).normalize());

449

}

450

return axes;

451

};

452

453

const project = (polygon, axis) => {

454

let min = Infinity;

455

let max = -Infinity;

456

457

for (const point of polygon.points) {

458

const dot = axis.dot(new Phaser.Math.Vector2(point.x, point.y));

459

min = Math.min(min, dot);

460

max = Math.max(max, dot);

461

}

462

463

return { min, max };

464

};

465

466

const axes = [...getAxes(poly1), ...getAxes(poly2)];

467

468

for (const axis of axes) {

469

const proj1 = project(poly1, axis);

470

const proj2 = project(poly2, axis);

471

472

if (proj1.max < proj2.min || proj2.max < proj1.min) {

473

return false; // Separating axis found

474

}

475

}

476

477

return true; // No separating axis found, collision detected

478

}

479

480

performRaycast() {

481

// Ray from point to target

482

const rayStart = new Phaser.Math.Vector2(50, 50);

483

const rayEnd = new Phaser.Math.Vector2(350, 350);

484

const rayDirection = rayEnd.clone().subtract(rayStart).normalize();

485

486

// Test against various shapes

487

const obstacles = [

488

this.staticRect,

489

this.movingCircle.current,

490

this.polygon1

491

];

492

493

let closestHit = null;

494

let closestDistance = Infinity;

495

496

obstacles.forEach(obstacle => {

497

const hit = this.raycastToShape(rayStart, rayDirection, obstacle);

498

if (hit && hit.distance < closestDistance) {

499

closestDistance = hit.distance;

500

closestHit = hit;

501

}

502

});

503

504

if (closestHit) {

505

console.log('Ray hit at:', closestHit.point);

506

}

507

}

508

509

raycastToShape(rayStart, rayDirection, shape) {

510

if (shape instanceof Phaser.Geom.Rectangle) {

511

return this.raycastToRectangle(rayStart, rayDirection, shape);

512

} else if (shape instanceof Phaser.Geom.Circle) {

513

return this.raycastToCircle(rayStart, rayDirection, shape);

514

}

515

return null;

516

}

517

518

raycastToRectangle(rayStart, rayDirection, rect) {

519

// Ray-rectangle intersection using slab method

520

const invDir = new Phaser.Math.Vector2(1 / rayDirection.x, 1 / rayDirection.y);

521

522

const t1 = (rect.x - rayStart.x) * invDir.x;

523

const t2 = (rect.x + rect.width - rayStart.x) * invDir.x;

524

const t3 = (rect.y - rayStart.y) * invDir.y;

525

const t4 = (rect.y + rect.height - rayStart.y) * invDir.y;

526

527

const tmin = Math.max(Math.min(t1, t2), Math.min(t3, t4));

528

const tmax = Math.min(Math.max(t1, t2), Math.max(t3, t4));

529

530

if (tmax < 0 || tmin > tmax) {

531

return null; // No intersection

532

}

533

534

const t = tmin < 0 ? tmax : tmin;

535

const hitPoint = rayStart.clone().add(rayDirection.clone().scale(t));

536

537

return {

538

point: hitPoint,

539

distance: t,

540

normal: this.getRectangleNormal(hitPoint, rect)

541

};

542

}

543

544

raycastToCircle(rayStart, rayDirection, circle) {

545

const toCircle = new Phaser.Math.Vector2(

546

circle.x - rayStart.x,

547

circle.y - rayStart.y

548

);

549

550

const a = rayDirection.dot(rayDirection);

551

const b = -2 * rayDirection.dot(toCircle);

552

const c = toCircle.dot(toCircle) - circle.radius * circle.radius;

553

554

const discriminant = b * b - 4 * a * c;

555

556

if (discriminant < 0) {

557

return null; // No intersection

558

}

559

560

const t = (-b - Math.sqrt(discriminant)) / (2 * a);

561

562

if (t < 0) {

563

return null; // Behind ray start

564

}

565

566

const hitPoint = rayStart.clone().add(rayDirection.clone().scale(t));

567

const normal = hitPoint.clone().subtract(new Phaser.Math.Vector2(circle.x, circle.y)).normalize();

568

569

return {

570

point: hitPoint,

571

distance: t,

572

normal: normal

573

};

574

}

575

576

getRectangleNormal(point, rect) {

577

const center = Phaser.Geom.Rectangle.GetCenter(rect);

578

const dx = point.x - center.x;

579

const dy = point.y - center.y;

580

581

if (Math.abs(dx) > Math.abs(dy)) {

582

return new Phaser.Math.Vector2(dx > 0 ? 1 : -1, 0);

583

} else {

584

return new Phaser.Math.Vector2(0, dy > 0 ? 1 : -1);

585

}

586

}

587

}

588

```

589

590

## Interpolation and Easing

591

592

### Interpolation Functions

593

Smooth transitions between values:

594

595

```javascript { .api }

596

class InterpolationScene extends Phaser.Scene {

597

create() {

598

// Linear interpolation

599

const lerp1 = Phaser.Math.Linear(0, 100, 0.5); // 50

600

const lerp2 = Phaser.Math.LinearXY(

601

new Phaser.Math.Vector2(0, 0),

602

new Phaser.Math.Vector2(100, 100),

603

0.3

604

); // (30, 30)

605

606

// Smooth step interpolation

607

const smooth = Phaser.Math.SmoothStep(0.2, 0, 1); // Smooth curve

608

const smoother = Phaser.Math.SmootherStep(0.7, 0, 1); // Even smoother

609

610

// Bezier interpolation

611

const bezier = Phaser.Math.Interpolation.Bezier([0, 25, 75, 100], 0.5);

612

613

// Catmull-Rom spline

614

const catmull = Phaser.Math.Interpolation.CatmullRom([0, 20, 80, 100], 0.4);

615

616

// Cubic Bezier curve

617

const cubic = Phaser.Math.Interpolation.CubicBezier(0.3, 0, 0.2, 1, 0.8);

618

619

// Demonstrate interpolation with moving object

620

this.demonstrateInterpolation();

621

}

622

623

demonstrateInterpolation() {

624

const sprite = this.add.circle(100, 300, 10, 0xff0000);

625

const startX = 100;

626

const endX = 700;

627

let progress = 0;

628

629

// Create path points for complex interpolation

630

const pathPoints = [

631

{ x: 100, y: 300 },

632

{ x: 200, y: 150 },

633

{ x: 400, y: 450 },

634

{ x: 600, y: 200 },

635

{ x: 700, y: 300 }

636

];

637

638

this.tweens.add({

639

targets: { progress: 0 },

640

progress: 1,

641

duration: 3000,

642

repeat: -1,

643

yoyo: true,

644

onUpdate: (tween) => {

645

const t = tween.getValue();

646

647

// Linear interpolation for comparison

648

const linearX = Phaser.Math.Linear(startX, endX, t);

649

650

// Smooth step for eased movement

651

const smoothT = Phaser.Math.SmoothStep(t, 0, 1);

652

const smoothX = Phaser.Math.Linear(startX, endX, smoothT);

653

654

// Catmull-Rom spline through path points

655

const splineIndex = t * (pathPoints.length - 1);

656

const segmentIndex = Math.floor(splineIndex);

657

const segmentT = splineIndex - segmentIndex;

658

659

if (segmentIndex < pathPoints.length - 1) {

660

const p0 = pathPoints[Math.max(0, segmentIndex - 1)];

661

const p1 = pathPoints[segmentIndex];

662

const p2 = pathPoints[segmentIndex + 1];

663

const p3 = pathPoints[Math.min(pathPoints.length - 1, segmentIndex + 2)];

664

665

const splineX = this.catmullRomInterpolate(p0.x, p1.x, p2.x, p3.x, segmentT);

666

const splineY = this.catmullRomInterpolate(p0.y, p1.y, p2.y, p3.y, segmentT);

667

668

sprite.setPosition(splineX, splineY);

669

}

670

}

671

});

672

}

673

674

catmullRomInterpolate(p0, p1, p2, p3, t) {

675

const t2 = t * t;

676

const t3 = t2 * t;

677

678

return 0.5 * (

679

(2 * p1) +

680

(-p0 + p2) * t +

681

(2 * p0 - 5 * p1 + 4 * p2 - p3) * t2 +

682

(-p0 + 3 * p1 - 3 * p2 + p3) * t3

683

);

684

}

685

}

686

```

687

688

### Easing Functions

689

Comprehensive easing function library:

690

691

```javascript { .api }

692

class EasingScene extends Phaser.Scene {

693

create() {

694

// Create sprites to demonstrate different easing functions

695

const easingFunctions = [

696

{ name: 'Linear', func: Phaser.Math.Easing.Linear },

697

{ name: 'Quad.In', func: Phaser.Math.Easing.Quadratic.In },

698

{ name: 'Quad.Out', func: Phaser.Math.Easing.Quadratic.Out },

699

{ name: 'Quad.InOut', func: Phaser.Math.Easing.Quadratic.InOut },

700

{ name: 'Cubic.In', func: Phaser.Math.Easing.Cubic.In },

701

{ name: 'Cubic.Out', func: Phaser.Math.Easing.Cubic.Out },

702

{ name: 'Bounce.Out', func: Phaser.Math.Easing.Bounce.Out },

703

{ name: 'Elastic.Out', func: Phaser.Math.Easing.Elastic.Out },

704

{ name: 'Back.Out', func: Phaser.Math.Easing.Back.Out }

705

];

706

707

easingFunctions.forEach((easing, index) => {

708

const y = 50 + index * 60;

709

const sprite = this.add.circle(50, y, 8, 0xff0000);

710

const label = this.add.text(10, y - 20, easing.name, {

711

fontSize: '12px',

712

fill: '#ffffff'

713

});

714

715

// Animate with specific easing function

716

this.tweens.add({

717

targets: sprite,

718

x: 750,

719

duration: 2000,

720

ease: easing.func,

721

yoyo: true,

722

repeat: -1,

723

delay: index * 100

724

});

725

});

726

727

// Custom easing function

728

const customEasing = (t) => {

729

// Bounce with custom parameters

730

return Math.abs(Math.sin(t * Math.PI * 6)) * (1 - t);

731

};

732

733

const customSprite = this.add.circle(50, 600, 10, 0x00ff00);

734

this.tweens.add({

735

targets: customSprite,

736

x: 750,

737

duration: 3000,

738

ease: customEasing,

739

repeat: -1,

740

yoyo: true

741

});

742

743

this.add.text(10, 580, 'Custom Easing', {

744

fontSize: '12px',

745

fill: '#00ff00'

746

});

747

}

748

}

749

```

750

751

## Random Number Generation

752

753

### Random Data Generator

754

Phaser's seedable random number generator:

755

756

```javascript { .api }

757

class RandomScene extends Phaser.Scene {

758

create() {

759

// Use global random generator

760

const random1 = Phaser.Math.RND.between(1, 10);

761

const random2 = Phaser.Math.RND.frac(); // 0-1

762

const random3 = Phaser.Math.RND.pick(['a', 'b', 'c']); // Pick from array

763

764

// Create seeded generator for reproducible randomness

765

const seededRNG = new Phaser.Math.RandomDataGenerator(['seed1', 'seed2']);

766

767

// Generate reproducible random numbers

768

console.log('Seeded random:', seededRNG.between(1, 100));

769

console.log('Seeded fraction:', seededRNG.frac());

770

console.log('Seeded pick:', seededRNG.pick(['red', 'green', 'blue']));

771

772

// Advanced random operations

773

const weightedArray = [

774

{ value: 'common', weight: 0.7 },

775

{ value: 'uncommon', weight: 0.25 },

776

{ value: 'rare', weight: 0.05 }

777

];

778

779

const weightedResult = seededRNG.weightedPick(weightedArray);

780

console.log('Weighted pick:', weightedResult);

781

782

// Shuffle array

783

const deck = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];

784

seededRNG.shuffle(deck);

785

console.log('Shuffled deck:', deck);

786

787

// Random vectors

788

const randomVector2 = Phaser.Math.RandomXY(new Phaser.Math.Vector2());

789

const randomVector3 = Phaser.Math.RandomXYZ(new Phaser.Math.Vector3());

790

791

// Random rotation

792

const angle = seededRNG.rotation(); // Random angle 0 to 2PI

793

794

// Generate random colors

795

this.generateRandomVisuals(seededRNG);

796

}

797

798

generateRandomVisuals(rng) {

799

// Create random colored circles

800

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

801

const x = rng.between(50, 750);

802

const y = rng.between(50, 550);

803

const radius = rng.between(10, 30);

804

const color = rng.integer(0x000000, 0xffffff);

805

806

const circle = this.add.circle(x, y, radius, color);

807

808

// Random animation

809

this.tweens.add({

810

targets: circle,

811

scaleX: rng.realInRange(0.5, 2),

812

scaleY: rng.realInRange(0.5, 2),

813

rotation: rng.rotation(),

814

duration: rng.between(1000, 3000),

815

yoyo: true,

816

repeat: -1,

817

delay: rng.between(0, 1000)

818

});

819

}

820

821

// Procedural generation example

822

this.generateTerrain(rng);

823

}

824

825

generateTerrain(rng) {

826

const graphics = this.add.graphics();

827

graphics.fillStyle(0x8B4513); // Brown

828

829

let height = 400;

830

const roughness = 50;

831

832

for (let x = 0; x < 800; x += 5) {

833

// Random walk terrain generation

834

height += rng.realInRange(-roughness, roughness);

835

height = Phaser.Math.Clamp(height, 300, 500);

836

837

graphics.fillRect(x, height, 5, 600 - height);

838

}

839

}

840

}

841

```

842

843

This comprehensive mathematical and geometric system provides all the tools needed for complex game mechanics, procedural generation, collision detection, and smooth animations.