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.