pac-man-phaser 1.0.9 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/index.d.ts +4 -2
  2. package/dist/index.js +1230 -3
  3. package/package.json +4 -5
  4. package/dist/assets/spritesheet.webp +0 -0
  5. package/dist/game/_scenes/game-over-scene.d.ts +0 -9
  6. package/dist/game/_scenes/game-over-scene.d.ts.map +0 -1
  7. package/dist/game/_scenes/game-over-scene.js +0 -59
  8. package/dist/game/_scenes/game-over-scene.js.map +0 -1
  9. package/dist/game/_scenes/pac-man-scene.d.ts +0 -14
  10. package/dist/game/_scenes/pac-man-scene.d.ts.map +0 -1
  11. package/dist/game/_scenes/pac-man-scene.js +0 -155
  12. package/dist/game/_scenes/pac-man-scene.js.map +0 -1
  13. package/dist/game/_scenes/pause-scene.d.ts +0 -5
  14. package/dist/game/_scenes/pause-scene.d.ts.map +0 -1
  15. package/dist/game/_scenes/pause-scene.js +0 -28
  16. package/dist/game/_scenes/pause-scene.js.map +0 -1
  17. package/dist/game/constants.d.ts +0 -19
  18. package/dist/game/constants.d.ts.map +0 -1
  19. package/dist/game/constants.js +0 -27
  20. package/dist/game/constants.js.map +0 -1
  21. package/dist/game/sprites/abstracts/action-item.d.ts +0 -5
  22. package/dist/game/sprites/abstracts/action-item.d.ts.map +0 -1
  23. package/dist/game/sprites/abstracts/action-item.js +0 -4
  24. package/dist/game/sprites/abstracts/action-item.js.map +0 -1
  25. package/dist/game/sprites/abstracts/item.d.ts +0 -6
  26. package/dist/game/sprites/abstracts/item.d.ts.map +0 -1
  27. package/dist/game/sprites/abstracts/item.js +0 -12
  28. package/dist/game/sprites/abstracts/item.js.map +0 -1
  29. package/dist/game/sprites/characters/character.d.ts +0 -20
  30. package/dist/game/sprites/characters/character.d.ts.map +0 -1
  31. package/dist/game/sprites/characters/character.js +0 -125
  32. package/dist/game/sprites/characters/character.js.map +0 -1
  33. package/dist/game/sprites/ghosts/blinky.d.ts +0 -11
  34. package/dist/game/sprites/ghosts/blinky.d.ts.map +0 -1
  35. package/dist/game/sprites/ghosts/blinky.js +0 -25
  36. package/dist/game/sprites/ghosts/blinky.js.map +0 -1
  37. package/dist/game/sprites/ghosts/clyde.d.ts +0 -10
  38. package/dist/game/sprites/ghosts/clyde.d.ts.map +0 -1
  39. package/dist/game/sprites/ghosts/clyde.js +0 -31
  40. package/dist/game/sprites/ghosts/clyde.js.map +0 -1
  41. package/dist/game/sprites/ghosts/ghost.d.ts +0 -48
  42. package/dist/game/sprites/ghosts/ghost.d.ts.map +0 -1
  43. package/dist/game/sprites/ghosts/ghost.js +0 -323
  44. package/dist/game/sprites/ghosts/ghost.js.map +0 -1
  45. package/dist/game/sprites/ghosts/inky.d.ts +0 -11
  46. package/dist/game/sprites/ghosts/inky.d.ts.map +0 -1
  47. package/dist/game/sprites/ghosts/inky.js +0 -50
  48. package/dist/game/sprites/ghosts/inky.js.map +0 -1
  49. package/dist/game/sprites/ghosts/pinky.d.ts +0 -10
  50. package/dist/game/sprites/ghosts/pinky.d.ts.map +0 -1
  51. package/dist/game/sprites/ghosts/pinky.js +0 -42
  52. package/dist/game/sprites/ghosts/pinky.js.map +0 -1
  53. package/dist/game/sprites/pac-man.d.ts +0 -17
  54. package/dist/game/sprites/pac-man.d.ts.map +0 -1
  55. package/dist/game/sprites/pac-man.js +0 -264
  56. package/dist/game/sprites/pac-man.js.map +0 -1
  57. package/dist/game/sprites/pellet.d.ts +0 -7
  58. package/dist/game/sprites/pellet.d.ts.map +0 -1
  59. package/dist/game/sprites/pellet.js +0 -15
  60. package/dist/game/sprites/pellet.js.map +0 -1
  61. package/dist/game/sprites/super-pellet.d.ts +0 -13
  62. package/dist/game/sprites/super-pellet.d.ts.map +0 -1
  63. package/dist/game/sprites/super-pellet.js +0 -67
  64. package/dist/game/sprites/super-pellet.js.map +0 -1
  65. package/dist/game/sprites/wall.d.ts +0 -5
  66. package/dist/game/sprites/wall.d.ts.map +0 -1
  67. package/dist/game/sprites/wall.js +0 -16
  68. package/dist/game/sprites/wall.js.map +0 -1
  69. package/dist/game/ui/score-display.d.ts +0 -7
  70. package/dist/game/ui/score-display.d.ts.map +0 -1
  71. package/dist/game/ui/score-display.js +0 -19
  72. package/dist/game/ui/score-display.js.map +0 -1
  73. package/dist/index.d.ts.map +0 -1
  74. package/dist/index.js.map +0 -1
  75. package/dist/pac-man.d.ts +0 -2
  76. package/dist/pac-man.d.ts.map +0 -1
  77. package/dist/pac-man.js +0 -19
  78. package/dist/pac-man.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,3 +1,1230 @@
