@mclawnet/agent 0.6.20 → 0.6.22
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.
- package/cli.js +63 -0
- package/dist/__tests__/checkpoint.test.d.ts +2 -0
- package/dist/__tests__/checkpoint.test.d.ts.map +1 -0
- package/dist/__tests__/fs-handler-decode.test.d.ts +2 -0
- package/dist/__tests__/fs-handler-decode.test.d.ts.map +1 -0
- package/dist/__tests__/idle-sweeper.test.d.ts +2 -0
- package/dist/__tests__/idle-sweeper.test.d.ts.map +1 -0
- package/dist/__tests__/mcp-config.test.d.ts +2 -0
- package/dist/__tests__/mcp-config.test.d.ts.map +1 -0
- package/dist/__tests__/schedule-runtime-spawn.test.d.ts +2 -0
- package/dist/__tests__/schedule-runtime-spawn.test.d.ts.map +1 -0
- package/dist/__tests__/schedule-runtime.test.d.ts +2 -0
- package/dist/__tests__/schedule-runtime.test.d.ts.map +1 -0
- package/dist/__tests__/session-limit.test.d.ts +2 -0
- package/dist/__tests__/session-limit.test.d.ts.map +1 -0
- package/dist/__tests__/swarm-cli-client.test.d.ts +2 -0
- package/dist/__tests__/swarm-cli-client.test.d.ts.map +1 -0
- package/dist/__tests__/swarm-control-dispatch.test.d.ts +2 -0
- package/dist/__tests__/swarm-control-dispatch.test.d.ts.map +1 -0
- package/dist/__tests__/swarm-session-bridge.test.d.ts +2 -0
- package/dist/__tests__/swarm-session-bridge.test.d.ts.map +1 -0
- package/dist/backend-adapter.d.ts +43 -0
- package/dist/backend-adapter.d.ts.map +1 -1
- package/dist/checkpoint.d.ts +67 -0
- package/dist/checkpoint.d.ts.map +1 -0
- package/dist/{chunk-RIK7IXSW.js → chunk-WJWCYGLQ.js} +1130 -147
- package/dist/chunk-WJWCYGLQ.js.map +1 -0
- package/dist/errors.d.ts +40 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/fs-handler.d.ts.map +1 -1
- package/dist/hub-connection.d.ts +13 -0
- package/dist/hub-connection.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/schedule-runtime.d.ts +125 -0
- package/dist/schedule-runtime.d.ts.map +1 -0
- package/dist/session-manager.d.ts +102 -0
- package/dist/session-manager.d.ts.map +1 -1
- package/dist/skill-loader.d.ts +20 -0
- package/dist/skill-loader.d.ts.map +1 -1
- package/dist/start.d.ts +2 -0
- package/dist/start.d.ts.map +1 -1
- package/dist/start.js +1 -1
- package/dist/swarm-cli-client.d.ts +24 -0
- package/dist/swarm-cli-client.d.ts.map +1 -0
- package/dist/swarm-cli-client.js +83 -0
- package/dist/swarm-cli-client.js.map +1 -0
- package/dist/swarm-control-dispatch.d.ts +47 -0
- package/dist/swarm-control-dispatch.d.ts.map +1 -0
- package/dist/swarm-session-bridge.d.ts +22 -0
- package/dist/swarm-session-bridge.d.ts.map +1 -0
- package/package.json +6 -4
- package/skills/cocos-creator-3x-cn/SKILL.md +475 -0
- package/skills/cocos-creator-3x-cn/references/framework/asset-management.md +322 -0
- package/skills/cocos-creator-3x-cn/references/framework/component-system.md +348 -0
- package/skills/cocos-creator-3x-cn/references/framework/event-patterns.md +410 -0
- package/skills/cocos-creator-3x-cn/references/framework/playable-optimization.md +257 -0
- package/skills/cocos-creator-3x-cn/references/language/performance.md +363 -0
- package/skills/cocos-creator-3x-cn/references/language/quality-hygiene.md +307 -0
- package/skills/cocos-creator-3x-cn/references/review/architecture-review.md +183 -0
- package/skills/cocos-creator-3x-cn/references/review/quality-review.md +251 -0
- package/skills/cocos-performance-optimizer/SKILL.md +214 -0
- package/skills/game-development/2d-games/SKILL.md +129 -0
- package/skills/game-development/3d-games/SKILL.md +145 -0
- package/skills/game-development/SKILL.md +175 -0
- package/skills/game-development/game-art/SKILL.md +195 -0
- package/skills/game-development/game-audio/SKILL.md +200 -0
- package/skills/game-development/game-design/SKILL.md +139 -0
- package/skills/game-development/mobile-games/SKILL.md +118 -0
- package/skills/game-development/multiplayer/SKILL.md +142 -0
- package/skills/game-development/pc-games/SKILL.md +154 -0
- package/skills/game-development/vr-ar/SKILL.md +133 -0
- package/skills/game-development/web-games/SKILL.md +160 -0
- package/skills/game-engine/SKILL.md +140 -0
- package/skills/game-engine/assets/2d-maze-game.md +528 -0
- package/skills/game-engine/assets/2d-platform-game.md +1855 -0
- package/skills/game-engine/assets/gameBase-template-repo.md +310 -0
- package/skills/game-engine/assets/paddle-game-template.md +1528 -0
- package/skills/game-engine/assets/simple-2d-engine.md +507 -0
- package/skills/game-engine/references/3d-web-games.md +754 -0
- package/skills/game-engine/references/algorithms.md +843 -0
- package/skills/game-engine/references/basics.md +343 -0
- package/skills/game-engine/references/game-control-mechanisms.md +617 -0
- package/skills/game-engine/references/game-engine-core-principles.md +695 -0
- package/skills/game-engine/references/game-publishing.md +352 -0
- package/skills/game-engine/references/techniques.md +894 -0
- package/skills/game-engine/references/terminology.md +354 -0
- package/skills/game-engine/references/web-apis.md +1394 -0
- package/skills/theone-cocos-standards/SKILL.md +557 -0
- package/skills/theone-cocos-standards/references/framework/component-system.md +645 -0
- package/skills/theone-cocos-standards/references/framework/event-patterns.md +433 -0
- package/skills/theone-cocos-standards/references/framework/playable-optimization.md +429 -0
- package/skills/theone-cocos-standards/references/framework/size-optimization.md +308 -0
- package/skills/theone-cocos-standards/references/language/modern-typescript.md +658 -0
- package/skills/theone-cocos-standards/references/language/performance.md +580 -0
- package/skills/theone-cocos-standards/references/language/quality-hygiene.md +582 -0
- package/skills/theone-cocos-standards/references/review/architecture-review.md +250 -0
- package/skills/theone-cocos-standards/references/review/performance-review.md +288 -0
- package/skills/theone-cocos-standards/references/review/quality-review.md +239 -0
- package/dist/chunk-RIK7IXSW.js.map +0 -1
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
# 2D Maze Game Template
|
|
2
|
+
|
|
3
|
+
A mobile-optimized 2D maze game where players guide a ball through a labyrinth of obstacles to reach a target hole. The game uses the **Device Orientation API** for tilt-based motion controls on mobile devices and keyboard arrow keys on desktop. Built with the **Phaser** framework (v2.x with Arcade Physics), it features multi-level progression, collision detection, audio feedback, vibration haptics, and a timer system.
|
|
4
|
+
|
|
5
|
+
**Source reference:** [MDN - HTML5 Gamedev Phaser Device Orientation](https://developer.mozilla.org/en-US/docs/Games/Tutorials/HTML5_Gamedev_Phaser_Device_Orientation)
|
|
6
|
+
**Live demo:** [Cyber Orb](https://orb.enclavegames.com/)
|
|
7
|
+
**Source code:** [GitHub - EnclaveGames/Cyber-Orb](https://github.com/EnclaveGames/Cyber-Orb)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Game Concept
|
|
12
|
+
|
|
13
|
+
The player controls a ball (the "orb") by tilting their mobile device or pressing arrow keys. The ball rolls through a maze of horizontal and vertical wall segments. The objective on each level is to navigate the ball to a hole at the top of the screen while avoiding walls. Collisions with walls trigger a bounce, a sound effect, and optional vibration. A timer tracks how long the player takes per level and across the entire game.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Project Structure
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
project/
|
|
21
|
+
index.html
|
|
22
|
+
src/
|
|
23
|
+
phaser-arcade-physics.2.2.2.min.js
|
|
24
|
+
Boot.js
|
|
25
|
+
Preloader.js
|
|
26
|
+
MainMenu.js
|
|
27
|
+
Howto.js
|
|
28
|
+
Game.js
|
|
29
|
+
img/
|
|
30
|
+
ball.png
|
|
31
|
+
hole.png
|
|
32
|
+
element-horizontal.png
|
|
33
|
+
element-vertical.png
|
|
34
|
+
button-start.png
|
|
35
|
+
loading-bg.png
|
|
36
|
+
loading-bar.png
|
|
37
|
+
audio/
|
|
38
|
+
bounce.ogg
|
|
39
|
+
bounce.mp3
|
|
40
|
+
bounce.m4a
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Phaser Setup and Initialization
|
|
46
|
+
|
|
47
|
+
### HTML Entry Point
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<!doctype html>
|
|
51
|
+
<html lang="en">
|
|
52
|
+
<head>
|
|
53
|
+
<meta charset="utf-8" />
|
|
54
|
+
<title>Cyber Orb</title>
|
|
55
|
+
<style>
|
|
56
|
+
body { margin: 0; background: #333; }
|
|
57
|
+
</style>
|
|
58
|
+
<script src="src/phaser-arcade-physics.2.2.2.min.js"></script>
|
|
59
|
+
<script src="src/Boot.js"></script>
|
|
60
|
+
<script src="src/Preloader.js"></script>
|
|
61
|
+
<script src="src/MainMenu.js"></script>
|
|
62
|
+
<script src="src/Howto.js"></script>
|
|
63
|
+
<script src="src/Game.js"></script>
|
|
64
|
+
</head>
|
|
65
|
+
<body>
|
|
66
|
+
<script>
|
|
67
|
+
(() => {
|
|
68
|
+
const game = new Phaser.Game(320, 480, Phaser.CANVAS, "game");
|
|
69
|
+
game.state.add("Boot", Ball.Boot);
|
|
70
|
+
game.state.add("Preloader", Ball.Preloader);
|
|
71
|
+
game.state.add("MainMenu", Ball.MainMenu);
|
|
72
|
+
game.state.add("Howto", Ball.Howto);
|
|
73
|
+
game.state.add("Game", Ball.Game);
|
|
74
|
+
game.state.start("Boot");
|
|
75
|
+
})();
|
|
76
|
+
</script>
|
|
77
|
+
</body>
|
|
78
|
+
</html>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- Canvas size: `320 x 480`
|
|
82
|
+
- Renderer: `Phaser.CANVAS` (alternatives: `Phaser.WEBGL`, `Phaser.AUTO`)
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Game State Architecture
|
|
87
|
+
|
|
88
|
+
The game follows a linear state flow:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
Boot --> Preloader --> MainMenu --> Howto --> Game
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Boot State
|
|
95
|
+
|
|
96
|
+
Loads minimal assets for the loading screen and configures scaling.
|
|
97
|
+
|
|
98
|
+
```javascript
|
|
99
|
+
const Ball = {
|
|
100
|
+
_WIDTH: 320,
|
|
101
|
+
_HEIGHT: 480,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
Ball.Boot = function (game) {};
|
|
105
|
+
Ball.Boot.prototype = {
|
|
106
|
+
preload() {
|
|
107
|
+
this.load.image("preloaderBg", "img/loading-bg.png");
|
|
108
|
+
this.load.image("preloaderBar", "img/loading-bar.png");
|
|
109
|
+
},
|
|
110
|
+
create() {
|
|
111
|
+
this.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
|
|
112
|
+
this.game.scale.pageAlignHorizontally = true;
|
|
113
|
+
this.game.scale.pageAlignVertically = true;
|
|
114
|
+
this.game.state.start("Preloader");
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Preloader State
|
|
120
|
+
|
|
121
|
+
Displays a visual loading bar while loading all game assets. Audio is loaded in multiple formats for cross-browser compatibility.
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
Ball.Preloader = function (game) {};
|
|
125
|
+
Ball.Preloader.prototype = {
|
|
126
|
+
preload() {
|
|
127
|
+
this.preloadBg = this.add.sprite(
|
|
128
|
+
(Ball._WIDTH - 297) * 0.5,
|
|
129
|
+
(Ball._HEIGHT - 145) * 0.5,
|
|
130
|
+
"preloaderBg"
|
|
131
|
+
);
|
|
132
|
+
this.preloadBar = this.add.sprite(
|
|
133
|
+
(Ball._WIDTH - 158) * 0.5,
|
|
134
|
+
(Ball._HEIGHT - 50) * 0.5,
|
|
135
|
+
"preloaderBar"
|
|
136
|
+
);
|
|
137
|
+
this.load.setPreloadSprite(this.preloadBar);
|
|
138
|
+
|
|
139
|
+
this.load.image("ball", "img/ball.png");
|
|
140
|
+
this.load.image("hole", "img/hole.png");
|
|
141
|
+
this.load.image("element-w", "img/element-horizontal.png");
|
|
142
|
+
this.load.image("element-h", "img/element-vertical.png");
|
|
143
|
+
this.load.spritesheet("button-start", "img/button-start.png", 146, 51);
|
|
144
|
+
this.load.audio("audio-bounce", [
|
|
145
|
+
"audio/bounce.ogg",
|
|
146
|
+
"audio/bounce.mp3",
|
|
147
|
+
"audio/bounce.m4a",
|
|
148
|
+
]);
|
|
149
|
+
},
|
|
150
|
+
create() {
|
|
151
|
+
this.game.state.start("MainMenu");
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### MainMenu State
|
|
157
|
+
|
|
158
|
+
Displays the title screen with a start button.
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
Ball.MainMenu = function (game) {};
|
|
162
|
+
Ball.MainMenu.prototype = {
|
|
163
|
+
create() {
|
|
164
|
+
this.add.sprite(0, 0, "screen-mainmenu");
|
|
165
|
+
this.gameTitle = this.add.sprite(Ball._WIDTH * 0.5, 40, "title");
|
|
166
|
+
this.gameTitle.anchor.set(0.5, 0);
|
|
167
|
+
|
|
168
|
+
this.startButton = this.add.button(
|
|
169
|
+
Ball._WIDTH * 0.5, 200, "button-start",
|
|
170
|
+
this.startGame, this,
|
|
171
|
+
2, 0, 1 // hover, out, down frames
|
|
172
|
+
);
|
|
173
|
+
this.startButton.anchor.set(0.5, 0);
|
|
174
|
+
this.startButton.input.useHandCursor = true;
|
|
175
|
+
},
|
|
176
|
+
startGame() {
|
|
177
|
+
this.game.state.start("Howto");
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Howto State
|
|
183
|
+
|
|
184
|
+
A single-click instruction screen before gameplay begins.
|
|
185
|
+
|
|
186
|
+
```javascript
|
|
187
|
+
Ball.Howto = function (game) {};
|
|
188
|
+
Ball.Howto.prototype = {
|
|
189
|
+
create() {
|
|
190
|
+
this.buttonContinue = this.add.button(
|
|
191
|
+
0, 0, "screen-howtoplay",
|
|
192
|
+
this.startGame, this
|
|
193
|
+
);
|
|
194
|
+
},
|
|
195
|
+
startGame() {
|
|
196
|
+
this.game.state.start("Game");
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Device Orientation API Usage
|
|
204
|
+
|
|
205
|
+
The Device Orientation API provides real-time data about the physical tilt of a device. Two axes are used:
|
|
206
|
+
|
|
207
|
+
| Property | Axis | Range | Effect |
|
|
208
|
+
|----------|------|-------|--------|
|
|
209
|
+
| `event.gamma` | Left/right tilt | -90 to 90 degrees | Horizontal ball velocity |
|
|
210
|
+
| `event.beta` | Front/back tilt | -180 to 180 degrees | Vertical ball velocity |
|
|
211
|
+
|
|
212
|
+
### Registering the Listener
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
// In the Game state's create() method
|
|
216
|
+
window.addEventListener("deviceorientation", this.handleOrientation);
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Handling Orientation Events
|
|
220
|
+
|
|
221
|
+
```javascript
|
|
222
|
+
handleOrientation(e) {
|
|
223
|
+
const x = e.gamma; // left-right tilt
|
|
224
|
+
const y = e.beta; // front-back tilt
|
|
225
|
+
Ball._player.body.velocity.x += x;
|
|
226
|
+
Ball._player.body.velocity.y += y;
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Tilt Behavior
|
|
231
|
+
|
|
232
|
+
- Tilt device left: negative gamma, ball rolls left
|
|
233
|
+
- Tilt device right: positive gamma, ball rolls right
|
|
234
|
+
- Tilt device forward: positive beta, ball rolls down
|
|
235
|
+
- Tilt device backward: negative beta, ball rolls up
|
|
236
|
+
|
|
237
|
+
The tilt angle directly maps to velocity increments -- the steeper the tilt, the greater the force applied to the ball each frame.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Core Game Mechanics
|
|
242
|
+
|
|
243
|
+
### Game State Structure
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
Ball.Game = function (game) {};
|
|
247
|
+
Ball.Game.prototype = {
|
|
248
|
+
create() {},
|
|
249
|
+
initLevels() {},
|
|
250
|
+
showLevel(level) {},
|
|
251
|
+
updateCounter() {},
|
|
252
|
+
managePause() {},
|
|
253
|
+
manageAudio() {},
|
|
254
|
+
update() {},
|
|
255
|
+
wallCollision() {},
|
|
256
|
+
handleOrientation(e) {},
|
|
257
|
+
finishLevel() {},
|
|
258
|
+
};
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Ball Creation and Physics
|
|
262
|
+
|
|
263
|
+
```javascript
|
|
264
|
+
// In create()
|
|
265
|
+
this.ball = this.add.sprite(this.ballStartPos.x, this.ballStartPos.y, "ball");
|
|
266
|
+
this.ball.anchor.set(0.5);
|
|
267
|
+
this.physics.enable(this.ball, Phaser.Physics.ARCADE);
|
|
268
|
+
this.ball.body.setSize(18, 18);
|
|
269
|
+
this.ball.body.bounce.set(0.3, 0.3);
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
- Anchor at center `(0.5, 0.5)` for rotation around midpoint
|
|
273
|
+
- Physics body: 18x18 pixels
|
|
274
|
+
- Bounce coefficient: 0.3 (retains 30% velocity after wall collision)
|
|
275
|
+
|
|
276
|
+
### Keyboard Controls (Desktop Fallback)
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
// In create()
|
|
280
|
+
this.keys = this.game.input.keyboard.createCursorKeys();
|
|
281
|
+
|
|
282
|
+
// In update()
|
|
283
|
+
if (this.keys.left.isDown) {
|
|
284
|
+
this.ball.body.velocity.x -= this.movementForce;
|
|
285
|
+
} else if (this.keys.right.isDown) {
|
|
286
|
+
this.ball.body.velocity.x += this.movementForce;
|
|
287
|
+
}
|
|
288
|
+
if (this.keys.up.isDown) {
|
|
289
|
+
this.ball.body.velocity.y -= this.movementForce;
|
|
290
|
+
} else if (this.keys.down.isDown) {
|
|
291
|
+
this.ball.body.velocity.y += this.movementForce;
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Hole (Goal) Setup
|
|
296
|
+
|
|
297
|
+
```javascript
|
|
298
|
+
this.hole = this.add.sprite(Ball._WIDTH * 0.5, 90, "hole");
|
|
299
|
+
this.physics.enable(this.hole, Phaser.Physics.ARCADE);
|
|
300
|
+
this.hole.anchor.set(0.5);
|
|
301
|
+
this.hole.body.setSize(2, 2);
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
The hole has a tiny 2x2 collision body for precise overlap detection.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Level System
|
|
309
|
+
|
|
310
|
+
### Level Data Format
|
|
311
|
+
|
|
312
|
+
Each level is an array of wall segment objects with position and type:
|
|
313
|
+
|
|
314
|
+
```javascript
|
|
315
|
+
this.levelData = [
|
|
316
|
+
[{ x: 96, y: 224, t: "w" }], // Level 1
|
|
317
|
+
[
|
|
318
|
+
{ x: 72, y: 320, t: "w" },
|
|
319
|
+
{ x: 200, y: 320, t: "h" },
|
|
320
|
+
{ x: 72, y: 150, t: "w" },
|
|
321
|
+
], // Level 2
|
|
322
|
+
// ... more levels
|
|
323
|
+
];
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
- `x, y`: Position in pixels
|
|
327
|
+
- `t`: Type -- `"w"` for horizontal wall, `"h"` for vertical wall
|
|
328
|
+
|
|
329
|
+
### Building Levels
|
|
330
|
+
|
|
331
|
+
```javascript
|
|
332
|
+
initLevels() {
|
|
333
|
+
for (let i = 0; i < this.maxLevels; i++) {
|
|
334
|
+
const newLevel = this.add.group();
|
|
335
|
+
newLevel.enableBody = true;
|
|
336
|
+
newLevel.physicsBodyType = Phaser.Physics.ARCADE;
|
|
337
|
+
|
|
338
|
+
for (const item of this.levelData[i]) {
|
|
339
|
+
newLevel.create(item.x, item.y, `element-${item.t}`);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
newLevel.setAll("body.immovable", true);
|
|
343
|
+
newLevel.visible = false;
|
|
344
|
+
this.levels.push(newLevel);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Showing a Level
|
|
350
|
+
|
|
351
|
+
```javascript
|
|
352
|
+
showLevel(level) {
|
|
353
|
+
const lvl = level || this.level;
|
|
354
|
+
if (this.levels[lvl - 2]) {
|
|
355
|
+
this.levels[lvl - 2].visible = false;
|
|
356
|
+
}
|
|
357
|
+
this.levels[lvl - 1].visible = true;
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## Collision Detection
|
|
364
|
+
|
|
365
|
+
### Wall Collisions (Bounce)
|
|
366
|
+
|
|
367
|
+
```javascript
|
|
368
|
+
// In update()
|
|
369
|
+
this.physics.arcade.collide(
|
|
370
|
+
this.ball, this.borderGroup,
|
|
371
|
+
this.wallCollision, null, this
|
|
372
|
+
);
|
|
373
|
+
this.physics.arcade.collide(
|
|
374
|
+
this.ball, this.levels[this.level - 1],
|
|
375
|
+
this.wallCollision, null, this
|
|
376
|
+
);
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
`collide` causes the ball to bounce off walls and triggers the callback.
|
|
380
|
+
|
|
381
|
+
### Hole Overlap (Pass-Through Detection)
|
|
382
|
+
|
|
383
|
+
```javascript
|
|
384
|
+
this.physics.arcade.overlap(
|
|
385
|
+
this.ball, this.hole,
|
|
386
|
+
this.finishLevel, null, this
|
|
387
|
+
);
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
`overlap` detects intersection without physical collision response.
|
|
391
|
+
|
|
392
|
+
### Wall Collision Callback
|
|
393
|
+
|
|
394
|
+
```javascript
|
|
395
|
+
wallCollision() {
|
|
396
|
+
if (this.audioStatus) {
|
|
397
|
+
this.bounceSound.play();
|
|
398
|
+
}
|
|
399
|
+
if ("vibrate" in window.navigator) {
|
|
400
|
+
window.navigator.vibrate(100);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## Audio System
|
|
408
|
+
|
|
409
|
+
```javascript
|
|
410
|
+
// In create()
|
|
411
|
+
this.bounceSound = this.game.add.audio("audio-bounce");
|
|
412
|
+
|
|
413
|
+
// Toggle
|
|
414
|
+
manageAudio() {
|
|
415
|
+
this.audioStatus = !this.audioStatus;
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## Vibration API
|
|
422
|
+
|
|
423
|
+
```javascript
|
|
424
|
+
if ("vibrate" in window.navigator) {
|
|
425
|
+
window.navigator.vibrate(100); // 100ms vibration pulse
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Feature-detect before calling. Provides tactile feedback on supported mobile devices.
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## Timer System
|
|
434
|
+
|
|
435
|
+
```javascript
|
|
436
|
+
// In create()
|
|
437
|
+
this.timer = 0;
|
|
438
|
+
this.totalTimer = 0;
|
|
439
|
+
this.timerText = this.game.add.text(15, 15, "Time: 0", this.fontBig);
|
|
440
|
+
this.totalTimeText = this.game.add.text(120, 30, "Total time: 0", this.fontSmall);
|
|
441
|
+
this.time.events.loop(Phaser.Timer.SECOND, this.updateCounter, this);
|
|
442
|
+
|
|
443
|
+
// Counter callback
|
|
444
|
+
updateCounter() {
|
|
445
|
+
this.timer++;
|
|
446
|
+
this.timerText.setText(`Time: ${this.timer}`);
|
|
447
|
+
this.totalTimeText.setText(`Total time: ${this.totalTimer + this.timer}`);
|
|
448
|
+
}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## Level Completion
|
|
454
|
+
|
|
455
|
+
```javascript
|
|
456
|
+
finishLevel() {
|
|
457
|
+
if (this.level >= this.maxLevels) {
|
|
458
|
+
this.totalTimer += this.timer;
|
|
459
|
+
alert(`Congratulations, game completed!\nTotal time: ${this.totalTimer}s`);
|
|
460
|
+
this.game.state.start("MainMenu");
|
|
461
|
+
} else {
|
|
462
|
+
alert(`Level ${this.level} completed!`);
|
|
463
|
+
this.totalTimer += this.timer;
|
|
464
|
+
this.timer = 0;
|
|
465
|
+
this.level++;
|
|
466
|
+
this.timerText.setText(`Time: ${this.timer}`);
|
|
467
|
+
this.totalTimeText.setText(`Total time: ${this.totalTimer}`);
|
|
468
|
+
this.levelText.setText(`Level: ${this.level} / ${this.maxLevels}`);
|
|
469
|
+
this.ball.body.x = this.ballStartPos.x;
|
|
470
|
+
this.ball.body.y = this.ballStartPos.y;
|
|
471
|
+
this.ball.body.velocity.x = 0;
|
|
472
|
+
this.ball.body.velocity.y = 0;
|
|
473
|
+
this.showLevel();
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## Complete Update Loop
|
|
481
|
+
|
|
482
|
+
```javascript
|
|
483
|
+
update() {
|
|
484
|
+
// Keyboard input
|
|
485
|
+
if (this.keys.left.isDown) {
|
|
486
|
+
this.ball.body.velocity.x -= this.movementForce;
|
|
487
|
+
} else if (this.keys.right.isDown) {
|
|
488
|
+
this.ball.body.velocity.x += this.movementForce;
|
|
489
|
+
}
|
|
490
|
+
if (this.keys.up.isDown) {
|
|
491
|
+
this.ball.body.velocity.y -= this.movementForce;
|
|
492
|
+
} else if (this.keys.down.isDown) {
|
|
493
|
+
this.ball.body.velocity.y += this.movementForce;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Wall collisions
|
|
497
|
+
this.physics.arcade.collide(
|
|
498
|
+
this.ball, this.borderGroup, this.wallCollision, null, this
|
|
499
|
+
);
|
|
500
|
+
this.physics.arcade.collide(
|
|
501
|
+
this.ball, this.levels[this.level - 1], this.wallCollision, null, this
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
// Hole overlap
|
|
505
|
+
this.physics.arcade.overlap(
|
|
506
|
+
this.ball, this.hole, this.finishLevel, null, this
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## Phaser API Quick Reference
|
|
514
|
+
|
|
515
|
+
| Function | Purpose |
|
|
516
|
+
|----------|---------|
|
|
517
|
+
| `this.add.sprite(x, y, key)` | Create a game object |
|
|
518
|
+
| `this.add.group()` | Create a container for objects |
|
|
519
|
+
| `this.add.button(x, y, key, cb, ctx, over, out, down)` | Create interactive button |
|
|
520
|
+
| `this.add.text(x, y, text, style)` | Create text display |
|
|
521
|
+
| `this.physics.enable(obj, system)` | Enable physics on object |
|
|
522
|
+
| `this.physics.arcade.collide(a, b, cb)` | Detect collision with bounce |
|
|
523
|
+
| `this.physics.arcade.overlap(a, b, cb)` | Detect overlap without bounce |
|
|
524
|
+
| `this.load.image(key, path)` | Load image asset |
|
|
525
|
+
| `this.load.spritesheet(key, path, w, h)` | Load sprite animation sheet |
|
|
526
|
+
| `this.load.audio(key, paths[])` | Load audio with format fallbacks |
|
|
527
|
+
| `this.game.add.audio(key)` | Instantiate audio object |
|
|
528
|
+
| `this.time.events.loop(interval, cb, ctx)` | Create repeating timer |
|