@guinetik/gcanvas 1.0.4 → 2.0.0
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/aizawa.html +27 -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/clifford.html +25 -0
- package/dist/cmb.html +24 -0
- package/dist/coordinates.html +698 -0
- package/dist/cube3d.html +23 -0
- package/dist/dadras.html +26 -0
- package/dist/dejong.html +25 -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 +14368 -9093
- 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/halvorsen.html +27 -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 +446 -0
- package/dist/isometric.html +34 -0
- package/dist/js/aizawa.js +425 -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/clifford.js +236 -0
- package/dist/js/cmb.js +594 -0
- package/dist/js/coordinates.js +840 -0
- package/dist/js/cube3d.js +789 -0
- package/dist/js/dadras.js +405 -0
- package/dist/js/dejong.js +257 -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/halvorsen.js +405 -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 +851 -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/lorenz.js +425 -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/rossler.js +480 -0
- package/dist/js/scene.js +304 -0
- package/dist/js/scenes.js +320 -0
- package/dist/js/schrodinger.js +706 -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/thomas.js +394 -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/lorenz.html +27 -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/rossler.html +27 -0
- package/dist/scene-interactivity-test.html +220 -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/thomas.html +27 -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
- package/readme.md +30 -22
- package/src/game/objects/go.js +7 -0
- package/src/game/objects/index.js +2 -0
- package/src/game/objects/isometric-scene.js +53 -3
- package/src/game/objects/layoutscene.js +57 -0
- package/src/game/objects/mask.js +241 -0
- package/src/game/objects/scene.js +19 -0
- package/src/game/objects/wrapper.js +14 -2
- package/src/game/pipeline.js +17 -0
- package/src/game/ui/button.js +101 -16
- package/src/game/ui/theme.js +0 -6
- package/src/game/ui/togglebutton.js +25 -14
- package/src/game/ui/tooltip.js +12 -4
- package/src/index.js +3 -0
- package/src/io/gesture.js +409 -0
- package/src/io/index.js +4 -1
- package/src/io/keys.js +9 -1
- package/src/io/screen.js +476 -0
- package/src/math/attractors.js +664 -0
- package/src/math/heat.js +106 -0
- package/src/math/index.js +1 -0
- package/src/mixins/draggable.js +15 -19
- package/src/painter/painter.shapes.js +11 -5
- package/src/particle/particle-system.js +165 -1
- package/src/physics/index.js +26 -0
- package/src/physics/physics-updaters.js +333 -0
- package/src/physics/physics.js +375 -0
- package/src/shapes/image.js +5 -5
- package/src/shapes/index.js +2 -0
- package/src/shapes/parallelogram.js +147 -0
- package/src/shapes/righttriangle.js +115 -0
- package/src/shapes/svg.js +281 -100
- package/src/shapes/text.js +22 -6
- package/src/shapes/transformable.js +5 -0
- package/src/sound/effects.js +807 -0
- package/src/sound/index.js +13 -0
- package/src/webgl/index.js +7 -0
- package/src/webgl/shaders/clifford-point-shaders.js +131 -0
- package/src/webgl/shaders/dejong-point-shaders.js +131 -0
- package/src/webgl/shaders/point-sprite-shaders.js +152 -0
- package/src/webgl/webgl-clifford-renderer.js +477 -0
- package/src/webgl/webgl-dejong-renderer.js +472 -0
- package/src/webgl/webgl-line-renderer.js +391 -0
- package/src/webgl/webgl-particle-renderer.js +410 -0
- package/types/index.d.ts +30 -2
- package/types/io.d.ts +217 -0
- package/types/physics.d.ts +299 -0
- package/types/shapes.d.ts +8 -0
- package/types/webgl.d.ts +188 -109
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Transform API Demo</title>
|
|
8
|
+
<link rel="stylesheet" href="demos.css" />
|
|
9
|
+
<script src="./js/info-toggle.js"></script>
|
|
10
|
+
<style>
|
|
11
|
+
#debug-toggle {
|
|
12
|
+
position: absolute;
|
|
13
|
+
bottom: 20px;
|
|
14
|
+
left: 20px;
|
|
15
|
+
z-index: 100;
|
|
16
|
+
padding: 10px 20px;
|
|
17
|
+
font-family: monospace;
|
|
18
|
+
font-size: 14px;
|
|
19
|
+
background: #333;
|
|
20
|
+
color: #ff00ff;
|
|
21
|
+
border: 2px solid #ff00ff;
|
|
22
|
+
cursor: pointer;
|
|
23
|
+
transition: all 0.2s ease;
|
|
24
|
+
}
|
|
25
|
+
#debug-toggle:hover {
|
|
26
|
+
background: #ff00ff;
|
|
27
|
+
color: #000;
|
|
28
|
+
}
|
|
29
|
+
#debug-toggle.active {
|
|
30
|
+
background: #ff00ff;
|
|
31
|
+
color: #000;
|
|
32
|
+
}
|
|
33
|
+
</style>
|
|
34
|
+
</head>
|
|
35
|
+
|
|
36
|
+
<body>
|
|
37
|
+
<div id="info" class="light">
|
|
38
|
+
<strong>Transform API Demo</strong> — The <code>Transform</code> API provides a consistent, chainable interface for modifying shape properties.
|
|
39
|
+
Use <code>shape.transform.x(100).y(200).rotation(45).scale(0.8)</code> for fluent chaining,
|
|
40
|
+
<code>shape.transform.set({ x: 100, rotation: 45 })</code> for batch updates, or
|
|
41
|
+
<code>shape.transform.translateBy(10, 20)</code> for relative transforms.
|
|
42
|
+
Click to randomize colors.
|
|
43
|
+
</div>
|
|
44
|
+
<button id="debug-toggle">Toggle Debug</button>
|
|
45
|
+
<canvas id="game"></canvas>
|
|
46
|
+
|
|
47
|
+
<script type="module">
|
|
48
|
+
import {
|
|
49
|
+
Game,
|
|
50
|
+
Scene,
|
|
51
|
+
GameObject,
|
|
52
|
+
FPSCounter,
|
|
53
|
+
Rectangle,
|
|
54
|
+
Circle,
|
|
55
|
+
Star,
|
|
56
|
+
Triangle,
|
|
57
|
+
TextShape,
|
|
58
|
+
Group,
|
|
59
|
+
Transform,
|
|
60
|
+
Painter,
|
|
61
|
+
Easing
|
|
62
|
+
} from "/gcanvas.es.min.js";
|
|
63
|
+
|
|
64
|
+
// Track all shapes for debug toggle
|
|
65
|
+
const allShapes = [];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* TransformDemo Game
|
|
69
|
+
* Showcases the new Transform API with animated shapes
|
|
70
|
+
*/
|
|
71
|
+
class TransformDemoGame extends Game {
|
|
72
|
+
constructor(canvas) {
|
|
73
|
+
super(canvas);
|
|
74
|
+
this.enableFluidSize();
|
|
75
|
+
this.backgroundColor = "black";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
onResize() {
|
|
79
|
+
if (this.scene) {
|
|
80
|
+
this.scene.width = this.width - 20;
|
|
81
|
+
this.scene.height = this.height - 20;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
init() {
|
|
86
|
+
super.init();
|
|
87
|
+
// Main scene
|
|
88
|
+
this.scene = new Scene(this, {
|
|
89
|
+
width: this.width - 20,
|
|
90
|
+
height: this.height - 20,
|
|
91
|
+
debug: false,
|
|
92
|
+
anchor: "center"
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
this.pipeline.add(this.scene);
|
|
96
|
+
|
|
97
|
+
// Add demos
|
|
98
|
+
this.scene.add(new FluentAPIDemo(this));
|
|
99
|
+
this.scene.add(new GroupTransformDemo(this));
|
|
100
|
+
this.scene.add(new BatchUpdateDemo(this));
|
|
101
|
+
this.scene.add(new RelativeTransformDemo(this));
|
|
102
|
+
|
|
103
|
+
// FPS counter
|
|
104
|
+
this.pipeline.add(new FPSCounter(this, { anchor: "bottom-right" }));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Demo 1: Fluent API Chaining
|
|
110
|
+
* Shows basic chained transform calls
|
|
111
|
+
*/
|
|
112
|
+
class FluentAPIDemo extends GameObject {
|
|
113
|
+
constructor(game) {
|
|
114
|
+
super(game);
|
|
115
|
+
|
|
116
|
+
// Create a rectangle using the new Transform API
|
|
117
|
+
this.rect = new Rectangle({
|
|
118
|
+
width: 80,
|
|
119
|
+
height: 60,
|
|
120
|
+
color: "#e94560",
|
|
121
|
+
stroke: "#fff",
|
|
122
|
+
lineWidth: 2,
|
|
123
|
+
debug: false,
|
|
124
|
+
debugColor: "#ff00ff"
|
|
125
|
+
});
|
|
126
|
+
allShapes.push(this.rect);
|
|
127
|
+
|
|
128
|
+
// Use fluent API to set initial position
|
|
129
|
+
this.rect.transform
|
|
130
|
+
.x(-200)
|
|
131
|
+
.y(-120);
|
|
132
|
+
|
|
133
|
+
// Label
|
|
134
|
+
this.label = new TextShape("Fluent API", {
|
|
135
|
+
x: -200,
|
|
136
|
+
y: -170,
|
|
137
|
+
font: "bold 14px monospace",
|
|
138
|
+
color: "#fff",
|
|
139
|
+
align: "center"
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
this.elapsed = 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
update(dt) {
|
|
146
|
+
super.update(dt);
|
|
147
|
+
this.elapsed += dt;
|
|
148
|
+
|
|
149
|
+
// Animate using the transform API
|
|
150
|
+
this.rect.transform
|
|
151
|
+
.rotation(this.elapsed * 45)
|
|
152
|
+
.scaleX(0.8 + Math.sin(this.elapsed * 2) * 0.3)
|
|
153
|
+
.scaleY(0.8 + Math.cos(this.elapsed * 2) * 0.3);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
draw() {
|
|
157
|
+
super.draw();
|
|
158
|
+
this.rect.render();
|
|
159
|
+
this.label.render();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Demo 2: Group Transform Operations
|
|
165
|
+
* Shows group-wide transform operations
|
|
166
|
+
*/
|
|
167
|
+
class GroupTransformDemo extends GameObject {
|
|
168
|
+
constructor(game) {
|
|
169
|
+
super(game);
|
|
170
|
+
|
|
171
|
+
// Create a group with multiple shapes
|
|
172
|
+
this.group = new Group({ debug: false, debugColor: "#ff00ff" });
|
|
173
|
+
allShapes.push(this.group);
|
|
174
|
+
|
|
175
|
+
// Add shapes to group using transform API
|
|
176
|
+
for (let i = 0; i < 3; i++) {
|
|
177
|
+
const circle = new Circle(15 + i * 5, {
|
|
178
|
+
color: Painter.colors.randomColorHSL(),
|
|
179
|
+
stroke: "#fff",
|
|
180
|
+
lineWidth: 1,
|
|
181
|
+
debug: false,
|
|
182
|
+
debugColor: "#ff00ff"
|
|
183
|
+
});
|
|
184
|
+
allShapes.push(circle);
|
|
185
|
+
// Position using transform
|
|
186
|
+
circle.transform.position(i * 40 - 40, 0);
|
|
187
|
+
this.group.add(circle);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Position the group
|
|
191
|
+
this.group.transform.position(0, -120);
|
|
192
|
+
|
|
193
|
+
// Label
|
|
194
|
+
this.label = new TextShape("Group Transforms", {
|
|
195
|
+
x: 0,
|
|
196
|
+
y: -170,
|
|
197
|
+
font: "bold 14px monospace",
|
|
198
|
+
color: "#fff",
|
|
199
|
+
align: "center"
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
this.elapsed = 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
update(dt) {
|
|
206
|
+
super.update(dt);
|
|
207
|
+
this.elapsed += dt;
|
|
208
|
+
|
|
209
|
+
// Animate group transform
|
|
210
|
+
this.group.transform
|
|
211
|
+
.rotation(this.elapsed * 30)
|
|
212
|
+
.scale(0.9 + Math.sin(this.elapsed * 1.5) * 0.2);
|
|
213
|
+
|
|
214
|
+
// Animate individual children using forEachTransform
|
|
215
|
+
this.group.forEachTransform((t, child, i) => {
|
|
216
|
+
// Each child rotates at different speed
|
|
217
|
+
t.rotation(-this.elapsed * (60 + i * 30));
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
draw() {
|
|
222
|
+
super.draw();
|
|
223
|
+
this.group.render();
|
|
224
|
+
this.label.render();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Demo 3: Batch Updates
|
|
230
|
+
* Shows using set() for multiple properties at once
|
|
231
|
+
*/
|
|
232
|
+
class BatchUpdateDemo extends GameObject {
|
|
233
|
+
constructor(game) {
|
|
234
|
+
super(game);
|
|
235
|
+
|
|
236
|
+
this.star = new Star(30, 5, 0.5, {
|
|
237
|
+
color: "#ffc107",
|
|
238
|
+
stroke: "#fff",
|
|
239
|
+
lineWidth: 2,
|
|
240
|
+
debug: false,
|
|
241
|
+
debugColor: "#ff00ff"
|
|
242
|
+
});
|
|
243
|
+
allShapes.push(this.star);
|
|
244
|
+
|
|
245
|
+
// Use batch set for initial state
|
|
246
|
+
this.star.transform.set({
|
|
247
|
+
x: 200,
|
|
248
|
+
y: -120,
|
|
249
|
+
rotation: 0,
|
|
250
|
+
scaleX: 1,
|
|
251
|
+
scaleY: 1
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Label
|
|
255
|
+
this.label = new TextShape("Batch set()", {
|
|
256
|
+
x: 200,
|
|
257
|
+
y: -170,
|
|
258
|
+
font: "bold 14px monospace",
|
|
259
|
+
color: "#fff",
|
|
260
|
+
align: "center"
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
this.elapsed = 0;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
update(dt) {
|
|
267
|
+
super.update(dt);
|
|
268
|
+
this.elapsed += dt;
|
|
269
|
+
|
|
270
|
+
// Use batch update for animation
|
|
271
|
+
const pulse = Math.sin(this.elapsed * 3);
|
|
272
|
+
const wobble = Math.sin(this.elapsed * 5) * 5;
|
|
273
|
+
|
|
274
|
+
this.star.transform.set({
|
|
275
|
+
rotation: this.elapsed * 60,
|
|
276
|
+
scaleX: 1 + pulse * 0.3,
|
|
277
|
+
scaleY: 1 - pulse * 0.3
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// Also translate using relative method
|
|
281
|
+
this.star.transform.x(200 + wobble);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
draw() {
|
|
285
|
+
super.draw();
|
|
286
|
+
this.star.render();
|
|
287
|
+
this.label.render();
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Demo 4: Animated Transforms
|
|
293
|
+
* Shows position, rotation, and scale animations
|
|
294
|
+
*/
|
|
295
|
+
class RelativeTransformDemo extends GameObject {
|
|
296
|
+
constructor(game) {
|
|
297
|
+
super(game);
|
|
298
|
+
|
|
299
|
+
// Create shapes for demonstrating animated transforms
|
|
300
|
+
this.shapes = [];
|
|
301
|
+
const positions = [
|
|
302
|
+
{ x: -200, y: 80 },
|
|
303
|
+
{ x: 0, y: 80 },
|
|
304
|
+
{ x: 200, y: 80 }
|
|
305
|
+
];
|
|
306
|
+
|
|
307
|
+
const types = [
|
|
308
|
+
{ name: "position", shape: new Rectangle({ width: 50, height: 50, color: "#00d9ff", stroke: "#fff", lineWidth: 2, debug: false, debugColor: "#ff00ff" }) },
|
|
309
|
+
{ name: "rotation", shape: new Triangle(40, { color: "#ff6b6b", stroke: "#fff", lineWidth: 2, debug: false, debugColor: "#ff00ff" }) },
|
|
310
|
+
{ name: "scale", shape: new Circle(25, { color: "#7bed9f", stroke: "#fff", lineWidth: 2, debug: false, debugColor: "#ff00ff" }) }
|
|
311
|
+
];
|
|
312
|
+
|
|
313
|
+
types.forEach((type, i) => {
|
|
314
|
+
allShapes.push(type.shape);
|
|
315
|
+
type.shape.transform.position(positions[i].x, positions[i].y);
|
|
316
|
+
type.label = new TextShape(type.name + "()", {
|
|
317
|
+
x: positions[i].x,
|
|
318
|
+
y: 30,
|
|
319
|
+
font: "bold 14px monospace",
|
|
320
|
+
color: "#fff",
|
|
321
|
+
align: "center"
|
|
322
|
+
});
|
|
323
|
+
type.baseX = positions[i].x;
|
|
324
|
+
type.baseY = positions[i].y;
|
|
325
|
+
this.shapes.push(type);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
this.elapsed = 0;
|
|
329
|
+
this.lastUpdate = 0;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
update(dt) {
|
|
333
|
+
super.update(dt);
|
|
334
|
+
this.elapsed += dt;
|
|
335
|
+
|
|
336
|
+
// position demo - oscillate position
|
|
337
|
+
const tx = Math.sin(this.elapsed * 2) * 30;
|
|
338
|
+
const ty = Math.cos(this.elapsed * 3) * 15;
|
|
339
|
+
this.shapes[0].shape.transform.position(this.shapes[0].baseX + tx, this.shapes[0].baseY + ty);
|
|
340
|
+
|
|
341
|
+
// rotation demo - continuous rotation
|
|
342
|
+
this.shapes[1].shape.transform.rotation(this.elapsed * 90);
|
|
343
|
+
|
|
344
|
+
// scale demo - pulsing scale
|
|
345
|
+
const scale = 0.7 + Math.abs(Math.sin(this.elapsed * 2)) * 0.6;
|
|
346
|
+
this.shapes[2].shape.transform.scale(scale);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
draw() {
|
|
350
|
+
super.draw();
|
|
351
|
+
this.shapes.forEach(s => {
|
|
352
|
+
s.shape.render();
|
|
353
|
+
s.label.render();
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Start the game
|
|
359
|
+
window.addEventListener("load", () => {
|
|
360
|
+
const canvas = document.getElementById("game");
|
|
361
|
+
const game = new TransformDemoGame(canvas);
|
|
362
|
+
game.start();
|
|
363
|
+
|
|
364
|
+
// Debug toggle button
|
|
365
|
+
let debugEnabled = false;
|
|
366
|
+
const debugBtn = document.getElementById("debug-toggle");
|
|
367
|
+
|
|
368
|
+
debugBtn.addEventListener("click", () => {
|
|
369
|
+
debugEnabled = !debugEnabled;
|
|
370
|
+
debugBtn.classList.toggle("active", debugEnabled);
|
|
371
|
+
debugBtn.textContent = debugEnabled ? "Debug: ON" : "Toggle Debug";
|
|
372
|
+
|
|
373
|
+
// Toggle debug on all shapes
|
|
374
|
+
allShapes.forEach(shape => {
|
|
375
|
+
shape._debug = debugEnabled;
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// Randomize colors on click
|
|
380
|
+
canvas.addEventListener("click", () => {
|
|
381
|
+
game.scene.children.forEach(child => {
|
|
382
|
+
if (child.rect) child.rect.color = Painter.colors.randomColorHSL();
|
|
383
|
+
if (child.star) child.star.color = Painter.colors.randomColorHSL();
|
|
384
|
+
if (child.group) {
|
|
385
|
+
child.group.children.forEach(c => {
|
|
386
|
+
c.color = Painter.colors.randomColorHSL();
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
if (child.shapes) {
|
|
390
|
+
child.shapes.forEach(s => {
|
|
391
|
+
s.shape.color = Painter.colors.randomColorHSL();
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
</script>
|
|
398
|
+
</body>
|
|
399
|
+
|
|
400
|
+
</html>
|
package/dist/tween.html
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Tween</title>
|
|
8
|
+
<link rel="stylesheet" href="demos.css" />
|
|
9
|
+
<script src="./js/info-toggle.js"></script>
|
|
10
|
+
</head>
|
|
11
|
+
|
|
12
|
+
<body>
|
|
13
|
+
<div id="info">
|
|
14
|
+
<strong>Tween Demo</strong> - A box animated over time. The library features two motion-related classes:
|
|
15
|
+
<span style="color:#CCC">
|
|
16
|
+
<li><code>Tween</code> - Contains motion primitives, lerps and easing functions.</li>
|
|
17
|
+
<li><code>Tweenetik</code> - A shorcut class that leverates Tween to interpolate object properties over time</li>
|
|
18
|
+
<pre>
|
|
19
|
+
Tweenetik.to(
|
|
20
|
+
mySprite, // an object or sprite
|
|
21
|
+
{ scaleX: scale, scaleY: scale}, // the properties & end-values
|
|
22
|
+
2.0, // duration in seconds
|
|
23
|
+
Easing.easeOutBounce, // easing function
|
|
24
|
+
{
|
|
25
|
+
delay: 0.5, // optional 0.5s delay
|
|
26
|
+
onStart: () => console.log("Tween started!"),
|
|
27
|
+
onComplete: () => console.log("Tween done!"),
|
|
28
|
+
onUpdate: () => console.log("Updated frame"),
|
|
29
|
+
}
|
|
30
|
+
);</pre>
|
|
31
|
+
</span>
|
|
32
|
+
</div>
|
|
33
|
+
<canvas id="game"></canvas>
|
|
34
|
+
<script type="module">
|
|
35
|
+
import { MyGame } from './js/tweendemo.js';
|
|
36
|
+
|
|
37
|
+
window.addEventListener("load", () => {
|
|
38
|
+
const canvas = document.getElementById("game");
|
|
39
|
+
const game = new MyGame(canvas);
|
|
40
|
+
game.start();
|
|
41
|
+
});
|
|
42
|
+
</script>
|
|
43
|
+
</body>
|
|
44
|
+
|
|
45
|
+
</html>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Opacity</title>
|
|
8
|
+
<link rel="stylesheet" href="demos.css" />
|
|
9
|
+
<script src="./js/info-toggle.js"></script>
|
|
10
|
+
</head>
|
|
11
|
+
|
|
12
|
+
<body>
|
|
13
|
+
<div id="info">
|
|
14
|
+
<strong>Visibility Toggle Demo</strong> - Shows how game objects can be dynamically shown or hidden.
|
|
15
|
+
<span style="color:#CCC">
|
|
16
|
+
<li><code>Transformable</code> — The base class providing the <code>visible</code> property.</li>
|
|
17
|
+
<li><code>Pipeline Integration</code> — The pipeline skips invisible objects during rendering.</li>
|
|
18
|
+
<li><code>Dynamic Toggling</code> — Click the button to toggle visibility of a random square.</li>
|
|
19
|
+
</span>
|
|
20
|
+
</div>
|
|
21
|
+
<canvas id="game"></canvas>
|
|
22
|
+
<script type="module">
|
|
23
|
+
import { MyGame } from './js/visibility.js';
|
|
24
|
+
|
|
25
|
+
window.addEventListener("load", () => {
|
|
26
|
+
const canvas = document.getElementById("game");
|
|
27
|
+
const game = new MyGame(canvas);
|
|
28
|
+
game.start();
|
|
29
|
+
});
|
|
30
|
+
</script>
|
|
31
|
+
</body>
|
|
32
|
+
|
|
33
|
+
</html>
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -235,7 +235,7 @@ game.start(); // Start the game loop
|
|
|
235
235
|
|
|
236
236
|
- `update(dt)` — Run game logic each frame
|
|
237
237
|
- `render()` — Optional custom rendering
|
|
238
|
-
- Event handling through
|
|
238
|
+
- Event handling through the event emitter pattern
|
|
239
239
|
|
|
240
240
|
This is the base class for all interactive entities:
|
|
241
241
|
|
|
@@ -244,7 +244,14 @@ class Player extends GameObject {
|
|
|
244
244
|
constructor(game) {
|
|
245
245
|
super(game);
|
|
246
246
|
this.shape = new Circle(100, 100, 40, { fillColor: "blue" });
|
|
247
|
-
|
|
247
|
+
|
|
248
|
+
// Enable interactivity
|
|
249
|
+
this.interactive = true;
|
|
250
|
+
|
|
251
|
+
// Listen for input events
|
|
252
|
+
this.on('inputdown', (e) => {
|
|
253
|
+
console.log('Player clicked!');
|
|
254
|
+
});
|
|
248
255
|
}
|
|
249
256
|
|
|
250
257
|
update(dt) {
|
|
@@ -257,10 +264,6 @@ class Player extends GameObject {
|
|
|
257
264
|
render() {
|
|
258
265
|
this.shape.draw();
|
|
259
266
|
}
|
|
260
|
-
|
|
261
|
-
onPointerDown(e) {
|
|
262
|
-
console.log('Player clicked!');
|
|
263
|
-
}
|
|
264
267
|
}
|
|
265
268
|
```
|
|
266
269
|
|
|
@@ -396,21 +399,26 @@ The `Tweenetik` system animates object properties directly over time using easin
|
|
|
396
399
|
|
|
397
400
|
```js
|
|
398
401
|
// Animate a button when pressed
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
402
|
+
constructor(game) {
|
|
403
|
+
super(game);
|
|
404
|
+
this.interactive = true;
|
|
405
|
+
|
|
406
|
+
this.on('inputdown', () => {
|
|
407
|
+
Tweenetik.to(this.shape,
|
|
408
|
+
{ scaleX: 1.2, scaleY: 1.2 },
|
|
409
|
+
0.2,
|
|
410
|
+
Easing.easeOutBack,
|
|
411
|
+
{
|
|
412
|
+
onComplete: () => {
|
|
413
|
+
Tweenetik.to(this.shape,
|
|
414
|
+
{ scaleX: 1.0, scaleY: 1.0 },
|
|
415
|
+
0.3,
|
|
416
|
+
Easing.easeInBack
|
|
417
|
+
);
|
|
418
|
+
}
|
|
411
419
|
}
|
|
412
|
-
|
|
413
|
-
);
|
|
420
|
+
);
|
|
421
|
+
});
|
|
414
422
|
}
|
|
415
423
|
```
|
|
416
424
|
|
|
@@ -545,7 +553,7 @@ class Bob extends GameObject {
|
|
|
545
553
|
constructor(game) {
|
|
546
554
|
super(game);
|
|
547
555
|
this.shape = new Circle(100, 100, 40, { fillColor: "tomato" });
|
|
548
|
-
this.
|
|
556
|
+
this.interactive = true;
|
|
549
557
|
}
|
|
550
558
|
|
|
551
559
|
update(dt) {
|
|
@@ -575,7 +583,7 @@ class SpinningShape extends GameObject {
|
|
|
575
583
|
constructor(game) {
|
|
576
584
|
super(game);
|
|
577
585
|
this.shape = new Circle(200, 200, 50, { fillColor: 'cyan' });
|
|
578
|
-
this.
|
|
586
|
+
this.interactive = true;
|
|
579
587
|
this.hovered = false;
|
|
580
588
|
|
|
581
589
|
this.on('mouseover', () => this.hovered = true);
|
package/src/game/objects/go.js
CHANGED
|
@@ -163,6 +163,13 @@ export class GameObject extends Transformable {
|
|
|
163
163
|
localX -= obj.x || 0;
|
|
164
164
|
localY -= obj.y || 0;
|
|
165
165
|
|
|
166
|
+
// Apply additional hit test offset (e.g., scroll offset from LayoutScene)
|
|
167
|
+
if (obj.getHitTestOffset) {
|
|
168
|
+
const offset = obj.getHitTestOffset();
|
|
169
|
+
localX -= offset.x || 0;
|
|
170
|
+
localY -= offset.y || 0;
|
|
171
|
+
}
|
|
172
|
+
|
|
166
173
|
// Rotation: apply inverse rotation if needed
|
|
167
174
|
if (obj.rotation) {
|
|
168
175
|
const cos = Math.cos(-obj.rotation);
|
|
@@ -178,6 +178,46 @@ export class IsometricScene extends Scene {
|
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Compute depth value for sorting, accounting for camera rotation.
|
|
183
|
+
* Use this when implementing custom isoDepth getters for box-like objects.
|
|
184
|
+
*
|
|
185
|
+
* For a rectangular object, pass all 4 corners and this will return
|
|
186
|
+
* the depth of the "front" corner (highest rotated x+y) at the current camera angle.
|
|
187
|
+
*
|
|
188
|
+
* @param {Array<{x: number, y: number}>} corners - Array of corner positions in grid coords
|
|
189
|
+
* @param {number} [height=0] - Height of object for z-ordering
|
|
190
|
+
* @returns {number} Depth value for sorting
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* // In a custom GameObject with grid position and size:
|
|
194
|
+
* get isoDepth() {
|
|
195
|
+
* const corners = [
|
|
196
|
+
* { x: this.gridX, y: this.gridY },
|
|
197
|
+
* { x: this.gridX + this.width, y: this.gridY },
|
|
198
|
+
* { x: this.gridX, y: this.gridY + this.depth },
|
|
199
|
+
* { x: this.gridX + this.width, y: this.gridY + this.depth },
|
|
200
|
+
* ];
|
|
201
|
+
* return this.isoScene.getRotatedDepth(corners, this.height);
|
|
202
|
+
* }
|
|
203
|
+
*/
|
|
204
|
+
getRotatedDepth(corners, height = 0) {
|
|
205
|
+
const angle = this.camera ? this.camera.angle : 0;
|
|
206
|
+
const cos = Math.cos(angle);
|
|
207
|
+
const sin = Math.sin(angle);
|
|
208
|
+
|
|
209
|
+
let maxDepth = -Infinity;
|
|
210
|
+
for (const c of corners) {
|
|
211
|
+
const rotatedX = c.x * cos - c.y * sin;
|
|
212
|
+
const rotatedY = c.x * sin + c.y * cos;
|
|
213
|
+
const depth = rotatedX + rotatedY;
|
|
214
|
+
if (depth > maxDepth) maxDepth = depth;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Height factor of 0.5 matches demo for proper depth sorting
|
|
218
|
+
return maxDepth + height * 0.5;
|
|
219
|
+
}
|
|
220
|
+
|
|
181
221
|
/**
|
|
182
222
|
* Calculate scale factor based on Y position (for perspective effect).
|
|
183
223
|
*
|
|
@@ -219,16 +259,26 @@ export class IsometricScene extends Scene {
|
|
|
219
259
|
for (const child of this._collection.getSortedChildren()) {
|
|
220
260
|
if (!child.visible) continue;
|
|
221
261
|
|
|
222
|
-
// Use custom isoDepth if available, otherwise calculate
|
|
262
|
+
// Use custom isoDepth if available, otherwise calculate using rotated coords
|
|
223
263
|
let depth;
|
|
224
264
|
if (child.isoDepth !== undefined) {
|
|
225
265
|
depth = child.isoDepth;
|
|
226
266
|
} else {
|
|
267
|
+
// Apply camera rotation to get correct depth at all angles
|
|
268
|
+
let rotatedX = child.x;
|
|
269
|
+
let rotatedY = child.y;
|
|
270
|
+
if (this.camera) {
|
|
271
|
+
const angle = this.camera.angle;
|
|
272
|
+
const cos = Math.cos(angle);
|
|
273
|
+
const sin = Math.sin(angle);
|
|
274
|
+
rotatedX = child.x * cos - child.y * sin;
|
|
275
|
+
rotatedY = child.x * sin + child.y * cos;
|
|
276
|
+
}
|
|
227
277
|
// For moving objects, use z as height
|
|
228
278
|
const height = child.z ?? 0;
|
|
229
|
-
// Higher (
|
|
279
|
+
// Higher (rotatedX + rotatedY) = closer to viewer = higher depth = render later
|
|
230
280
|
// Higher z = on top = higher depth = render later
|
|
231
|
-
depth = (
|
|
281
|
+
depth = (rotatedX + rotatedY) + height * 0.05;
|
|
232
282
|
}
|
|
233
283
|
|
|
234
284
|
renderList.push({
|