1
- import { PacMan } from './pac-man';
2
- export { PacMan };
3
- //# sourceMappingURL=index.js.map
1
+ // src/pac-man.tsx
2
+ import { useEffect, useRef } from "react";
3
+
4
+ // src/game/_scenes/pac-man-scene.ts
5
+ import { Scene } from "phaser";
6
+
7
+ // src/game/sprites/wall.ts
8
+ var Wall = class extends Phaser.Physics.Arcade.Sprite {
9
+ constructor(scene, x, y) {
10
+ super(scene, x * 32, y * 32, "wall");
11
+ this.setOrigin(0, 0);
12
+ scene.add.existing(this);
13
+ }
14
+ static addWallGraphics(scene) {
15
+ const graphics = scene.add.graphics();
16
+ graphics.fillStyle(3355443, 1);
17
+ graphics.fillRect(0, 0, 32, 32);
18
+ graphics.generateTexture("wall", 32, 32);
19
+ graphics.destroy();
20
+ }
21
+ };
22
+
23
+ // src/game/_scenes/pac-man-scene.ts
24
+ import { generateMap } from "pac-man-map-generator";
25
+
26
+ // src/game/sprites/abstracts/item.ts
27
+ var Item = class extends Phaser.Physics.Arcade.Sprite {
28
+ coords;
29
+ constructor(scene, x, y, sizeOffset, texture) {
30
+ const adjustedX = x * 32 + sizeOffset;
31
+ const adjustedY = y * 32 + sizeOffset;
32
+ super(scene, adjustedX, adjustedY, texture);
33
+ this.coords = { x, y };
34
+ this.setOrigin(0, 0);
35
+ scene.add.existing(this);
36
+ }
37
+ };
38
+
39
+ // src/game/sprites/pellet.ts
40
+ var Pellet = class extends Item {
41
+ points = 10;
42
+ constructor(scene, x, y) {
43
+ super(scene, x, y, 12, "pellet");
44
+ }
45
+ static addPelletGraphics(scene) {
46
+ const graphics = scene.add.graphics();
47
+ graphics.fillStyle(16777215, 1);
48
+ graphics.fillCircle(4, 4, 4);
49
+ graphics.generateTexture("pellet", 8, 8);
50
+ graphics.destroy();
51
+ }
52
+ };
53
+
54
+ // src/game/constants.ts
55
+ var directions = {
56
+ LEFT: 0,
57
+ RIGHT: 1,
58
+ UP: 2,
59
+ DOWN: 3
60
+ };
61
+ var directionsArray = [
62
+ { x: 0, y: -1, dir: directions.UP },
63
+ { x: 0, y: 1, dir: directions.DOWN },
64
+ { x: -1, y: 0, dir: directions.LEFT },
65
+ { x: 1, y: 0, dir: directions.RIGHT }
66
+ ];
67
+ var BASE_SPEED = 120;
68
+ var PAC_MAN_SPEED = BASE_SPEED;
69
+ var PAC_MAN_SPEED_SCATTER = BASE_SPEED * 1.25;
70
+ var PAC_MAN_SPEED_EATING = BASE_SPEED * 0.9;
71
+ var PAC_MAN_SPEED_TUNNEL = BASE_SPEED * 0.5;
72
+ var GHOST_SPEED = BASE_SPEED * 0.9375;
73
+ var GHOST_SPEED_FRIGHTENED = BASE_SPEED * 0.625;
74
+
75
+ // src/game/sprites/characters/character.ts
76
+ var Character = class extends Phaser.Physics.Arcade.Sprite {
77
+ position = { x: 0, y: 0 };
78
+ gridPosition = { x: 0, y: 0 };
79
+ direction = -1;
80
+ gameMap;
81
+ textureMap;
82
+ constructor(scene, gameMap, x, y, textureMap, texture, startingFrame) {
83
+ super(scene, x, y, texture, startingFrame);
84
+ this.gameMap = gameMap;
85
+ this.position = { x, y };
86
+ this.gridPosition = { x: Math.floor(x / 32), y: Math.floor(y / 32) };
87
+ this.textureMap = textureMap;
88
+ scene.add.existing(this);
89
+ scene.physics.add.existing(this);
90
+ this.setCollideWorldBounds(false);
91
+ }
92
+ update() {
93
+ const cell = {
94
+ x: Math.floor(this.x / 32),
95
+ y: Math.floor(this.y / 32)
96
+ };
97
+ const center = {
98
+ x: cell.x * 32 + 16,
99
+ y: cell.y * 32 + 16
100
+ };
101
+ const tolerance = 4;
102
+ const inCenterX = Math.abs(this.x - center.x) < tolerance;
103
+ const inCenterY = Math.abs(this.y - center.y) < tolerance;
104
+ if ((this.direction === directions.RIGHT || this.direction === directions.LEFT) && !inCenterY) {
105
+ this.setPosition(this.x, this.position.y);
106
+ }
107
+ if ((this.direction === directions.UP || this.direction === directions.DOWN) && !inCenterX) {
108
+ this.setPosition(this.position.x, this.y);
109
+ }
110
+ if (inCenterX && inCenterY) {
111
+ this.position = center;
112
+ this.gridPosition = cell;
113
+ if (cell.x < -1) {
114
+ this.setPosition(32 * 28, this.y);
115
+ } else if (cell.x > 27) {
116
+ this.setPosition(-32, this.y);
117
+ }
118
+ if (!this.gameMap[cell.y]?.[cell.x] || this.gameMap[cell.y]?.[cell.x]?.type === "teleporter") {
119
+ return;
120
+ }
121
+ this.onCenter(cell);
122
+ }
123
+ }
124
+ canMove(cell, direction) {
125
+ const targetCell = { x: cell.x, y: cell.y };
126
+ switch (direction) {
127
+ case directions.LEFT:
128
+ targetCell.x -= 1;
129
+ break;
130
+ case directions.RIGHT:
131
+ targetCell.x += 1;
132
+ break;
133
+ case directions.UP:
134
+ targetCell.y -= 1;
135
+ break;
136
+ case directions.DOWN:
137
+ targetCell.y += 1;
138
+ break;
139
+ default:
140
+ return false;
141
+ }
142
+ if (targetCell.x < 0 || targetCell.x > 27) {
143
+ return true;
144
+ }
145
+ const type = this.gameMap[targetCell.y]?.[targetCell.x]?.type;
146
+ return type === "empty" || type === "teleporter";
147
+ }
148
+ changeDirection(direction) {
149
+ this.direction = direction;
150
+ switch (direction) {
151
+ case directions.LEFT:
152
+ this.setVelocity(-this.speed, 0);
153
+ break;
154
+ case directions.RIGHT:
155
+ this.setVelocity(this.speed, 0);
156
+ break;
157
+ case directions.UP:
158
+ this.setVelocity(0, -this.speed);
159
+ break;
160
+ case directions.DOWN:
161
+ this.setVelocity(0, this.speed);
162
+ break;
163
+ }
164
+ const tex = this.textureMap[direction];
165
+ if (tex) {
166
+ this.anims.stop();
167
+ if (tex.startsWith("frame:")) {
168
+ this.setFrame(tex.replace("frame:", ""));
169
+ } else {
170
+ this.anims.play(tex);
171
+ }
172
+ }
173
+ }
174
+ getOppositeDirection(direction) {
175
+ switch (direction) {
176
+ case directions.LEFT:
177
+ return directions.RIGHT;
178
+ case directions.RIGHT:
179
+ return directions.LEFT;
180
+ case directions.UP:
181
+ return directions.DOWN;
182
+ case directions.DOWN:
183
+ return directions.UP;
184
+ default:
185
+ return -1;
186
+ }
187
+ }
188
+ };
189
+
190
+ // src/game/sprites/pac-man.ts
191
+ var Pacman = class extends Character {
192
+ nextDir = -1;
193
+ eatCoords = null;
194
+ speed = PAC_MAN_SPEED;
195
+ hasMoved = false;
196
+ constructor(scene, gameMap) {
197
+ const x = 14 * 32;
198
+ const y = 17 * 32 + 16;
199
+ const texMap = {
200
+ [directions.LEFT]: "pacman-left",
201
+ [directions.RIGHT]: "pacman-right",
202
+ [directions.UP]: "pacman-up",
203
+ [directions.DOWN]: "pacman-down"
204
+ };
205
+ super(scene, gameMap, x, y, texMap, "spritesheet", "pacman-whole");
206
+ if (scene.input.keyboard) {
207
+ this.setEventListeners(scene.input.keyboard);
208
+ }
209
+ }
210
+ handleDeath() {
211
+ this.setVelocity(0, 0);
212
+ this.anims.play("pacman-death", false);
213
+ const animDuration = 11 / 8 * 1e3;
214
+ this.scene.time.delayedCall(animDuration, () => {
215
+ this.scene.events.emit("game-over");
216
+ });
217
+ }
218
+ update() {
219
+ if (this.nextDir !== -1 && !this.hasMoved) {
220
+ this.changeDirection(this.nextDir);
221
+ this.nextDir = -1;
222
+ this.hasMoved = true;
223
+ }
224
+ super.update();
225
+ }
226
+ eatPellet(x, y) {
227
+ this.eatCoords = `${x},${y}`;
228
+ }
229
+ onCenter(cell) {
230
+ const key = `${cell.x},${cell.y}`;
231
+ if (this.eatCoords === key) {
232
+ this.speed = PAC_MAN_SPEED_EATING;
233
+ this.changeDirection(this.direction);
234
+ } else if (this.gameMap[cell.y]?.[cell.x]?.type === "teleporter") {
235
+ this.speed = PAC_MAN_SPEED_TUNNEL;
236
+ this.changeDirection(this.direction);
237
+ } else {
238
+ this.eatCoords = null;
239
+ this.speed = PAC_MAN_SPEED;
240
+ this.changeDirection(this.direction);
241
+ }
242
+ if (this.nextDir !== -1 && this.canMove(cell, this.nextDir)) {
243
+ this.changeDirection(this.nextDir);
244
+ this.nextDir = -1;
245
+ } else if (!this.canMove(cell, this.direction)) {
246
+ this.setVelocity(0, 0);
247
+ this.anims.stop();
248
+ }
249
+ }
250
+ setEventListeners(input) {
251
+ const left = () => {
252
+ this.nextDir = directions.LEFT;
253
+ };
254
+ const right = () => {
255
+ this.nextDir = directions.RIGHT;
256
+ };
257
+ const up = () => {
258
+ this.nextDir = directions.UP;
259
+ };
260
+ const down = () => {
261
+ this.nextDir = directions.DOWN;
262
+ };
263
+ input.on("keydown-LEFT", left);
264
+ input.on("keydown-A", left);
265
+ input.on("keydown-RIGHT", right);
266
+ input.on("keydown-D", right);
267
+ input.on("keydown-UP", up);
268
+ input.on("keydown-W", up);
269
+ input.on("keydown-DOWN", down);
270
+ input.on("keydown-S", down);
271
+ }
272
+ static loadTextures(textures) {
273
+ const tex = textures.get("spritesheet");
274
+ const pacManSprites = [
275
+ {
276
+ key: "pacman-left-small",
277
+ xPos: 0,
278
+ yPos: 0
279
+ },
280
+ {
281
+ key: "pacman-left-large",
282
+ xPos: 0,
283
+ yPos: 2
284
+ },
285
+ {
286
+ key: "pacman-right-small",
287
+ xPos: 2,
288
+ yPos: 0
289
+ },
290
+ {
291
+ key: "pacman-right-large",
292
+ xPos: 2,
293
+ yPos: 2
294
+ },
295
+ {
296
+ key: "pacman-down-small",
297
+ xPos: 4,
298
+ yPos: 0
299
+ },
300
+ {
301
+ key: "pacman-down-large",
302
+ xPos: 4,
303
+ yPos: 2
304
+ },
305
+ {
306
+ key: "pacman-up-small",
307
+ xPos: 6,
308
+ yPos: 0
309
+ },
310
+ {
311
+ key: "pacman-up-large",
312
+ xPos: 6,
313
+ yPos: 2
314
+ },
315
+ {
316
+ key: "pacman-whole",
317
+ xPos: 8,
318
+ yPos: 0
319
+ },
320
+ {
321
+ key: "pacman-dead-1",
322
+ xPos: 0,
323
+ yPos: 12
324
+ },
325
+ {
326
+ key: "pacman-dead-2",
327
+ xPos: 2,
328
+ yPos: 12
329
+ },
330
+ {
331
+ key: "pacman-dead-3",
332
+ xPos: 4,
333
+ yPos: 12
334
+ },
335
+ {
336
+ key: "pacman-dead-4",
337
+ xPos: 6,
338
+ yPos: 12
339
+ },
340
+ {
341
+ key: "pacman-dead-5",
342
+ xPos: 8,
343
+ yPos: 12
344
+ },
345
+ {
346
+ key: "pacman-dead-6",
347
+ xPos: 10,
348
+ yPos: 12
349
+ },
350
+ {
351
+ key: "pacman-dead-7",
352
+ xPos: 12,
353
+ yPos: 12
354
+ },
355
+ {
356
+ key: "pacman-dead-8",
357
+ xPos: 14,
358
+ yPos: 12
359
+ },
360
+ {
361
+ key: "pacman-dead-9",
362
+ xPos: 16,
363
+ yPos: 12
364
+ },
365
+ {
366
+ key: "pacman-dead-10",
367
+ xPos: 18,
368
+ yPos: 12
369
+ },
370
+ {
371
+ key: "pacman-dead-11",
372
+ xPos: 20,
373
+ yPos: 12
374
+ }
375
+ ];
376
+ for (let i = 0; i < pacManSprites.length; i++) {
377
+ const { key, xPos, yPos } = pacManSprites[i];
378
+ tex.add(key, 0, xPos * 16, yPos * 16, 32, 32);
379
+ }
380
+ }
381
+ static loadAnimations(anims) {
382
+ anims.create({
383
+ key: "pacman-left",
384
+ frames: [
385
+ { key: "spritesheet", frame: "pacman-left-small" },
386
+ { key: "spritesheet", frame: "pacman-left-large" },
387
+ { key: "spritesheet", frame: "pacman-left-small" },
388
+ { key: "spritesheet", frame: "pacman-whole" }
389
+ ],
390
+ repeat: -1,
391
+ frameRate: 16
392
+ });
393
+ anims.create({
394
+ key: "pacman-right",
395
+ frames: [
396
+ { key: "spritesheet", frame: "pacman-right-small" },
397
+ { key: "spritesheet", frame: "pacman-right-large" },
398
+ { key: "spritesheet", frame: "pacman-right-small" },
399
+ { key: "spritesheet", frame: "pacman-whole" }
400
+ ],
401
+ repeat: -1,
402
+ frameRate: 16
403
+ });
404
+ anims.create({
405
+ key: "pacman-down",
406
+ frames: [
407
+ { key: "spritesheet", frame: "pacman-down-small" },
408
+ { key: "spritesheet", frame: "pacman-down-large" },
409
+ { key: "spritesheet", frame: "pacman-down-small" },
410
+ { key: "spritesheet", frame: "pacman-whole" }
411
+ ],
412
+ repeat: -1,
413
+ frameRate: 16
414
+ });
415
+ anims.create({
416
+ key: "pacman-up",
417
+ frames: [
418
+ { key: "spritesheet", frame: "pacman-up-small" },
419
+ { key: "spritesheet", frame: "pacman-up-large" },
420
+ { key: "spritesheet", frame: "pacman-up-small" },
421
+ { key: "spritesheet", frame: "pacman-whole" }
422
+ ],
423
+ repeat: -1,
424
+ frameRate: 16
425
+ });
426
+ anims.create({
427
+ key: "pacman-death",
428
+ frames: [
429
+ { key: "spritesheet", frame: "pacman-dead-1" },
430
+ { key: "spritesheet", frame: "pacman-dead-2" },
431
+ { key: "spritesheet", frame: "pacman-dead-3" },
432
+ { key: "spritesheet", frame: "pacman-dead-4" },
433
+ { key: "spritesheet", frame: "pacman-dead-5" },
434
+ { key: "spritesheet", frame: "pacman-dead-6" },
435
+ { key: "spritesheet", frame: "pacman-dead-7" },
436
+ { key: "spritesheet", frame: "pacman-dead-8" },
437
+ { key: "spritesheet", frame: "pacman-dead-9" },
438
+ { key: "spritesheet", frame: "pacman-dead-10" },
439
+ { key: "spritesheet", frame: "pacman-dead-11" }
440
+ ],
441
+ frameRate: 10,
442
+ repeat: 0
443
+ });
444
+ }
445
+ };
446
+
447
+ // src/game/ui/score-display.ts
448
+ var ScoreDisplay = class extends Phaser.GameObjects.Text {
449
+ score = 0;
450
+ constructor(scene, x, y) {
451
+ super(scene, x, y, "Score: 0", {
452
+ fontFamily: "Arial",
453
+ fontSize: "24px",
454
+ color: "#ffffff"
455
+ });
456
+ scene.add.existing(this);
457
+ }
458
+ addPoints(points) {
459
+ this.score += points;
460
+ this.setText(`Score: ${this.score}`);
461
+ }
462
+ getScore() {
463
+ return this.score;
464
+ }
465
+ };
466
+
467
+ // src/game/sprites/abstracts/action-item.ts
468
+ var ActionItem = class extends Item {
469
+ };
470
+
471
+ // src/game/sprites/super-pellet.ts
472
+ var SuperPellet = class extends ActionItem {
473
+ points = 50;
474
+ constructor(scene, x, y) {
475
+ super(scene, x, y, 8, "super-pellet");
476
+ }
477
+ onCollect() {
478
+ this.destroy();
479
+ }
480
+ static addSuperPelletGraphics(scene) {
481
+ const graphics = scene.add.graphics();
482
+ graphics.fillStyle(16777215, 1);
483
+ graphics.fillCircle(8, 8, 8);
484
+ graphics.generateTexture("super-pellet", 16, 16);
485
+ graphics.destroy();
486
+ }
487
+ // Since we use a random map generator,
488
+ // the location of the four corners is not fixed.
489
+ // This function finds the four 'corners' of the map,
490
+ // defined as the four empty spaces closest to each corner of the map.
491
+ static getFourCorners(gameMap) {
492
+ const corners = [
493
+ { x: 1, y: 1 },
494
+ // Top-left
495
+ { x: gameMap[0].length - 2, y: 1 },
496
+ // Top-right
497
+ { x: 1, y: gameMap.length - 2 },
498
+ // Bottom-left
499
+ { x: gameMap[0].length - 2, y: gameMap.length - 2 }
500
+ // Bottom-right
501
+ ];
502
+ const cornerPelletPositions = [];
503
+ corners.forEach((corner) => {
504
+ const queue = [corner];
505
+ const visited = /* @__PURE__ */ new Set();
506
+ visited.add(`${corner.x},${corner.y}`);
507
+ while (queue.length > 0) {
508
+ const current = queue.shift();
509
+ if (!current) {
510
+ continue;
511
+ }
512
+ const cell = gameMap[current.y][current.x];
513
+ if (cell?.type === "empty") {
514
+ cornerPelletPositions.push({ x: current.x, y: current.y });
515
+ break;
516
+ }
517
+ const directions2 = [
518
+ { x: 0, y: -1 },
519
+ { x: 1, y: 0 },
520
+ { x: 0, y: 1 },
521
+ { x: -1, y: 0 }
522
+ ];
523
+ directions2.forEach((dir) => {
524
+ const nextX = current.x + dir.x;
525
+ const nextY = current.y + dir.y;
526
+ if (nextX >= 0 && nextX < gameMap[0].length && nextY >= 0 && nextY < gameMap.length && !visited.has(`${nextX},${nextY}`)) {
527
+ visited.add(`${nextX},${nextY}`);
528
+ queue.push({ x: nextX, y: nextY });
529
+ }
530
+ });
531
+ }
532
+ });
533
+ return cornerPelletPositions;
534
+ }
535
+ };
536
+
537
+ // src/game/sprites/ghosts/ghost.ts
538
+ var Ghost = class extends Character {
539
+ ghostState = 1 /* SCATTER */;
540
+ pelletCount = 0;
541
+ speed = GHOST_SPEED;
542
+ pacman;
543
+ gameMap;
544
+ scatterTarget = {
545
+ x: 0,
546
+ y: 0
547
+ };
548
+ target = { x: 0, y: 0 };
549
+ previousGridCoords = { x: 0, y: 0 };
550
+ hasLeftHouse = false;
551
+ isLeavingHouse = false;
552
+ sequenceIndex = 0;
553
+ sequenceTimer;
554
+ frightenedTimer;
555
+ modeSequences = [
556
+ { state: 1 /* SCATTER */, duration: 5e3 },
557
+ { state: 0 /* CHASE */, duration: 2e4 },
558
+ { state: 1 /* SCATTER */, duration: 5e3 },
559
+ { state: 0 /* CHASE */, duration: 2e4 },
560
+ { state: 1 /* SCATTER */, duration: 5e3 },
561
+ { state: 0 /* CHASE */, duration: 2e4 },
562
+ { state: 1 /* SCATTER */, duration: 5e3 },
563
+ { state: 0 /* CHASE */, duration: null }
564
+ // -1 means indefinite
565
+ ];
566
+ directionPriority;
567
+ defTextureMap;
568
+ startingCoords;
569
+ frightenedTextureMap = {
570
+ [directions.LEFT]: "frame:frightened",
571
+ [directions.RIGHT]: "frame:frightened",
572
+ [directions.UP]: "frame:frightened",
573
+ [directions.DOWN]: "frame:frightened"
574
+ };
575
+ frightenedEndTextureMap = {
576
+ [directions.LEFT]: "frightened-end",
577
+ [directions.RIGHT]: "frightened-end",
578
+ [directions.UP]: "frightened-end",
579
+ [directions.DOWN]: "frightened-end"
580
+ };
581
+ constructor(scene, gameMap, x, y, scatterTarget, pacman, ghostName, directionPriority) {
582
+ const startingFrame = `frame:${ghostName}-up`;
583
+ const textureMap = {
584
+ [directions.LEFT]: `frame:${ghostName}-left`,
585
+ [directions.RIGHT]: `frame:${ghostName}-right`,
586
+ [directions.UP]: `frame:${ghostName}-up`,
587
+ [directions.DOWN]: `frame:${ghostName}-down`
588
+ };
589
+ super(scene, gameMap, x, y, textureMap, "spritesheet", startingFrame);
590
+ this.startingCoords = { x, y };
591
+ this.directionPriority = directionPriority;
592
+ this.previousGridCoords = this.gridPosition;
593
+ this.defTextureMap = textureMap;
594
+ this.pacman = pacman;
595
+ this.gameMap = gameMap;
596
+ this.scatterTarget = scatterTarget;
597
+ this.frightenedTimer?.destroy();
598
+ this.frightenedTimer = void 0;
599
+ this.sequenceTimer?.destroy();
600
+ this.sequenceTimer = void 0;
601
+ this.sequenceIndex = 0;
602
+ this.target = this.scatterTarget;
603
+ }
604
+ countPellet() {
605
+ this.pelletCount++;
606
+ if (this.pelletCount === this.pelletCountToLeaveHouse) {
607
+ this.leaveHouse();
608
+ }
609
+ }
610
+ scare() {
611
+ this.ghostState = 2 /* FRIGHTENED */;
612
+ this.speed = GHOST_SPEED_FRIGHTENED;
613
+ let newDirection = this.getOppositeDirection(this.direction);
614
+ const canMoveInOppositeDirection = this.canMove(
615
+ this.gridPosition,
616
+ newDirection
617
+ );
618
+ if (!canMoveInOppositeDirection) {
619
+ newDirection = this.getRandomDirection();
620
+ }
621
+ this.changeDirection(newDirection);
622
+ this.textureMap = this.frightenedTextureMap;
623
+ this.setFrame("frightened");
624
+ this.sequenceTimer?.destroy();
625
+ this.frightenedTimer?.destroy();
626
+ this.frightenedTimer = this.scene.time.delayedCall(6e3, () => {
627
+ this.textureMap = this.frightenedEndTextureMap;
628
+ this.anims.play("frightened-end", true);
629
+ this.frightenedTimer = this.scene.time.delayedCall(2e3, () => {
630
+ this.speed = GHOST_SPEED;
631
+ this.textureMap = this.defTextureMap;
632
+ this.changeDirection(this.direction);
633
+ this.startSequence();
634
+ });
635
+ });
636
+ }
637
+ startSequence() {
638
+ if (this.sequenceIndex >= this.modeSequences.length) {
639
+ return;
640
+ }
641
+ const sequence = this.modeSequences[this.sequenceIndex];
642
+ this.ghostState = sequence.state;
643
+ if (sequence.duration !== null) {
644
+ this.sequenceTimer = this.scene.time.delayedCall(
645
+ sequence.duration,
646
+ () => {
647
+ this.sequenceIndex++;
648
+ this.startSequence();
649
+ }
650
+ );
651
+ }
652
+ }
653
+ // Ghosts start moving after a delay
654
+ setStartTimer() {
655
+ this.scene.time.delayedCall(this.timerToLeaveHouse, () => {
656
+ this.leaveHouse();
657
+ });
658
+ }
659
+ leaveHouse() {
660
+ if (this.hasLeftHouse) {
661
+ return;
662
+ }
663
+ this.hasLeftHouse = true;
664
+ this.isLeavingHouse = true;
665
+ const x = 14 * 32;
666
+ const y = 11 * 32 + 16;
667
+ if (this.x <= x) {
668
+ this.changeDirection(directions.RIGHT);
669
+ } else if (this.x >= x) {
670
+ this.changeDirection(directions.LEFT);
671
+ } else if (this.y >= y) {
672
+ this.changeDirection(directions.UP);
673
+ } else {
674
+ this.gridPosition = { x: 14, y: 11 };
675
+ this.previousGridCoords = this.gridPosition;
676
+ this.mapPathToTarget(this.target);
677
+ this.isLeavingHouse = false;
678
+ this.startSequence();
679
+ }
680
+ }
681
+ update() {
682
+ if (!this.hasLeftHouse) {
683
+ return;
684
+ }
685
+ if (this.isLeavingHouse) {
686
+ const targetX = 14 * 32;
687
+ const targetY = 11 * 32 + 16;
688
+ if (this.direction === directions.UP && this.y <= targetY) {
689
+ this.gridPosition = { x: 14, y: 11 };
690
+ this.previousGridCoords = this.gridPosition;
691
+ this.isLeavingHouse = false;
692
+ this.setPosition(targetX, targetY);
693
+ this.mapPathToTarget(this.target);
694
+ this.startSequence();
695
+ } else if (this.direction === directions.RIGHT && this.x >= targetX || this.direction === directions.LEFT && this.x <= targetX) {
696
+ this.setPosition(targetX, this.y);
697
+ this.changeDirection(directions.UP);
698
+ }
699
+ return;
700
+ }
701
+ super.update();
702
+ }
703
+ onCenter() {
704
+ const newCoords = this.gridPosition;
705
+ if (newCoords.x === this.previousGridCoords.x && newCoords.y === this.previousGridCoords.y) {
706
+ return;
707
+ }
708
+ this.previousGridCoords = newCoords;
709
+ if (this.direction === -1 || this.isAtIntersection()) {
710
+ switch (this.ghostState) {
711
+ case 1 /* SCATTER */:
712
+ this.target = this.scatterTarget;
713
+ break;
714
+ case 2 /* FRIGHTENED */:
715
+ this.changeDirection(this.getRandomDirection());
716
+ return;
717
+ }
718
+ this.mapPathToTarget(this.target);
719
+ return;
720
+ }
721
+ this.checkForWall();
722
+ }
723
+ handleDeath() {
724
+ if (this.body) {
725
+ this.body.stop();
726
+ this.body.enable = false;
727
+ }
728
+ this.setAlpha(0);
729
+ this.speed = 0;
730
+ this.ghostState = 3 /* DEAD */;
731
+ this.scene.time.delayedCall(3e3, () => {
732
+ this.setAlpha(1);
733
+ if (this.body) {
734
+ this.body.enable = true;
735
+ }
736
+ this.reset();
737
+ });
738
+ }
739
+ reset() {
740
+ this.frightenedTimer?.destroy();
741
+ this.sequenceTimer?.destroy();
742
+ this.ghostState = 1 /* SCATTER */;
743
+ this.speed = GHOST_SPEED;
744
+ this.hasLeftHouse = false;
745
+ this.isLeavingHouse = false;
746
+ this.textureMap = this.defTextureMap;
747
+ this.setPosition(this.startingCoords.x, this.startingCoords.y);
748
+ this.gridPosition = {
749
+ x: Math.floor(this.startingCoords.x / 32),
750
+ y: Math.floor(this.startingCoords.y / 32)
751
+ };
752
+ this.previousGridCoords = this.gridPosition;
753
+ this.direction = -1;
754
+ this.setStartTimer();
755
+ }
756
+ getRandomDirection() {
757
+ const possibleDirections = directionsArray.filter(
758
+ (d) => d.dir !== this.getOppositeDirection(this.direction)
759
+ );
760
+ const validDirections = possibleDirections.filter((d) => {
761
+ const newX = this.previousGridCoords.x + d.x;
762
+ const newY = this.previousGridCoords.y + d.y;
763
+ return this.gameMap[newY]?.[newX]?.type !== "wall" && this.gameMap[newY]?.[newX]?.type !== "ghost-house";
764
+ });
765
+ if (validDirections.length === 0) {
766
+ return this.getOppositeDirection(this.direction);
767
+ }
768
+ return Phaser.Utils.Array.GetRandom(validDirections).dir;
769
+ }
770
+ mapPathToTarget(target) {
771
+ const directionsToCheck = this.directionPriority.filter((d) => d !== this.getOppositeDirection(this.direction)).map((dir) => {
772
+ return directionsArray.find((d) => d.dir === dir);
773
+ }).filter((d) => d !== void 0);
774
+ let shortestDistance = Infinity;
775
+ let bestDirection = this.direction;
776
+ directionsToCheck.forEach((d) => {
777
+ const newX = this.gridPosition.x + d.x;
778
+ const newY = this.gridPosition.y + d.y;
779
+ const block = this.gameMap[newY]?.[newX];
780
+ if (block && this.gameMap[newY]?.[newX]?.type !== "wall" && this.gameMap[newY]?.[newX]?.type !== "ghost-house") {
781
+ const distance = Math.hypot(target.x - newX, target.y - newY);
782
+ if (distance < shortestDistance) {
783
+ shortestDistance = distance;
784
+ bestDirection = d.dir;
785
+ } else if (distance === shortestDistance && bestDirection === this.direction) {
786
+ bestDirection = d.dir;
787
+ }
788
+ }
789
+ });
790
+ this.changeDirection(bestDirection);
791
+ }
792
+ isAtIntersection() {
793
+ const cell = {
794
+ x: Math.floor(this.position.x / 32),
795
+ y: Math.floor(this.position.y / 32)
796
+ };
797
+ let paths = 0;
798
+ directionsArray.forEach((dir) => {
799
+ const newX = cell.x + dir.x;
800
+ const newY = cell.y + dir.y;
801
+ if (this.gameMap[newY]?.[newX]?.type !== "wall" && this.gameMap[newY]?.[newX]?.type !== "ghost-house") {
802
+ paths++;
803
+ }
804
+ });
805
+ return paths > 2;
806
+ }
807
+ checkForWall() {
808
+ if (!this.canMove(this.previousGridCoords, this.direction)) {
809
+ this.mapPathToTarget(this.target);
810
+ }
811
+ }
812
+ static loadTextures(textures) {
813
+ const tex = textures.get("spritesheet");
814
+ const ghosts = ["blinky", "pinky", "inky", "clyde", "eyes"];
815
+ const spriteMaps = [];
816
+ for (let i = 0; i < ghosts.length; i++) {
817
+ const ghost = ghosts[i];
818
+ spriteMaps.push(
819
+ { key: `${ghost}-up`, xPos: i * 2, yPos: 4 },
820
+ { key: `${ghost}-down`, xPos: i * 2, yPos: 6 },
821
+ { key: `${ghost}-left`, xPos: i * 2, yPos: 8 },
822
+ { key: `${ghost}-right`, xPos: i * 2, yPos: 10 }
823
+ );
824
+ }
825
+ spriteMaps.push({ key: `frightened`, xPos: 10, yPos: 4 });
826
+ spriteMaps.push({ key: `frightened-flash`, xPos: 10, yPos: 6 });
827
+ for (let i = 0; i < spriteMaps.length; i++) {
828
+ const { key, xPos, yPos } = spriteMaps[i];
829
+ tex.add(key, 0, xPos * 16, yPos * 16, 32, 32);
830
+ }
831
+ }
832
+ static loadAnimations(anims) {
833
+ anims.create({
834
+ key: "frightened-end",
835
+ frames: [
836
+ { key: "spritesheet", frame: "frightened-flash" },
837
+ { key: "spritesheet", frame: "frightened" }
838
+ ],
839
+ repeat: -1,
840
+ frameRate: 5
841
+ });
842
+ }
843
+ };
844
+
845
+ // src/game/sprites/ghosts/blinky.ts
846
+ var Blinky = class extends Ghost {
847
+ pelletCountToLeaveHouse = 0;
848
+ timerToLeaveHouse = 0;
849
+ // milliseconds
850
+ randomId = Math.random().toString(36).substring(2, 15);
851
+ constructor(scene, gameMap, pacman, scatterTarget) {
852
+ const x = 14 * 32;
853
+ const y = 11 * 32 + 16;
854
+ super(scene, gameMap, x, y, scatterTarget, pacman, "blinky", [
855
+ directions.UP,
856
+ directions.RIGHT,
857
+ directions.DOWN,
858
+ directions.LEFT
859
+ ]);
860
+ this.setStartTimer();
861
+ this.setFrame("blinky-left");
862
+ }
863
+ // Blinky always chases Pac-Man directly
864
+ onCenter() {
865
+ this.target = this.pacman.gridPosition;
866
+ super.onCenter();
867
+ }
868
+ };
869
+
870
+ // src/game/sprites/ghosts/clyde.ts
871
+ var Clyde = class extends Ghost {
872
+ pelletCountToLeaveHouse = 60;
873
+ timerToLeaveHouse = 11e3;
874
+ // milliseconds
875
+ constructor(scene, gameMap, pacman, scatterTarget) {
876
+ const x = 15.25 * 32;
877
+ const y = 13.5 * 32;
878
+ super(scene, gameMap, x, y, scatterTarget, pacman, "clyde", [
879
+ directions.DOWN,
880
+ directions.LEFT,
881
+ directions.UP,
882
+ directions.RIGHT
883
+ ]);
884
+ this.setFrame("clyde-left");
885
+ this.setStartTimer();
886
+ }
887
+ // Clyde always chases Pac-Man directly
888
+ // However, if he gets within 8 tiles of Pac-Man, he will stop moving toward him
889
+ // and instead target his "home" position in the bottom-left corner of the map
890
+ onCenter() {
891
+ this.target = this.pacman.gridPosition;
892
+ const distance = Math.abs(this.gridPosition.x - this.pacman.gridPosition.x) + Math.abs(this.gridPosition.y - this.pacman.gridPosition.y);
893
+ if (distance < 8) {
894
+ this.target = this.scatterTarget;
895
+ }
896
+ super.onCenter();
897
+ }
898
+ };
899
+
900
+ // src/game/sprites/ghosts/inky.ts
901
+ var Inky = class extends Ghost {
902
+ pelletCountToLeaveHouse = 30;
903
+ timerToLeaveHouse = 5e3;
904
+ // milliseconds
905
+ blinky;
906
+ constructor(scene, gameMap, pacman, blinky, scatterTarget) {
907
+ const x = 12.75 * 32;
908
+ const y = 13.5 * 32;
909
+ super(scene, gameMap, x, y, scatterTarget, pacman, "inky", [
910
+ directions.RIGHT,
911
+ directions.DOWN,
912
+ directions.LEFT,
913
+ directions.UP
914
+ ]);
915
+ this.blinky = blinky;
916
+ this.setFrame("inky-right");
917
+ this.setStartTimer();
918
+ }
919
+ // Inky tries to position itself based on both Blinky's and Pac-Man's positions
920
+ // First, it picks a tile two spaces in front of Pac-Man
921
+ // Then, it draws a vector from Blinky to that tile and doubles it
922
+ // Inky then targets the end of that new vector
923
+ onCenter() {
924
+ this.target = this.pacman.gridPosition;
925
+ switch (this.pacman.direction) {
926
+ case directions.LEFT:
927
+ this.target.x -= 2;
928
+ break;
929
+ case directions.UP:
930
+ this.target.x -= 2;
931
+ this.target.y -= 2;
932
+ break;
933
+ case directions.RIGHT:
934
+ this.target.x += 2;
935
+ break;
936
+ case directions.DOWN:
937
+ this.target.y += 2;
938
+ break;
939
+ }
940
+ const vectorX = (this.target.x - this.blinky.gridPosition.x) * 2;
941
+ const vectorY = (this.target.y - this.blinky.gridPosition.y) * 2;
942
+ this.target.x += vectorX;
943
+ this.target.y += vectorY;
944
+ super.onCenter();
945
+ }
946
+ };
947
+
948
+ // src/game/sprites/ghosts/pinky.ts
949
+ var Pinky = class extends Ghost {
950
+ pelletCountToLeaveHouse = 0;
951
+ timerToLeaveHouse = 0;
952
+ // milliseconds
953
+ constructor(scene, gameMap, pacman, scatterTarget) {
954
+ const x = 14 * 32;
955
+ const y = 13.5 * 32;
956
+ super(scene, gameMap, x, y, scatterTarget, pacman, "pinky", [
957
+ directions.UP,
958
+ directions.LEFT,
959
+ directions.DOWN,
960
+ directions.RIGHT
961
+ ]);
962
+ this.setFrame("pinky-up");
963
+ this.setStartTimer();
964
+ }
965
+ // Pinky tries to position itself 4 tiles ahead of Pac-Man
966
+ onCenter() {
967
+ this.target = this.pacman.gridPosition;
968
+ switch (this.pacman.direction) {
969
+ case directions.LEFT:
970
+ this.target.x -= 4;
971
+ break;
972
+ case directions.UP:
973
+ this.target.y -= 4;
974
+ this.target.x -= 4;
975
+ break;
976
+ case directions.RIGHT:
977
+ this.target.x += 4;
978
+ break;
979
+ case directions.DOWN:
980
+ this.target.y += 4;
981
+ break;
982
+ }
983
+ super.onCenter();
984
+ }
985
+ };
986
+
987
+ // src/game/_scenes/pause-scene.ts
988
+ var PauseMenu = class extends Phaser.Scene {
989
+ constructor() {
990
+ super({ key: "PauseMenu" });
991
+ }
992
+ create() {
993
+ const { width, height } = this.scale;
994
+ this.add.text(width / 2, height / 2 - 40, "Game Paused", {
995
+ fontSize: "32px",
996
+ color: "#fff"
997
+ }).setOrigin(0.5);
998
+ const resumeButton = this.add.text(width / 2, height / 2, "Resume", {
999
+ fontSize: "24px",
1000
+ color: "#0f0"
1001
+ }).setOrigin(0.5).setInteractive();
1002
+ const resume = () => {
1003
+ this.scene.stop();
1004
+ this.scene.resume("PacManScene");
1005
+ };
1006
+ resumeButton.on("pointerdown", resume);
1007
+ this.input.keyboard?.on("keydown-P", resume);
1008
+ }
1009
+ };
1010
+
1011
+ // src/game/_scenes/game-over-scene.ts
1012
+ var GameOverScene = class extends Phaser.Scene {
1013
+ constructor() {
1014
+ super({ key: "GameOverScene" });
1015
+ }
1016
+ create({ score }) {
1017
+ const { width, height } = this.scale;
1018
+ this.add.text(width / 2, height / 2 - 40, "Game Over!", {
1019
+ fontSize: "32px",
1020
+ color: "#fff",
1021
+ shadow: {
1022
+ offsetX: 2,
1023
+ offsetY: 2,
1024
+ color: "#000",
1025
+ blur: 10,
1026
+ fill: true
1027
+ }
1028
+ }).setOrigin(0.5);
1029
+ this.add.text(width / 2, height / 2, `Final Score: ${score}`, {
1030
+ fontSize: "32px",
1031
+ color: "#fff",
1032
+ shadow: {
1033
+ offsetX: 2,
1034
+ offsetY: 2,
1035
+ color: "#000",
1036
+ blur: 10,
1037
+ fill: true
1038
+ }
1039
+ }).setOrigin(0.5);
1040
+ const restart = () => {
1041
+ this.scene.stop();
1042
+ const pacManScene = this.scene.get("PacManScene");
1043
+ if (pacManScene) {
1044
+ pacManScene.scene.restart();
1045
+ }
1046
+ };
1047
+ this.add.text(width / 2, height / 2 + 40, "Restart", {
1048
+ fontSize: "24px",
1049
+ color: "#fff",
1050
+ padding: { x: 10, y: 5 },
1051
+ shadow: {
1052
+ offsetX: 2,
1053
+ offsetY: 2,
1054
+ color: "#000",
1055
+ blur: 10,
1056
+ fill: true
1057
+ }
1058
+ }).setOrigin(0.5).setInteractive({ useHandCursor: true }).on("pointerdown", restart);
1059
+ }
1060
+ };
1061
+
1062
+ // assets/spritesheet.webp
1063
+ var spritesheet_default = "data:image/webp;base64,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";
1064
+
1065
+ // src/game/_scenes/pac-man-scene.ts
1066
+ var PacManScene = class extends Scene {
1067
+ pacman;
1068
+ ghosts = [];
1069
+ scoreDisplay;
1070
+ gameOver = false;
1071
+ constructor() {
1072
+ super("PacManScene");
1073
+ }
1074
+ preload() {
1075
+ this.load.image("spritesheet", spritesheet_default);
1076
+ }
1077
+ create() {
1078
+ this.gameOver = false;
1079
+ this.physics.world.colliders.destroy();
1080
+ this.input.keyboard?.on("keydown-P", () => {
1081
+ this.scene.pause();
1082
+ this.scene.launch("PauseMenu");
1083
+ });
1084
+ this.events.on("game-over", () => {
1085
+ this.gameOver = true;
1086
+ this.physics.pause();
1087
+ this.scene.launch("GameOverScene", {
1088
+ score: this.scoreDisplay.getScore()
1089
+ });
1090
+ });
1091
+ this.createGraphics();
1092
+ const map = generateMap();
1093
+ const items = this.physics.add.staticGroup();
1094
+ const fourCorners = SuperPellet.getFourCorners(map);
1095
+ map.forEach((row, y) => {
1096
+ row.forEach((block, x) => {
1097
+ if (block?.type === "wall") {
1098
+ new Wall(this, x, y);
1099
+ } else if (block?.type === "empty" && (x !== 14 || y !== 19)) {
1100
+ if (fourCorners.some((corner) => corner.x === x && corner.y === y)) {
1101
+ items.add(new SuperPellet(this, x, y));
1102
+ return;
1103
+ }
1104
+ const surroundingBlocks = [
1105
+ map[y - 1]?.[x],
1106
+ // Up
1107
+ map[y + 1]?.[x],
1108
+ // Down
1109
+ map[y]?.[x - 1],
1110
+ // Left
1111
+ map[y]?.[x + 1],
1112
+ // Right
1113
+ map[y - 1]?.[x - 1],
1114
+ // Up-Left
1115
+ map[y - 1]?.[x + 1],
1116
+ // Up-Right
1117
+ map[y + 1]?.[x - 1],
1118
+ // Down-Left
1119
+ map[y + 1]?.[x + 1]
1120
+ // Down-Right
1121
+ ];
1122
+ if (surroundingBlocks.some((b) => b?.type === "ghost-house")) {
1123
+ return;
1124
+ }
1125
+ items.add(new Pellet(this, x, y));
1126
+ }
1127
+ });
1128
+ });
1129
+ const ghostCollisionGroup = this.physics.add.group([]);
1130
+ this.pacman = new Pacman(this, map);
1131
+ ghostCollisionGroup.add(this.pacman);
1132
+ this.scoreDisplay = new ScoreDisplay(this, 4, 4);
1133
+ this.physics.add.overlap(
1134
+ this.pacman,
1135
+ items,
1136
+ (_pacman, item) => {
1137
+ if (!(item instanceof Item)) {
1138
+ return;
1139
+ }
1140
+ if (item instanceof SuperPellet) {
1141
+ this.ghosts.forEach((ghost) => ghost.scare());
1142
+ }
1143
+ this.scoreDisplay.addPoints(item.points);
1144
+ item.destroy();
1145
+ this.pacman.eatPellet(item.coords.x, item.coords.y);
1146
+ this.ghosts.forEach((ghost) => ghost.countPellet());
1147
+ },
1148
+ void 0,
1149
+ this
1150
+ );
1151
+ const blinky = new Blinky(this, map, this.pacman, fourCorners[1]);
1152
+ this.ghosts.push(
1153
+ new Pinky(this, map, this.pacman, fourCorners[0]),
1154
+ blinky,
1155
+ new Clyde(this, map, this.pacman, fourCorners[2])
1156
+ );
1157
+ this.ghosts.push(new Inky(this, map, this.pacman, blinky, fourCorners[3]));
1158
+ this.ghosts.forEach((ghost) => ghostCollisionGroup.add(ghost));
1159
+ this.physics.add.overlap(this.pacman, ghostCollisionGroup, (_, o2) => {
1160
+ const ghost = o2;
1161
+ if (ghost.ghostState === 2 /* FRIGHTENED */) {
1162
+ this.scoreDisplay.addPoints(200);
1163
+ ghost.handleDeath();
1164
+ } else {
1165
+ this.pacman.handleDeath();
1166
+ }
1167
+ });
1168
+ }
1169
+ update() {
1170
+ if (this.gameOver) {
1171
+ return;
1172
+ }
1173
+ this.pacman.update();
1174
+ this.ghosts.forEach((ghost) => {
1175
+ if (ghost.ghostState !== 3 /* DEAD */) ghost.update();
1176
+ });
1177
+ }
1178
+ createGraphics() {
1179
+ Pacman.loadTextures(this.textures);
1180
+ Pacman.loadAnimations(this.anims);
1181
+ Ghost.loadTextures(this.textures);
1182
+ Ghost.loadAnimations(this.anims);
1183
+ Wall.addWallGraphics(this);
1184
+ Pellet.addPelletGraphics(this);
1185
+ SuperPellet.addSuperPelletGraphics(this);
1186
+ }
1187
+ };
1188
+ function createPacManScene(container) {
1189
+ const config = {
1190
+ type: Phaser.AUTO,
1191
+ parent: container,
1192
+ backgroundColor: "#5e5f60ff",
1193
+ width: 896,
1194
+ height: 992,
1195
+ physics: {
1196
+ default: "arcade",
1197
+ arcade: {
1198
+ gravity: { x: 0, y: 0 },
1199
+ debug: false
1200
+ }
1201
+ },
1202
+ scale: {
1203
+ mode: Phaser.Scale.FIT,
1204
+ autoCenter: Phaser.Scale.CENTER_BOTH
1205
+ },
1206
+ scene: [PacManScene, PauseMenu, GameOverScene]
1207
+ };
1208
+ return new Phaser.Game(config);
1209
+ }
1210
+
1211
+ // src/pac-man.tsx
1212
+ import { jsx } from "react/jsx-runtime";
1213
+ function PacMan() {
1214
+ const container = useRef(null);
1215
+ const gameRef = useRef(null);
1216
+ useEffect(() => {
1217
+ if (gameRef.current || !container.current) {
1218
+ return;
1219
+ }
1220
+ gameRef.current = createPacManScene(container.current);
1221
+ return () => {
1222
+ gameRef.current?.destroy(true);
1223
+ gameRef.current = null;
1224
+ };
1225
+ }, []);
1226
+ return /* @__PURE__ */ jsx("div", { style: { width: "448px", height: "496px" }, ref: container });
1227
+ }
1228
+ export {
1229
+ PacMan
1230
+ };