@guinetik/gcanvas 1.0.4 → 1.0.5
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/dist/CNAME +1 -0
- package/dist/animations.html +31 -0
- package/dist/basic.html +38 -0
- package/dist/baskara.html +31 -0
- package/dist/bezier.html +35 -0
- package/dist/beziersignature.html +29 -0
- package/dist/blackhole.html +28 -0
- package/dist/blob.html +35 -0
- package/dist/coordinates.html +698 -0
- package/dist/cube3d.html +23 -0
- package/dist/demos.css +303 -0
- package/dist/dino.html +42 -0
- package/dist/easing.html +28 -0
- package/dist/events.html +195 -0
- package/dist/fluent.html +647 -0
- package/dist/fluid-simple.html +22 -0
- package/dist/fluid.html +37 -0
- package/dist/fractals.html +36 -0
- package/dist/gameobjects.html +626 -0
- package/dist/gcanvas.es.js +517 -0
- package/dist/gcanvas.es.min.js +1 -1
- package/dist/gcanvas.umd.js +1 -1
- package/dist/gcanvas.umd.min.js +1 -1
- package/dist/genart.html +26 -0
- package/dist/gendream.html +26 -0
- package/dist/group.html +36 -0
- package/dist/home.html +587 -0
- package/dist/hyperbolic001.html +23 -0
- package/dist/hyperbolic002.html +23 -0
- package/dist/hyperbolic003.html +23 -0
- package/dist/hyperbolic004.html +23 -0
- package/dist/hyperbolic005.html +22 -0
- package/dist/index.html +398 -0
- package/dist/isometric.html +34 -0
- package/dist/js/animations.js +452 -0
- package/dist/js/basic.js +204 -0
- package/dist/js/baskara.js +751 -0
- package/dist/js/bezier.js +692 -0
- package/dist/js/beziersignature.js +241 -0
- package/dist/js/blackhole/accretiondisk.obj.js +379 -0
- package/dist/js/blackhole/blackhole.obj.js +318 -0
- package/dist/js/blackhole/index.js +409 -0
- package/dist/js/blackhole/particle.js +56 -0
- package/dist/js/blackhole/starfield.obj.js +218 -0
- package/dist/js/blob.js +2276 -0
- package/dist/js/coordinates.js +840 -0
- package/dist/js/cube3d.js +789 -0
- package/dist/js/dino.js +1420 -0
- package/dist/js/easing.js +477 -0
- package/dist/js/fluent.js +183 -0
- package/dist/js/fluid-simple.js +253 -0
- package/dist/js/fluid.js +527 -0
- package/dist/js/fractals.js +932 -0
- package/dist/js/fractalworker.js +93 -0
- package/dist/js/gameobjects.js +176 -0
- package/dist/js/genart.js +268 -0
- package/dist/js/gendream.js +209 -0
- package/dist/js/group.js +140 -0
- package/dist/js/hyperbolic001.js +310 -0
- package/dist/js/hyperbolic002.js +388 -0
- package/dist/js/hyperbolic003.js +319 -0
- package/dist/js/hyperbolic004.js +345 -0
- package/dist/js/hyperbolic005.js +340 -0
- package/dist/js/info-toggle.js +25 -0
- package/dist/js/isometric.js +863 -0
- package/dist/js/kerr.js +1547 -0
- package/dist/js/lavalamp.js +590 -0
- package/dist/js/layout.js +354 -0
- package/dist/js/mondrian.js +285 -0
- package/dist/js/opacity.js +275 -0
- package/dist/js/painter.js +484 -0
- package/dist/js/particles-showcase.js +514 -0
- package/dist/js/particles.js +299 -0
- package/dist/js/patterns.js +397 -0
- package/dist/js/penrose/artifact.js +69 -0
- package/dist/js/penrose/blackhole.js +121 -0
- package/dist/js/penrose/constants.js +73 -0
- package/dist/js/penrose/game.js +943 -0
- package/dist/js/penrose/lore.js +278 -0
- package/dist/js/penrose/penrosescene.js +892 -0
- package/dist/js/penrose/ship.js +216 -0
- package/dist/js/penrose/sounds.js +211 -0
- package/dist/js/penrose/voidparticle.js +55 -0
- package/dist/js/penrose/voidscene.js +258 -0
- package/dist/js/penrose/voidship.js +144 -0
- package/dist/js/penrose/wormhole.js +46 -0
- package/dist/js/pipeline.js +555 -0
- package/dist/js/plane3d.js +256 -0
- package/dist/js/platformer.js +1579 -0
- package/dist/js/scene.js +304 -0
- package/dist/js/scenes.js +320 -0
- package/dist/js/schrodinger.js +410 -0
- package/dist/js/schwarzschild.js +1015 -0
- package/dist/js/shapes.js +628 -0
- package/dist/js/space/alien.js +171 -0
- package/dist/js/space/boom.js +98 -0
- package/dist/js/space/boss.js +353 -0
- package/dist/js/space/buff.js +73 -0
- package/dist/js/space/bullet.js +102 -0
- package/dist/js/space/constants.js +85 -0
- package/dist/js/space/game.js +1884 -0
- package/dist/js/space/hud.js +112 -0
- package/dist/js/space/laserbeam.js +179 -0
- package/dist/js/space/lightning.js +277 -0
- package/dist/js/space/minion.js +192 -0
- package/dist/js/space/missile.js +212 -0
- package/dist/js/space/player.js +430 -0
- package/dist/js/space/powerup.js +90 -0
- package/dist/js/space/starfield.js +58 -0
- package/dist/js/space/starpower.js +90 -0
- package/dist/js/spacetime.js +559 -0
- package/dist/js/sphere3d.js +229 -0
- package/dist/js/sprite.js +473 -0
- package/dist/js/starfaux/config.js +118 -0
- package/dist/js/starfaux/enemy.js +353 -0
- package/dist/js/starfaux/hud.js +78 -0
- package/dist/js/starfaux/index.js +482 -0
- package/dist/js/starfaux/laser.js +182 -0
- package/dist/js/starfaux/player.js +468 -0
- package/dist/js/starfaux/terrain.js +560 -0
- package/dist/js/study001.js +275 -0
- package/dist/js/study002.js +366 -0
- package/dist/js/study003.js +331 -0
- package/dist/js/study004.js +389 -0
- package/dist/js/study005.js +209 -0
- package/dist/js/study006.js +194 -0
- package/dist/js/study007.js +192 -0
- package/dist/js/study008.js +413 -0
- package/dist/js/svgtween.js +204 -0
- package/dist/js/tde/accretiondisk.js +471 -0
- package/dist/js/tde/blackhole.js +219 -0
- package/dist/js/tde/blackholescene.js +209 -0
- package/dist/js/tde/config.js +59 -0
- package/dist/js/tde/index.js +820 -0
- package/dist/js/tde/jets.js +290 -0
- package/dist/js/tde/lensedstarfield.js +154 -0
- package/dist/js/tde/tdestar.js +297 -0
- package/dist/js/tde/tidalstream.js +372 -0
- package/dist/js/tde_old/blackhole.obj.js +354 -0
- package/dist/js/tde_old/debris.obj.js +791 -0
- package/dist/js/tde_old/flare.obj.js +239 -0
- package/dist/js/tde_old/index.js +448 -0
- package/dist/js/tde_old/star.obj.js +812 -0
- package/dist/js/tetris/config.js +157 -0
- package/dist/js/tetris/grid.js +286 -0
- package/dist/js/tetris/index.js +1195 -0
- package/dist/js/tetris/renderer.js +634 -0
- package/dist/js/tetris/tetrominos.js +280 -0
- package/dist/js/tiles.js +312 -0
- package/dist/js/tweendemo.js +79 -0
- package/dist/js/visibility.js +102 -0
- package/dist/kerr.html +28 -0
- package/dist/lavalamp.html +27 -0
- package/dist/layouts.html +37 -0
- package/dist/logo.svg +4 -0
- package/dist/loop.html +84 -0
- package/dist/mondrian.html +32 -0
- package/dist/og_image.png +0 -0
- package/dist/opacity.html +36 -0
- package/dist/painter.html +39 -0
- package/dist/particles-showcase.html +28 -0
- package/dist/particles.html +24 -0
- package/dist/patterns.html +33 -0
- package/dist/penrose-game.html +31 -0
- package/dist/pipeline.html +737 -0
- package/dist/plane3d.html +24 -0
- package/dist/platformer.html +43 -0
- package/dist/scene.html +33 -0
- package/dist/scenes.html +96 -0
- package/dist/schrodinger.html +27 -0
- package/dist/schwarzschild.html +27 -0
- package/dist/shapes.html +16 -0
- package/dist/space.html +85 -0
- package/dist/spacetime.html +27 -0
- package/dist/sphere3d.html +24 -0
- package/dist/sprite.html +18 -0
- package/dist/starfaux.html +22 -0
- package/dist/study001.html +23 -0
- package/dist/study002.html +23 -0
- package/dist/study003.html +23 -0
- package/dist/study004.html +23 -0
- package/dist/study005.html +22 -0
- package/dist/study006.html +24 -0
- package/dist/study007.html +24 -0
- package/dist/study008.html +22 -0
- package/dist/svgtween.html +29 -0
- package/dist/tde.html +28 -0
- package/dist/tetris3d.html +25 -0
- package/dist/tiles.html +28 -0
- package/dist/transforms.html +400 -0
- package/dist/tween.html +45 -0
- package/dist/visibility.html +33 -0
- package/package.json +1 -1
|
@@ -0,0 +1,840 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coordinate System Demo Initializations
|
|
3
|
+
*
|
|
4
|
+
* Each function creates an interactive demo on a specific canvas element,
|
|
5
|
+
* showcasing different aspects of GCanvas's coordinate system.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
Game,
|
|
10
|
+
Rectangle,
|
|
11
|
+
Circle,
|
|
12
|
+
Triangle,
|
|
13
|
+
TextShape,
|
|
14
|
+
Group,
|
|
15
|
+
Line,
|
|
16
|
+
Scene,
|
|
17
|
+
Painter,
|
|
18
|
+
GameObject,
|
|
19
|
+
Camera3D,
|
|
20
|
+
applyDraggable,
|
|
21
|
+
GameObjectShapeWrapper,
|
|
22
|
+
} from "/gcanvas.es.min.js";
|
|
23
|
+
|
|
24
|
+
// ─────────────────────────────────────────────────────────
|
|
25
|
+
// Demo 1: Center-Based Positioning
|
|
26
|
+
// Shows how x,y refers to center, not top-left
|
|
27
|
+
// ─────────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
function initCenterBasedDemo() {
|
|
30
|
+
const canvas = document.getElementById('center-based-canvas');
|
|
31
|
+
if (!canvas) return;
|
|
32
|
+
|
|
33
|
+
const game = new Game(canvas);
|
|
34
|
+
game.backgroundColor = '#000';
|
|
35
|
+
game.enableFluidSize(canvas.parentElement);
|
|
36
|
+
game.init();
|
|
37
|
+
|
|
38
|
+
let dragGO, shape, centerDot, boundsRect, labels;
|
|
39
|
+
|
|
40
|
+
const originalUpdate = game.update.bind(game);
|
|
41
|
+
|
|
42
|
+
game.update = function(dt) {
|
|
43
|
+
originalUpdate(dt);
|
|
44
|
+
|
|
45
|
+
if (!dragGO) {
|
|
46
|
+
const centerX = game.width / 2;
|
|
47
|
+
const centerY = game.height / 2;
|
|
48
|
+
|
|
49
|
+
// Create a Circle shape
|
|
50
|
+
shape = new Circle(50, {
|
|
51
|
+
color: 'rgba(0, 255, 0, 0.3)',
|
|
52
|
+
stroke: '#0f0',
|
|
53
|
+
lineWidth: 2
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Wrap it in a GameObjectShapeWrapper for interactivity
|
|
57
|
+
dragGO = new GameObjectShapeWrapper(game, shape, {
|
|
58
|
+
x: centerX,
|
|
59
|
+
y: centerY,
|
|
60
|
+
width: 100,
|
|
61
|
+
height: 100
|
|
62
|
+
});
|
|
63
|
+
dragGO.interactive = true;
|
|
64
|
+
|
|
65
|
+
// Make it draggable
|
|
66
|
+
applyDraggable(dragGO, {});
|
|
67
|
+
|
|
68
|
+
// Center point indicator
|
|
69
|
+
centerDot = new Circle(5, {
|
|
70
|
+
x: centerX,
|
|
71
|
+
y: centerY,
|
|
72
|
+
color: '#ff0',
|
|
73
|
+
stroke: '#ff0',
|
|
74
|
+
lineWidth: 1
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Bounding box visualization
|
|
78
|
+
boundsRect = new Rectangle({
|
|
79
|
+
x: centerX,
|
|
80
|
+
y: centerY,
|
|
81
|
+
width: 100,
|
|
82
|
+
height: 100,
|
|
83
|
+
color: null,
|
|
84
|
+
stroke: 'rgba(255, 255, 0, 0.5)',
|
|
85
|
+
lineWidth: 1
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Coordinate labels
|
|
89
|
+
labels = {
|
|
90
|
+
center: new TextShape('', {
|
|
91
|
+
x: centerX,
|
|
92
|
+
y: centerY - 60,
|
|
93
|
+
color: '#0f0',
|
|
94
|
+
font: '12px monospace',
|
|
95
|
+
align: 'center'
|
|
96
|
+
}),
|
|
97
|
+
left: new TextShape('', {
|
|
98
|
+
x: centerX - 60,
|
|
99
|
+
y: centerY,
|
|
100
|
+
color: '#888',
|
|
101
|
+
font: '10px monospace',
|
|
102
|
+
align: 'right'
|
|
103
|
+
}),
|
|
104
|
+
right: new TextShape('', {
|
|
105
|
+
x: centerX + 60,
|
|
106
|
+
y: centerY,
|
|
107
|
+
color: '#888',
|
|
108
|
+
font: '10px monospace',
|
|
109
|
+
align: 'left'
|
|
110
|
+
}),
|
|
111
|
+
top: new TextShape('', {
|
|
112
|
+
x: centerX,
|
|
113
|
+
y: centerY - 55,
|
|
114
|
+
color: '#888',
|
|
115
|
+
font: '10px monospace',
|
|
116
|
+
align: 'center'
|
|
117
|
+
}),
|
|
118
|
+
bottom: new TextShape('', {
|
|
119
|
+
x: centerX,
|
|
120
|
+
y: centerY + 60,
|
|
121
|
+
color: '#888',
|
|
122
|
+
font: '10px monospace',
|
|
123
|
+
align: 'center'
|
|
124
|
+
})
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
game.pipeline.add(boundsRect);
|
|
128
|
+
game.pipeline.add(dragGO);
|
|
129
|
+
game.pipeline.add(centerDot);
|
|
130
|
+
Object.values(labels).forEach(l => game.pipeline.add(l));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Update positions to follow the dragged object
|
|
134
|
+
centerDot.x = dragGO.x;
|
|
135
|
+
centerDot.y = dragGO.y;
|
|
136
|
+
boundsRect.x = dragGO.x;
|
|
137
|
+
boundsRect.y = dragGO.y;
|
|
138
|
+
|
|
139
|
+
// Update labels
|
|
140
|
+
const radius = 50;
|
|
141
|
+
labels.center.x = dragGO.x;
|
|
142
|
+
labels.center.y = dragGO.y - radius - 15;
|
|
143
|
+
labels.center.text = `Center: (${Math.round(dragGO.x)}, ${Math.round(dragGO.y)})`;
|
|
144
|
+
|
|
145
|
+
labels.left.x = dragGO.x - radius - 5;
|
|
146
|
+
labels.left.y = dragGO.y;
|
|
147
|
+
labels.left.text = `${Math.round(dragGO.x - radius)}`;
|
|
148
|
+
|
|
149
|
+
labels.right.x = dragGO.x + radius + 5;
|
|
150
|
+
labels.right.y = dragGO.y;
|
|
151
|
+
labels.right.text = `${Math.round(dragGO.x + radius)}`;
|
|
152
|
+
|
|
153
|
+
labels.top.x = dragGO.x;
|
|
154
|
+
labels.top.y = dragGO.y - radius - 5;
|
|
155
|
+
labels.top.text = `${Math.round(dragGO.y - radius)}`;
|
|
156
|
+
|
|
157
|
+
labels.bottom.x = dragGO.x;
|
|
158
|
+
labels.bottom.y = dragGO.y + radius + 15;
|
|
159
|
+
labels.bottom.text = `${Math.round(dragGO.y + radius)}`;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
game.start();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ─────────────────────────────────────────────────────────
|
|
166
|
+
// Demo 2: Basic Screen Coordinates
|
|
167
|
+
// Click to place shapes at screen positions
|
|
168
|
+
// ─────────────────────────────────────────────────────────
|
|
169
|
+
|
|
170
|
+
function initBasicPositionDemo() {
|
|
171
|
+
const canvas = document.getElementById('basic-position-canvas');
|
|
172
|
+
if (!canvas) return;
|
|
173
|
+
|
|
174
|
+
const game = new Game(canvas);
|
|
175
|
+
game.backgroundColor = '#000';
|
|
176
|
+
game.enableFluidSize(canvas.parentElement);
|
|
177
|
+
game.init();
|
|
178
|
+
|
|
179
|
+
const shapes = [];
|
|
180
|
+
let coordLabel;
|
|
181
|
+
let axisLines = [];
|
|
182
|
+
let clickCount = 0;
|
|
183
|
+
|
|
184
|
+
// Draw coordinate axis
|
|
185
|
+
class AxisGameObject extends GameObject {
|
|
186
|
+
constructor(game) {
|
|
187
|
+
super(game, {});
|
|
188
|
+
this.zIndex = -100;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
draw() {
|
|
192
|
+
super.draw();
|
|
193
|
+
Painter.useCtx((ctx) => {
|
|
194
|
+
// Origin marker
|
|
195
|
+
ctx.fillStyle = '#0f0';
|
|
196
|
+
ctx.font = '12px monospace';
|
|
197
|
+
ctx.fillText('(0,0)', 5, 15);
|
|
198
|
+
|
|
199
|
+
// X axis arrow
|
|
200
|
+
ctx.strokeStyle = '#0f0';
|
|
201
|
+
ctx.lineWidth = 1;
|
|
202
|
+
ctx.beginPath();
|
|
203
|
+
ctx.moveTo(0, 0);
|
|
204
|
+
ctx.lineTo(80, 0);
|
|
205
|
+
ctx.stroke();
|
|
206
|
+
ctx.fillText('X →', 85, 5);
|
|
207
|
+
|
|
208
|
+
// Y axis arrow
|
|
209
|
+
ctx.beginPath();
|
|
210
|
+
ctx.moveTo(0, 0);
|
|
211
|
+
ctx.lineTo(0, 80);
|
|
212
|
+
ctx.stroke();
|
|
213
|
+
ctx.save();
|
|
214
|
+
ctx.translate(5, 90);
|
|
215
|
+
ctx.fillText('Y ↓', 0, 0);
|
|
216
|
+
ctx.restore();
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
game.pipeline.add(new AxisGameObject(game));
|
|
222
|
+
|
|
223
|
+
// Coordinate display
|
|
224
|
+
coordLabel = new TextShape('Click to place shapes', {
|
|
225
|
+
x: game.width / 2,
|
|
226
|
+
y: 20,
|
|
227
|
+
color: '#0f0',
|
|
228
|
+
font: '14px monospace',
|
|
229
|
+
align: 'center'
|
|
230
|
+
});
|
|
231
|
+
game.pipeline.add(coordLabel);
|
|
232
|
+
|
|
233
|
+
// Handle clicks
|
|
234
|
+
canvas.addEventListener('click', (e) => {
|
|
235
|
+
const rect = canvas.getBoundingClientRect();
|
|
236
|
+
const scaleX = canvas.width / rect.width;
|
|
237
|
+
const scaleY = canvas.height / rect.height;
|
|
238
|
+
const x = (e.clientX - rect.left) * scaleX;
|
|
239
|
+
const y = (e.clientY - rect.top) * scaleY;
|
|
240
|
+
|
|
241
|
+
// Alternate between shapes using click counter (not array length)
|
|
242
|
+
clickCount++;
|
|
243
|
+
const shapeTypes = ['circle', 'rect', 'triangle'];
|
|
244
|
+
const type = shapeTypes[clickCount % 3];
|
|
245
|
+
const colors = ['#0ff', '#f0f', '#ff0'];
|
|
246
|
+
const color = colors[clickCount % 3];
|
|
247
|
+
|
|
248
|
+
let shape;
|
|
249
|
+
if (type === 'circle') {
|
|
250
|
+
shape = new Circle(15, { x, y, color, stroke: '#0f0', lineWidth: 1 });
|
|
251
|
+
} else if (type === 'rect') {
|
|
252
|
+
shape = new Rectangle({ x, y, width: 30, height: 20, color, stroke: '#0f0', lineWidth: 1 });
|
|
253
|
+
} else {
|
|
254
|
+
shape = new Triangle(20, { x, y, color, stroke: '#0f0', lineWidth: 1 });
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Add coordinate label
|
|
258
|
+
const label = new TextShape(`(${Math.round(x)}, ${Math.round(y)})`, {
|
|
259
|
+
x: x,
|
|
260
|
+
y: y + 25,
|
|
261
|
+
color: '#888',
|
|
262
|
+
font: '10px monospace',
|
|
263
|
+
align: 'center'
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
shapes.push({ shape, label });
|
|
267
|
+
game.pipeline.add(shape);
|
|
268
|
+
game.pipeline.add(label);
|
|
269
|
+
|
|
270
|
+
// Keep only last 5 shapes
|
|
271
|
+
if (shapes.length > 5) {
|
|
272
|
+
const removed = shapes.shift();
|
|
273
|
+
game.pipeline.remove(removed.shape);
|
|
274
|
+
game.pipeline.remove(removed.label);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
coordLabel.text = `Last click: (${Math.round(x)}, ${Math.round(y)})`;
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
const originalUpdate = game.update.bind(game);
|
|
281
|
+
game.update = function(dt) {
|
|
282
|
+
originalUpdate(dt);
|
|
283
|
+
coordLabel.x = game.width / 2;
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
game.start();
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// ─────────────────────────────────────────────────────────
|
|
290
|
+
// Demo 3: Parent-Child Relationships
|
|
291
|
+
// Draggable scene with children that follow
|
|
292
|
+
// ─────────────────────────────────────────────────────────
|
|
293
|
+
|
|
294
|
+
function initParentChildDemo() {
|
|
295
|
+
const canvas = document.getElementById('parent-child-canvas');
|
|
296
|
+
if (!canvas) return;
|
|
297
|
+
|
|
298
|
+
const game = new Game(canvas);
|
|
299
|
+
game.backgroundColor = '#000';
|
|
300
|
+
game.enableFluidSize(canvas.parentElement);
|
|
301
|
+
game.init();
|
|
302
|
+
|
|
303
|
+
let dragGO, sceneGroup, child1, child2, child3, sceneLabel, child1Label;
|
|
304
|
+
|
|
305
|
+
const originalUpdate = game.update.bind(game);
|
|
306
|
+
|
|
307
|
+
game.update = function(dt) {
|
|
308
|
+
originalUpdate(dt);
|
|
309
|
+
|
|
310
|
+
if (!dragGO) {
|
|
311
|
+
const centerX = game.width / 2;
|
|
312
|
+
const centerY = game.height / 2;
|
|
313
|
+
|
|
314
|
+
// Create a Group with all the visual elements
|
|
315
|
+
sceneGroup = new Group();
|
|
316
|
+
|
|
317
|
+
// Scene background (for visualization)
|
|
318
|
+
const sceneBg = new Rectangle({
|
|
319
|
+
x: 0, y: 0,
|
|
320
|
+
width: 150, height: 120,
|
|
321
|
+
color: 'rgba(0, 255, 0, 0.1)',
|
|
322
|
+
stroke: '#0f0',
|
|
323
|
+
lineWidth: 2
|
|
324
|
+
});
|
|
325
|
+
sceneGroup.add(sceneBg);
|
|
326
|
+
|
|
327
|
+
// Scene center marker
|
|
328
|
+
const sceneCenter = new Circle(3, {
|
|
329
|
+
x: 0, y: 0,
|
|
330
|
+
color: '#0f0'
|
|
331
|
+
});
|
|
332
|
+
sceneGroup.add(sceneCenter);
|
|
333
|
+
|
|
334
|
+
// Children at local positions
|
|
335
|
+
child1 = new Circle(15, {
|
|
336
|
+
x: 40, y: 20,
|
|
337
|
+
color: '#0ff',
|
|
338
|
+
stroke: '#0ff',
|
|
339
|
+
lineWidth: 1
|
|
340
|
+
});
|
|
341
|
+
sceneGroup.add(child1);
|
|
342
|
+
|
|
343
|
+
child2 = new Circle(12, {
|
|
344
|
+
x: -30, y: 30,
|
|
345
|
+
color: '#f0f',
|
|
346
|
+
stroke: '#f0f',
|
|
347
|
+
lineWidth: 1
|
|
348
|
+
});
|
|
349
|
+
sceneGroup.add(child2);
|
|
350
|
+
|
|
351
|
+
child3 = new Rectangle({
|
|
352
|
+
x: 0, y: -35,
|
|
353
|
+
width: 40, height: 20,
|
|
354
|
+
color: '#ff0',
|
|
355
|
+
stroke: '#ff0',
|
|
356
|
+
lineWidth: 1
|
|
357
|
+
});
|
|
358
|
+
sceneGroup.add(child3);
|
|
359
|
+
|
|
360
|
+
// Wrap in GameObjectShapeWrapper for interactivity
|
|
361
|
+
dragGO = new GameObjectShapeWrapper(game, sceneGroup, {
|
|
362
|
+
x: centerX,
|
|
363
|
+
y: centerY,
|
|
364
|
+
width: 150,
|
|
365
|
+
height: 120
|
|
366
|
+
});
|
|
367
|
+
dragGO.interactive = true;
|
|
368
|
+
|
|
369
|
+
// Make it draggable
|
|
370
|
+
applyDraggable(dragGO, {});
|
|
371
|
+
|
|
372
|
+
// Labels
|
|
373
|
+
sceneLabel = new TextShape('', {
|
|
374
|
+
x: centerX,
|
|
375
|
+
y: centerY - 80,
|
|
376
|
+
color: '#0f0',
|
|
377
|
+
font: '12px monospace',
|
|
378
|
+
align: 'center'
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
child1Label = new TextShape('', {
|
|
382
|
+
x: centerX + 40,
|
|
383
|
+
y: centerY + 20 + 25,
|
|
384
|
+
color: '#0ff',
|
|
385
|
+
font: '10px monospace',
|
|
386
|
+
align: 'center'
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
game.pipeline.add(dragGO);
|
|
390
|
+
game.pipeline.add(sceneLabel);
|
|
391
|
+
game.pipeline.add(child1Label);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Update labels
|
|
395
|
+
sceneLabel.x = dragGO.x;
|
|
396
|
+
sceneLabel.y = dragGO.y - 80;
|
|
397
|
+
sceneLabel.text = `Scene: (${Math.round(dragGO.x)}, ${Math.round(dragGO.y)})`;
|
|
398
|
+
|
|
399
|
+
child1Label.x = dragGO.x + child1.x;
|
|
400
|
+
child1Label.y = dragGO.y + child1.y + 25;
|
|
401
|
+
child1Label.text = `Local: (${child1.x}, ${child1.y}) → Screen: (${Math.round(dragGO.x + child1.x)}, ${Math.round(dragGO.y + child1.y)})`;
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
game.start();
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// ─────────────────────────────────────────────────────────
|
|
408
|
+
// Demo 4: Nested Hierarchy
|
|
409
|
+
// Multi-level nesting demonstration
|
|
410
|
+
// ─────────────────────────────────────────────────────────
|
|
411
|
+
|
|
412
|
+
function initNestedDemo() {
|
|
413
|
+
const canvas = document.getElementById('nested-canvas');
|
|
414
|
+
if (!canvas) return;
|
|
415
|
+
|
|
416
|
+
const game = new Game(canvas);
|
|
417
|
+
game.backgroundColor = '#000';
|
|
418
|
+
game.enableFluidSize(canvas.parentElement);
|
|
419
|
+
game.init();
|
|
420
|
+
|
|
421
|
+
let dragGO, outerGroup, innerGroup, deepest, labels;
|
|
422
|
+
// Store offsets for nested elements
|
|
423
|
+
const innerOffset = { x: 40, y: 20 };
|
|
424
|
+
const deepestOffset = { x: 20, y: 15 };
|
|
425
|
+
|
|
426
|
+
const originalUpdate = game.update.bind(game);
|
|
427
|
+
|
|
428
|
+
game.update = function(dt) {
|
|
429
|
+
originalUpdate(dt);
|
|
430
|
+
|
|
431
|
+
if (!dragGO) {
|
|
432
|
+
const startX = game.width / 3;
|
|
433
|
+
const startY = game.height / 2;
|
|
434
|
+
|
|
435
|
+
// Create nested group structure for visualization
|
|
436
|
+
outerGroup = new Group();
|
|
437
|
+
|
|
438
|
+
// Outer background
|
|
439
|
+
const outerBg = new Rectangle({
|
|
440
|
+
x: 0, y: 0, width: 180, height: 140,
|
|
441
|
+
color: 'rgba(0, 255, 0, 0.1)',
|
|
442
|
+
stroke: '#0f0',
|
|
443
|
+
lineWidth: 2
|
|
444
|
+
});
|
|
445
|
+
outerGroup.add(outerBg);
|
|
446
|
+
outerGroup.add(new TextShape('Outer (0,0)', { x: 0, y: -50, color: '#0f0', font: '10px monospace', align: 'center' }));
|
|
447
|
+
|
|
448
|
+
// Inner group (offset from outer)
|
|
449
|
+
innerGroup = new Group({ x: innerOffset.x, y: innerOffset.y });
|
|
450
|
+
const innerBg = new Rectangle({
|
|
451
|
+
x: 0, y: 0, width: 100, height: 80,
|
|
452
|
+
color: 'rgba(0, 255, 255, 0.1)',
|
|
453
|
+
stroke: '#0ff',
|
|
454
|
+
lineWidth: 2
|
|
455
|
+
});
|
|
456
|
+
innerGroup.add(innerBg);
|
|
457
|
+
innerGroup.add(new TextShape('Inner (+40,+20)', { x: 0, y: -25, color: '#0ff', font: '10px monospace', align: 'center' }));
|
|
458
|
+
|
|
459
|
+
// Deepest shape (offset from inner)
|
|
460
|
+
deepest = new Circle(12, {
|
|
461
|
+
x: deepestOffset.x, y: deepestOffset.y,
|
|
462
|
+
color: '#ff0',
|
|
463
|
+
stroke: '#ff0',
|
|
464
|
+
lineWidth: 1
|
|
465
|
+
});
|
|
466
|
+
innerGroup.add(deepest);
|
|
467
|
+
innerGroup.add(new TextShape('Shape (+20,+15)', { x: deepestOffset.x, y: deepestOffset.y + 20, color: '#ff0', font: '9px monospace', align: 'center' }));
|
|
468
|
+
|
|
469
|
+
outerGroup.add(innerGroup);
|
|
470
|
+
|
|
471
|
+
// Wrap in GameObjectShapeWrapper for interactivity
|
|
472
|
+
dragGO = new GameObjectShapeWrapper(game, outerGroup, {
|
|
473
|
+
x: startX,
|
|
474
|
+
y: startY,
|
|
475
|
+
width: 180,
|
|
476
|
+
height: 140
|
|
477
|
+
});
|
|
478
|
+
dragGO.interactive = true;
|
|
479
|
+
applyDraggable(dragGO, {});
|
|
480
|
+
game.pipeline.add(dragGO);
|
|
481
|
+
|
|
482
|
+
// Calculation display
|
|
483
|
+
labels = {
|
|
484
|
+
calc: new TextShape('', {
|
|
485
|
+
x: game.width * 0.75,
|
|
486
|
+
y: game.height / 2 - 40,
|
|
487
|
+
color: '#888',
|
|
488
|
+
font: '11px monospace',
|
|
489
|
+
align: 'center'
|
|
490
|
+
}),
|
|
491
|
+
result: new TextShape('', {
|
|
492
|
+
x: game.width * 0.75,
|
|
493
|
+
y: game.height / 2,
|
|
494
|
+
color: '#ff0',
|
|
495
|
+
font: '14px monospace',
|
|
496
|
+
align: 'center'
|
|
497
|
+
})
|
|
498
|
+
};
|
|
499
|
+
game.pipeline.add(labels.calc);
|
|
500
|
+
game.pipeline.add(labels.result);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Update calculation display
|
|
504
|
+
const screenX = Math.round(dragGO.x + innerOffset.x + deepestOffset.x);
|
|
505
|
+
const screenY = Math.round(dragGO.y + innerOffset.y + deepestOffset.y);
|
|
506
|
+
|
|
507
|
+
labels.calc.x = game.width * 0.7;
|
|
508
|
+
labels.calc.text = `Outer(${Math.round(dragGO.x)},${Math.round(dragGO.y)}) + Inner(${innerOffset.x},${innerOffset.y}) + Shape(${deepestOffset.x},${deepestOffset.y})`;
|
|
509
|
+
|
|
510
|
+
labels.result.x = game.width * 0.7;
|
|
511
|
+
labels.result.text = `= Screen Position (${screenX}, ${screenY})`;
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
game.start();
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// ─────────────────────────────────────────────────────────
|
|
518
|
+
// Demo 5: Camera3D Projection
|
|
519
|
+
// 3D projection with mouse rotation
|
|
520
|
+
// ─────────────────────────────────────────────────────────
|
|
521
|
+
|
|
522
|
+
function initCamera3dDemo() {
|
|
523
|
+
const canvas = document.getElementById('camera3d-canvas');
|
|
524
|
+
if (!canvas) return;
|
|
525
|
+
|
|
526
|
+
const game = new Game(canvas);
|
|
527
|
+
game.backgroundColor = '#000';
|
|
528
|
+
game.enableFluidSize(canvas.parentElement);
|
|
529
|
+
game.init();
|
|
530
|
+
|
|
531
|
+
const camera = new Camera3D({
|
|
532
|
+
perspective: 400,
|
|
533
|
+
rotationY: 0.3,
|
|
534
|
+
rotationX: 0.2,
|
|
535
|
+
inertia: true,
|
|
536
|
+
friction: 0.95
|
|
537
|
+
});
|
|
538
|
+
camera.enableMouseControl(canvas);
|
|
539
|
+
|
|
540
|
+
// 3D points to project
|
|
541
|
+
const points3D = [
|
|
542
|
+
{ x: 0, y: 0, z: 0, color: '#0f0', label: 'Origin' },
|
|
543
|
+
{ x: 80, y: 0, z: 0, color: '#f00', label: '+X' },
|
|
544
|
+
{ x: 0, y: -80, z: 0, color: '#0ff', label: '+Y' },
|
|
545
|
+
{ x: 0, y: 0, z: 80, color: '#ff0', label: '+Z' },
|
|
546
|
+
{ x: -60, y: -40, z: 40, color: '#f0f', label: 'Point A' },
|
|
547
|
+
{ x: 60, y: 40, z: -40, color: '#fff', label: 'Point B' },
|
|
548
|
+
];
|
|
549
|
+
|
|
550
|
+
// Axis lines
|
|
551
|
+
const axisLines = [
|
|
552
|
+
{ from: { x: -100, y: 0, z: 0 }, to: { x: 100, y: 0, z: 0 }, color: '#f00' },
|
|
553
|
+
{ from: { x: 0, y: -100, z: 0 }, to: { x: 0, y: 100, z: 0 }, color: '#0ff' },
|
|
554
|
+
{ from: { x: 0, y: 0, z: -100 }, to: { x: 0, y: 0, z: 100 }, color: '#ff0' },
|
|
555
|
+
];
|
|
556
|
+
|
|
557
|
+
const originalUpdate = game.update.bind(game);
|
|
558
|
+
const originalRender = game.render.bind(game);
|
|
559
|
+
|
|
560
|
+
game.update = function(dt) {
|
|
561
|
+
originalUpdate(dt);
|
|
562
|
+
camera.update(dt);
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
game.render = function() {
|
|
566
|
+
originalRender();
|
|
567
|
+
|
|
568
|
+
const centerX = game.width / 2;
|
|
569
|
+
const centerY = game.height / 2;
|
|
570
|
+
|
|
571
|
+
Painter.useCtx((ctx) => {
|
|
572
|
+
ctx.save();
|
|
573
|
+
ctx.translate(centerX, centerY);
|
|
574
|
+
|
|
575
|
+
// Draw axis lines
|
|
576
|
+
ctx.lineWidth = 1;
|
|
577
|
+
for (const line of axisLines) {
|
|
578
|
+
const from = camera.project(line.from.x, line.from.y, line.from.z);
|
|
579
|
+
const to = camera.project(line.to.x, line.to.y, line.to.z);
|
|
580
|
+
ctx.strokeStyle = line.color;
|
|
581
|
+
ctx.globalAlpha = 0.3;
|
|
582
|
+
ctx.beginPath();
|
|
583
|
+
ctx.moveTo(from.x, from.y);
|
|
584
|
+
ctx.lineTo(to.x, to.y);
|
|
585
|
+
ctx.stroke();
|
|
586
|
+
}
|
|
587
|
+
ctx.globalAlpha = 1;
|
|
588
|
+
|
|
589
|
+
// Sort points by z for proper depth ordering
|
|
590
|
+
const projected = points3D.map(p => ({
|
|
591
|
+
...p,
|
|
592
|
+
proj: camera.project(p.x, p.y, p.z)
|
|
593
|
+
})).sort((a, b) => b.proj.z - a.proj.z);
|
|
594
|
+
|
|
595
|
+
// Draw points
|
|
596
|
+
for (const p of projected) {
|
|
597
|
+
const { x, y, scale } = p.proj;
|
|
598
|
+
const radius = Math.max(3, 8 * scale);
|
|
599
|
+
|
|
600
|
+
ctx.fillStyle = p.color;
|
|
601
|
+
ctx.beginPath();
|
|
602
|
+
ctx.arc(x, y, radius, 0, Math.PI * 2);
|
|
603
|
+
ctx.fill();
|
|
604
|
+
|
|
605
|
+
// Label
|
|
606
|
+
ctx.font = `${Math.max(8, 12 * scale)}px monospace`;
|
|
607
|
+
ctx.fillStyle = p.color;
|
|
608
|
+
ctx.textAlign = 'left';
|
|
609
|
+
ctx.fillText(p.label, x + radius + 5, y + 4);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
ctx.restore();
|
|
613
|
+
|
|
614
|
+
// Info text
|
|
615
|
+
ctx.fillStyle = '#888';
|
|
616
|
+
ctx.font = '11px monospace';
|
|
617
|
+
ctx.textAlign = 'left';
|
|
618
|
+
ctx.fillText(`Camera rotation: Y=${camera.rotationY.toFixed(2)}, X=${camera.rotationX.toFixed(2)}`, 10, 20);
|
|
619
|
+
ctx.fillText('Scene3D centered at canvas center', 10, 35);
|
|
620
|
+
ctx.fillText('Origin (0,0,0) appears at center', 10, 50);
|
|
621
|
+
});
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
game.start();
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// ─────────────────────────────────────────────────────────
|
|
628
|
+
// Demo 6: Anchor Positions
|
|
629
|
+
// Shows all anchor positions
|
|
630
|
+
// ─────────────────────────────────────────────────────────
|
|
631
|
+
|
|
632
|
+
function initAnchorDemo() {
|
|
633
|
+
const canvas = document.getElementById('anchor-canvas');
|
|
634
|
+
if (!canvas) return;
|
|
635
|
+
|
|
636
|
+
const game = new Game(canvas);
|
|
637
|
+
game.backgroundColor = '#000';
|
|
638
|
+
game.enableFluidSize(canvas.parentElement);
|
|
639
|
+
game.init();
|
|
640
|
+
|
|
641
|
+
const anchors = [
|
|
642
|
+
{ name: 'TOP_LEFT', getPos: (w, h, m) => ({ x: m, y: m }) },
|
|
643
|
+
{ name: 'TOP_CENTER', getPos: (w, h, m) => ({ x: w / 2, y: m }) },
|
|
644
|
+
{ name: 'TOP_RIGHT', getPos: (w, h, m) => ({ x: w - m, y: m }) },
|
|
645
|
+
{ name: 'CENTER_LEFT', getPos: (w, h, m) => ({ x: m, y: h / 2 }) },
|
|
646
|
+
{ name: 'CENTER', getPos: (w, h, m) => ({ x: w / 2, y: h / 2 }) },
|
|
647
|
+
{ name: 'CENTER_RIGHT', getPos: (w, h, m) => ({ x: w - m, y: h / 2 }) },
|
|
648
|
+
{ name: 'BOTTOM_LEFT', getPos: (w, h, m) => ({ x: m, y: h - m }) },
|
|
649
|
+
{ name: 'BOTTOM_CENTER', getPos: (w, h, m) => ({ x: w / 2, y: h - m }) },
|
|
650
|
+
{ name: 'BOTTOM_RIGHT', getPos: (w, h, m) => ({ x: w - m, y: h - m }) },
|
|
651
|
+
];
|
|
652
|
+
|
|
653
|
+
const margin = 30;
|
|
654
|
+
const labels = [];
|
|
655
|
+
const dots = [];
|
|
656
|
+
|
|
657
|
+
const originalUpdate = game.update.bind(game);
|
|
658
|
+
let initialized = false;
|
|
659
|
+
|
|
660
|
+
game.update = function(dt) {
|
|
661
|
+
originalUpdate(dt);
|
|
662
|
+
|
|
663
|
+
if (!initialized) {
|
|
664
|
+
for (const anchor of anchors) {
|
|
665
|
+
const pos = anchor.getPos(game.width, game.height, margin);
|
|
666
|
+
|
|
667
|
+
const dot = new Circle(5, {
|
|
668
|
+
x: pos.x,
|
|
669
|
+
y: pos.y,
|
|
670
|
+
color: '#0f0'
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
const label = new TextShape(anchor.name, {
|
|
674
|
+
x: pos.x,
|
|
675
|
+
y: pos.y + 15,
|
|
676
|
+
color: '#888',
|
|
677
|
+
font: '9px monospace',
|
|
678
|
+
align: 'center'
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
dots.push({ anchor, dot });
|
|
682
|
+
labels.push({ anchor, label });
|
|
683
|
+
|
|
684
|
+
game.pipeline.add(dot);
|
|
685
|
+
game.pipeline.add(label);
|
|
686
|
+
}
|
|
687
|
+
initialized = true;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// Update positions on resize
|
|
691
|
+
for (const { anchor, dot } of dots) {
|
|
692
|
+
const pos = anchor.getPos(game.width, game.height, margin);
|
|
693
|
+
dot.x = pos.x;
|
|
694
|
+
dot.y = pos.y;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
for (const { anchor, label } of labels) {
|
|
698
|
+
const pos = anchor.getPos(game.width, game.height, margin);
|
|
699
|
+
label.x = pos.x;
|
|
700
|
+
label.y = pos.y + 15;
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
|
|
704
|
+
game.start();
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// ─────────────────────────────────────────────────────────
|
|
708
|
+
// Demo 7: Vertical Layout
|
|
709
|
+
// Interactive layout with add/remove
|
|
710
|
+
// ─────────────────────────────────────────────────────────
|
|
711
|
+
|
|
712
|
+
function initLayoutDemo() {
|
|
713
|
+
const canvas = document.getElementById('layout-canvas');
|
|
714
|
+
if (!canvas) return;
|
|
715
|
+
|
|
716
|
+
const game = new Game(canvas);
|
|
717
|
+
game.backgroundColor = '#000';
|
|
718
|
+
game.enableFluidSize(canvas.parentElement);
|
|
719
|
+
game.init();
|
|
720
|
+
|
|
721
|
+
const items = [];
|
|
722
|
+
const spacing = 12;
|
|
723
|
+
let itemCount = 0;
|
|
724
|
+
|
|
725
|
+
function addItem() {
|
|
726
|
+
itemCount++;
|
|
727
|
+
const colors = ['#0ff', '#f0f', '#ff0', '#0f0', '#f00'];
|
|
728
|
+
const color = colors[(itemCount - 1) % colors.length];
|
|
729
|
+
|
|
730
|
+
const rect = new Rectangle({
|
|
731
|
+
x: 0, y: 0,
|
|
732
|
+
width: 100 + Math.random() * 50,
|
|
733
|
+
height: 25,
|
|
734
|
+
color: color,
|
|
735
|
+
stroke: '#fff',
|
|
736
|
+
lineWidth: 1
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
const label = new TextShape(`Item ${itemCount}`, {
|
|
740
|
+
x: 0, y: 0,
|
|
741
|
+
color: '#000',
|
|
742
|
+
font: '12px monospace',
|
|
743
|
+
align: 'center',
|
|
744
|
+
baseline: 'middle'
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
const group = new Group({ x: 0, y: 0 });
|
|
748
|
+
group.add(rect);
|
|
749
|
+
group.add(label);
|
|
750
|
+
|
|
751
|
+
items.push({ group, rect, label });
|
|
752
|
+
game.pipeline.add(group);
|
|
753
|
+
updateLayout();
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
function removeItem() {
|
|
757
|
+
if (items.length > 0) {
|
|
758
|
+
const removed = items.pop();
|
|
759
|
+
game.pipeline.remove(removed.group);
|
|
760
|
+
updateLayout();
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
function updateLayout() {
|
|
765
|
+
const centerX = game.width / 2;
|
|
766
|
+
let totalHeight = 0;
|
|
767
|
+
|
|
768
|
+
// Calculate total height
|
|
769
|
+
for (const item of items) {
|
|
770
|
+
totalHeight += item.rect.height;
|
|
771
|
+
}
|
|
772
|
+
totalHeight += (items.length - 1) * spacing;
|
|
773
|
+
|
|
774
|
+
// Position items
|
|
775
|
+
let y = (game.height - totalHeight) / 2;
|
|
776
|
+
for (const item of items) {
|
|
777
|
+
item.group.x = centerX;
|
|
778
|
+
item.group.y = y + item.rect.height / 2;
|
|
779
|
+
y += item.rect.height + spacing;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Add initial items
|
|
784
|
+
for (let i = 0; i < 3; i++) {
|
|
785
|
+
addItem();
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// Click handlers
|
|
789
|
+
canvas.addEventListener('click', (e) => {
|
|
790
|
+
const rect = canvas.getBoundingClientRect();
|
|
791
|
+
const x = (e.clientX - rect.left) * (canvas.width / rect.width);
|
|
792
|
+
|
|
793
|
+
if (x < canvas.width / 2) {
|
|
794
|
+
addItem();
|
|
795
|
+
} else {
|
|
796
|
+
removeItem();
|
|
797
|
+
}
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
// Instructions
|
|
801
|
+
const leftLabel = new TextShape('Click LEFT to add', {
|
|
802
|
+
x: 10, y: 20,
|
|
803
|
+
color: '#0f0',
|
|
804
|
+
font: '12px monospace',
|
|
805
|
+
align: 'left'
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
const rightLabel = new TextShape('Click RIGHT to remove', {
|
|
809
|
+
x: game.width - 10, y: 20,
|
|
810
|
+
color: '#f00',
|
|
811
|
+
font: '12px monospace',
|
|
812
|
+
align: 'right'
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
game.pipeline.add(leftLabel);
|
|
816
|
+
game.pipeline.add(rightLabel);
|
|
817
|
+
|
|
818
|
+
const originalUpdate = game.update.bind(game);
|
|
819
|
+
game.update = function(dt) {
|
|
820
|
+
originalUpdate(dt);
|
|
821
|
+
rightLabel.x = game.width - 10;
|
|
822
|
+
updateLayout();
|
|
823
|
+
};
|
|
824
|
+
|
|
825
|
+
game.start();
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// ─────────────────────────────────────────────────────────
|
|
829
|
+
// Initialize all demos on page load
|
|
830
|
+
// ─────────────────────────────────────────────────────────
|
|
831
|
+
|
|
832
|
+
window.addEventListener('load', () => {
|
|
833
|
+
initCenterBasedDemo();
|
|
834
|
+
initBasicPositionDemo();
|
|
835
|
+
initParentChildDemo();
|
|
836
|
+
initNestedDemo();
|
|
837
|
+
initCamera3dDemo();
|
|
838
|
+
initAnchorDemo();
|
|
839
|
+
initLayoutDemo();
|
|
840
|
+
});
|