@guinetik/gcanvas 1.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/.github/workflows/release.yaml +70 -0
- package/.jshintrc +4 -0
- package/.vscode/settings.json +22 -0
- package/CLAUDE.md +310 -0
- package/blackhole.jpg +0 -0
- package/demo.png +0 -0
- package/demos/CNAME +1 -0
- package/demos/animations.html +31 -0
- package/demos/basic.html +38 -0
- package/demos/baskara.html +31 -0
- package/demos/bezier.html +35 -0
- package/demos/beziersignature.html +29 -0
- package/demos/blackhole.html +28 -0
- package/demos/blob.html +35 -0
- package/demos/demos.css +289 -0
- package/demos/easing.html +28 -0
- package/demos/events.html +195 -0
- package/demos/fluent.html +647 -0
- package/demos/fractals.html +36 -0
- package/demos/genart.html +26 -0
- package/demos/gendream.html +26 -0
- package/demos/group.html +36 -0
- package/demos/home.html +587 -0
- package/demos/index.html +364 -0
- package/demos/isometric.html +34 -0
- package/demos/js/animations.js +452 -0
- package/demos/js/basic.js +204 -0
- package/demos/js/baskara.js +751 -0
- package/demos/js/bezier.js +692 -0
- package/demos/js/beziersignature.js +241 -0
- package/demos/js/blackhole/accretiondisk.obj.js +379 -0
- package/demos/js/blackhole/blackhole.obj.js +318 -0
- package/demos/js/blackhole/index.js +409 -0
- package/demos/js/blackhole/particle.js +56 -0
- package/demos/js/blackhole/starfield.obj.js +218 -0
- package/demos/js/blob.js +2263 -0
- package/demos/js/easing.js +477 -0
- package/demos/js/fluent.js +183 -0
- package/demos/js/fractals.js +931 -0
- package/demos/js/fractalworker.js +93 -0
- package/demos/js/genart.js +268 -0
- package/demos/js/gendream.js +209 -0
- package/demos/js/group.js +140 -0
- package/demos/js/info-toggle.js +25 -0
- package/demos/js/isometric.js +863 -0
- package/demos/js/kerr.js +1556 -0
- package/demos/js/lavalamp.js +590 -0
- package/demos/js/layout.js +354 -0
- package/demos/js/mondrian.js +285 -0
- package/demos/js/opacity.js +275 -0
- package/demos/js/painter.js +484 -0
- package/demos/js/particles-showcase.js +514 -0
- package/demos/js/particles.js +299 -0
- package/demos/js/patterns.js +397 -0
- package/demos/js/penrose/artifact.js +69 -0
- package/demos/js/penrose/blackhole.js +121 -0
- package/demos/js/penrose/constants.js +73 -0
- package/demos/js/penrose/game.js +943 -0
- package/demos/js/penrose/lore.js +278 -0
- package/demos/js/penrose/penrosescene.js +892 -0
- package/demos/js/penrose/ship.js +216 -0
- package/demos/js/penrose/sounds.js +211 -0
- package/demos/js/penrose/voidparticle.js +55 -0
- package/demos/js/penrose/voidscene.js +258 -0
- package/demos/js/penrose/voidship.js +144 -0
- package/demos/js/penrose/wormhole.js +46 -0
- package/demos/js/pipeline.js +555 -0
- package/demos/js/scene.js +304 -0
- package/demos/js/scenes.js +320 -0
- package/demos/js/schrodinger.js +410 -0
- package/demos/js/schwarzschild.js +1023 -0
- package/demos/js/shapes.js +628 -0
- package/demos/js/space/alien.js +171 -0
- package/demos/js/space/boom.js +98 -0
- package/demos/js/space/boss.js +353 -0
- package/demos/js/space/buff.js +73 -0
- package/demos/js/space/bullet.js +102 -0
- package/demos/js/space/constants.js +85 -0
- package/demos/js/space/game.js +1884 -0
- package/demos/js/space/hud.js +112 -0
- package/demos/js/space/laserbeam.js +179 -0
- package/demos/js/space/lightning.js +277 -0
- package/demos/js/space/minion.js +192 -0
- package/demos/js/space/missile.js +212 -0
- package/demos/js/space/player.js +430 -0
- package/demos/js/space/powerup.js +90 -0
- package/demos/js/space/starfield.js +58 -0
- package/demos/js/space/starpower.js +90 -0
- package/demos/js/spacetime.js +559 -0
- package/demos/js/svgtween.js +204 -0
- package/demos/js/tde/accretiondisk.js +418 -0
- package/demos/js/tde/blackhole.js +219 -0
- package/demos/js/tde/blackholescene.js +209 -0
- package/demos/js/tde/config.js +59 -0
- package/demos/js/tde/index.js +695 -0
- package/demos/js/tde/jets.js +290 -0
- package/demos/js/tde/lensedstarfield.js +147 -0
- package/demos/js/tde/tdestar.js +317 -0
- package/demos/js/tde/tidalstream.js +356 -0
- package/demos/js/tde_old/blackhole.obj.js +354 -0
- package/demos/js/tde_old/debris.obj.js +791 -0
- package/demos/js/tde_old/flare.obj.js +239 -0
- package/demos/js/tde_old/index.js +448 -0
- package/demos/js/tde_old/star.obj.js +812 -0
- package/demos/js/tiles.js +312 -0
- package/demos/js/tweendemo.js +79 -0
- package/demos/js/visibility.js +102 -0
- package/demos/kerr.html +28 -0
- package/demos/lavalamp.html +27 -0
- package/demos/layouts.html +37 -0
- package/demos/logo.svg +4 -0
- package/demos/loop.html +84 -0
- package/demos/mondrian.html +32 -0
- package/demos/og_image.png +0 -0
- package/demos/opacity.html +36 -0
- package/demos/painter.html +39 -0
- package/demos/particles-showcase.html +28 -0
- package/demos/particles.html +24 -0
- package/demos/patterns.html +33 -0
- package/demos/penrose-game.html +31 -0
- package/demos/pipeline.html +737 -0
- package/demos/scene.html +33 -0
- package/demos/scenes.html +96 -0
- package/demos/schrodinger.html +27 -0
- package/demos/schwarzschild.html +27 -0
- package/demos/shapes.html +16 -0
- package/demos/space.html +85 -0
- package/demos/spacetime.html +27 -0
- package/demos/svgtween.html +29 -0
- package/demos/tde.html +28 -0
- package/demos/tiles.html +28 -0
- package/demos/transforms.html +400 -0
- package/demos/tween.html +45 -0
- package/demos/visibility.html +33 -0
- package/disk_example.png +0 -0
- package/docs/README.md +222 -0
- package/docs/concepts/architecture-overview.md +204 -0
- package/docs/concepts/lifecycle.md +255 -0
- package/docs/concepts/rendering-pipeline.md +279 -0
- package/docs/concepts/tde-zorder.md +106 -0
- package/docs/concepts/two-layer-architecture.md +229 -0
- package/docs/getting-started/first-game.md +354 -0
- package/docs/getting-started/hello-world.md +269 -0
- package/docs/getting-started/installation.md +157 -0
- package/docs/modules/collision/README.md +453 -0
- package/docs/modules/fluent/README.md +1075 -0
- package/docs/modules/game/README.md +303 -0
- package/docs/modules/isometric-camera.md +210 -0
- package/docs/modules/isometric.md +275 -0
- package/docs/modules/painter/README.md +328 -0
- package/docs/modules/particle/README.md +559 -0
- package/docs/modules/shapes/README.md +221 -0
- package/docs/modules/shapes/base/euclidian.md +123 -0
- package/docs/modules/shapes/base/geometry2d.md +204 -0
- package/docs/modules/shapes/base/renderable.md +215 -0
- package/docs/modules/shapes/base/shape.md +262 -0
- package/docs/modules/shapes/base/transformable.md +243 -0
- package/docs/modules/shapes/hierarchy.md +218 -0
- package/docs/modules/state/README.md +577 -0
- package/docs/modules/util/README.md +99 -0
- package/docs/modules/util/camera3d.md +412 -0
- package/docs/modules/util/scene3d.md +395 -0
- package/index.html +17 -0
- package/jsdoc.json +50 -0
- package/package.json +55 -0
- package/readme.md +599 -0
- package/scripts/build-demo.js +69 -0
- package/scripts/bundle4llm.js +276 -0
- package/scripts/clearconsole.js +48 -0
- package/src/collision/collision-system.js +332 -0
- package/src/collision/collision.js +303 -0
- package/src/collision/index.js +10 -0
- package/src/fluent/fluent-game.js +430 -0
- package/src/fluent/fluent-go.js +1060 -0
- package/src/fluent/fluent-layer.js +152 -0
- package/src/fluent/fluent-scene.js +291 -0
- package/src/fluent/index.js +98 -0
- package/src/fluent/sketch.js +380 -0
- package/src/game/game.js +467 -0
- package/src/game/index.js +49 -0
- package/src/game/objects/go.js +220 -0
- package/src/game/objects/imagego.js +30 -0
- package/src/game/objects/index.js +54 -0
- package/src/game/objects/isometric-scene.js +260 -0
- package/src/game/objects/layoutscene.js +549 -0
- package/src/game/objects/scene.js +175 -0
- package/src/game/objects/scene3d.js +118 -0
- package/src/game/objects/text.js +221 -0
- package/src/game/objects/wrapper.js +232 -0
- package/src/game/pipeline.js +243 -0
- package/src/game/ui/button.js +396 -0
- package/src/game/ui/cursor.js +93 -0
- package/src/game/ui/fps.js +91 -0
- package/src/game/ui/index.js +5 -0
- package/src/game/ui/togglebutton.js +93 -0
- package/src/game/ui/tooltip.js +249 -0
- package/src/index.js +25 -0
- package/src/io/events.js +20 -0
- package/src/io/index.js +86 -0
- package/src/io/input.js +70 -0
- package/src/io/keys.js +152 -0
- package/src/io/mouse.js +61 -0
- package/src/io/touch.js +39 -0
- package/src/logger/debugtab.js +138 -0
- package/src/logger/index.js +3 -0
- package/src/logger/loggable.js +47 -0
- package/src/logger/logger.js +113 -0
- package/src/math/complex.js +37 -0
- package/src/math/constants.js +1 -0
- package/src/math/fractal.js +1271 -0
- package/src/math/gr.js +201 -0
- package/src/math/heat.js +202 -0
- package/src/math/index.js +12 -0
- package/src/math/noise.js +433 -0
- package/src/math/orbital.js +191 -0
- package/src/math/patterns.js +1339 -0
- package/src/math/penrose.js +259 -0
- package/src/math/quantum.js +115 -0
- package/src/math/random.js +195 -0
- package/src/math/tensor.js +1009 -0
- package/src/mixins/anchor.js +131 -0
- package/src/mixins/draggable.js +72 -0
- package/src/mixins/index.js +2 -0
- package/src/motion/bezier.js +132 -0
- package/src/motion/bounce.js +58 -0
- package/src/motion/easing.js +349 -0
- package/src/motion/float.js +130 -0
- package/src/motion/follow.js +125 -0
- package/src/motion/hop.js +52 -0
- package/src/motion/index.js +82 -0
- package/src/motion/motion.js +1124 -0
- package/src/motion/orbit.js +49 -0
- package/src/motion/oscillate.js +39 -0
- package/src/motion/parabolic.js +141 -0
- package/src/motion/patrol.js +147 -0
- package/src/motion/pendulum.js +48 -0
- package/src/motion/pulse.js +88 -0
- package/src/motion/shake.js +83 -0
- package/src/motion/spiral.js +144 -0
- package/src/motion/spring.js +150 -0
- package/src/motion/swing.js +47 -0
- package/src/motion/tween.js +92 -0
- package/src/motion/tweenetik.js +139 -0
- package/src/motion/waypoint.js +210 -0
- package/src/painter/index.js +8 -0
- package/src/painter/painter.colors.js +331 -0
- package/src/painter/painter.effects.js +230 -0
- package/src/painter/painter.img.js +229 -0
- package/src/painter/painter.js +295 -0
- package/src/painter/painter.lines.js +189 -0
- package/src/painter/painter.opacity.js +41 -0
- package/src/painter/painter.shapes.js +277 -0
- package/src/painter/painter.text.js +273 -0
- package/src/particle/emitter.js +124 -0
- package/src/particle/index.js +11 -0
- package/src/particle/particle-system.js +322 -0
- package/src/particle/particle.js +71 -0
- package/src/particle/updaters.js +170 -0
- package/src/shapes/arc.js +43 -0
- package/src/shapes/arrow.js +33 -0
- package/src/shapes/bezier.js +42 -0
- package/src/shapes/circle.js +62 -0
- package/src/shapes/clouds.js +56 -0
- package/src/shapes/cone.js +219 -0
- package/src/shapes/cross.js +70 -0
- package/src/shapes/cube.js +244 -0
- package/src/shapes/cylinder.js +254 -0
- package/src/shapes/diamond.js +48 -0
- package/src/shapes/euclidian.js +111 -0
- package/src/shapes/figure.js +115 -0
- package/src/shapes/geometry.js +220 -0
- package/src/shapes/group.js +375 -0
- package/src/shapes/heart.js +42 -0
- package/src/shapes/hexagon.js +26 -0
- package/src/shapes/image.js +192 -0
- package/src/shapes/index.js +111 -0
- package/src/shapes/line.js +29 -0
- package/src/shapes/pattern.js +90 -0
- package/src/shapes/pin.js +44 -0
- package/src/shapes/poly.js +31 -0
- package/src/shapes/prism.js +226 -0
- package/src/shapes/rect.js +35 -0
- package/src/shapes/renderable.js +333 -0
- package/src/shapes/ring.js +26 -0
- package/src/shapes/roundrect.js +95 -0
- package/src/shapes/shape.js +117 -0
- package/src/shapes/slice.js +26 -0
- package/src/shapes/sphere.js +314 -0
- package/src/shapes/sphere3d.js +537 -0
- package/src/shapes/square.js +15 -0
- package/src/shapes/star.js +99 -0
- package/src/shapes/svg.js +408 -0
- package/src/shapes/text.js +553 -0
- package/src/shapes/traceable.js +83 -0
- package/src/shapes/transform.js +357 -0
- package/src/shapes/transformable.js +172 -0
- package/src/shapes/triangle.js +26 -0
- package/src/sound/index.js +17 -0
- package/src/sound/sound.js +473 -0
- package/src/sound/synth.analyzer.js +149 -0
- package/src/sound/synth.effects.js +207 -0
- package/src/sound/synth.envelope.js +59 -0
- package/src/sound/synth.js +229 -0
- package/src/sound/synth.musical.js +160 -0
- package/src/sound/synth.noise.js +85 -0
- package/src/sound/synth.oscillators.js +293 -0
- package/src/state/index.js +10 -0
- package/src/state/state-machine.js +371 -0
- package/src/util/camera3d.js +438 -0
- package/src/util/index.js +6 -0
- package/src/util/isometric-camera.js +235 -0
- package/src/util/layout.js +317 -0
- package/src/util/position.js +147 -0
- package/src/util/tasks.js +47 -0
- package/src/util/zindex.js +287 -0
- package/src/webgl/index.js +9 -0
- package/src/webgl/shaders/sphere-shaders.js +994 -0
- package/src/webgl/webgl-renderer.js +388 -0
- package/tde.png +0 -0
- package/test/math/orbital.test.js +61 -0
- package/test/math/tensor.test.js +114 -0
- package/test/particle/emitter.test.js +204 -0
- package/test/particle/particle-system.test.js +310 -0
- package/test/particle/particle.test.js +116 -0
- package/test/particle/updaters.test.js +386 -0
- package/test/setup.js +120 -0
- package/test/shapes/euclidian.test.js +44 -0
- package/test/shapes/geometry.test.js +86 -0
- package/test/shapes/group.test.js +86 -0
- package/test/shapes/rectangle.test.js +64 -0
- package/test/shapes/transform.test.js +379 -0
- package/test/util/camera3d.test.js +428 -0
- package/test/util/scene3d.test.js +352 -0
- package/types/collision.d.ts +249 -0
- package/types/common.d.ts +155 -0
- package/types/game.d.ts +497 -0
- package/types/index.d.ts +309 -0
- package/types/io.d.ts +188 -0
- package/types/logger.d.ts +127 -0
- package/types/math.d.ts +268 -0
- package/types/mixins.d.ts +92 -0
- package/types/motion.d.ts +678 -0
- package/types/painter.d.ts +378 -0
- package/types/shapes.d.ts +864 -0
- package/types/sound.d.ts +672 -0
- package/types/state.d.ts +251 -0
- package/types/util.d.ts +253 -0
- package/vite.config.js +50 -0
- package/vitest.config.js +13 -0
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Arc,
|
|
3
|
+
Circle,
|
|
4
|
+
Easing,
|
|
5
|
+
FPSCounter,
|
|
6
|
+
Game,
|
|
7
|
+
GameObjectShapeWrapper,
|
|
8
|
+
Group,
|
|
9
|
+
Heart,
|
|
10
|
+
Painter,
|
|
11
|
+
PieSlice,
|
|
12
|
+
Rectangle,
|
|
13
|
+
Scene,
|
|
14
|
+
Square,
|
|
15
|
+
Star,
|
|
16
|
+
StickFigure,
|
|
17
|
+
TextShape,
|
|
18
|
+
TileLayout,
|
|
19
|
+
Triangle,
|
|
20
|
+
Motion,
|
|
21
|
+
Tween,
|
|
22
|
+
GameObject,
|
|
23
|
+
} from "../../src/index";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* ShapeBox: A GameObject that wraps an inner shape within a background
|
|
27
|
+
*
|
|
28
|
+
* Demonstrates the Transform API for animations:
|
|
29
|
+
* - Uses transform.position() for x/y updates
|
|
30
|
+
* - Uses transform.rotation() for rotation updates
|
|
31
|
+
* - Uses transform.scale() for scale updates
|
|
32
|
+
*/
|
|
33
|
+
class ShapeBox extends GameObject {
|
|
34
|
+
constructor(game, innerShape, type, options = {}) {
|
|
35
|
+
super(game, options);
|
|
36
|
+
const whites = ["bezier", "patrol", "follow", "waypoint"];
|
|
37
|
+
const group = new Group();
|
|
38
|
+
// Use Transform API to set group dimensions
|
|
39
|
+
group.transform.size(options.width, options.height);
|
|
40
|
+
|
|
41
|
+
const bg = new Rectangle({
|
|
42
|
+
width: 100,
|
|
43
|
+
height: 100,
|
|
44
|
+
color: whites.includes(type) ? "white" : "transparent",
|
|
45
|
+
stroke: "white",
|
|
46
|
+
lineWidth: 2,
|
|
47
|
+
});
|
|
48
|
+
group.add(bg);
|
|
49
|
+
group.add(innerShape);
|
|
50
|
+
this.type = type;
|
|
51
|
+
this.group = group;
|
|
52
|
+
this.group.add(
|
|
53
|
+
new TextShape(this.type, {
|
|
54
|
+
x: 0,
|
|
55
|
+
y: 40,
|
|
56
|
+
font: "16px monospace",
|
|
57
|
+
color: whites.includes(type) ? "black" : "white",
|
|
58
|
+
})
|
|
59
|
+
);
|
|
60
|
+
// Store a reference to the inner shape so you can update its animation separately.
|
|
61
|
+
this.innerShape = innerShape;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
draw() {
|
|
65
|
+
super.draw();
|
|
66
|
+
this.group.render();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
swing(box, dt) {
|
|
70
|
+
if (box.animTime === undefined) box.animTime = 0;
|
|
71
|
+
box.animTime += dt;
|
|
72
|
+
if (!box.swingState) box.swingState = null;
|
|
73
|
+
const result = Motion.swing(
|
|
74
|
+
0, 0,
|
|
75
|
+
90,
|
|
76
|
+
box.animTime,
|
|
77
|
+
3.0,
|
|
78
|
+
true, true, null, {},
|
|
79
|
+
box.swingState
|
|
80
|
+
);
|
|
81
|
+
box.swingState = result.state;
|
|
82
|
+
// Use Transform API for rotation
|
|
83
|
+
box.innerShape.transform.rotation(45 + result.angle);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
pendulum(box, dt) {
|
|
87
|
+
if (box.animTime === undefined) box.animTime = 0;
|
|
88
|
+
box.animTime += dt;
|
|
89
|
+
if (!box.pendulumState) box.pendulumState = null;
|
|
90
|
+
|
|
91
|
+
const result = Motion.pendulum(
|
|
92
|
+
60, 120,
|
|
93
|
+
box.animTime,
|
|
94
|
+
3.0,
|
|
95
|
+
true, true, null, {},
|
|
96
|
+
box.pendulumState
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
box.pendulumState = result.state;
|
|
100
|
+
// Use Transform API for rotation
|
|
101
|
+
box.innerShape.transform.rotation(result.angle);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
hop(box, dt) {
|
|
105
|
+
if (box.animTime === undefined) box.animTime = 0;
|
|
106
|
+
box.animTime += dt;
|
|
107
|
+
if (!box.hopState) box.hopState = null;
|
|
108
|
+
|
|
109
|
+
const result = Motion.hop(
|
|
110
|
+
-20, -40,
|
|
111
|
+
box.animTime,
|
|
112
|
+
1.2,
|
|
113
|
+
true, true,
|
|
114
|
+
Easing.easeInOutQuart,
|
|
115
|
+
{ onLoop: () => {} },
|
|
116
|
+
box.hopState
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
box.hopState = result.state;
|
|
120
|
+
// Use Transform API for y position
|
|
121
|
+
box.innerShape.transform.y(result.y);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
parabolic(box) {
|
|
125
|
+
const startPos = { x: -45, y: 30 };
|
|
126
|
+
const endPos = { x: 30, y: -40 };
|
|
127
|
+
const cycleDuration = 2;
|
|
128
|
+
|
|
129
|
+
const frameX = Motion.parabolic(
|
|
130
|
+
startPos.x, -50, endPos.x,
|
|
131
|
+
box.animTime, cycleDuration,
|
|
132
|
+
true, true,
|
|
133
|
+
Easing.easeInOutBack
|
|
134
|
+
);
|
|
135
|
+
const frameY = Motion.parabolic(
|
|
136
|
+
startPos.y, -50, endPos.y,
|
|
137
|
+
box.animTime, cycleDuration,
|
|
138
|
+
true, true,
|
|
139
|
+
Easing.easeInOutBack
|
|
140
|
+
);
|
|
141
|
+
// Use Transform API for position
|
|
142
|
+
box.innerShape.transform.position(frameX.value, frameY.value);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
spiral(box) {
|
|
146
|
+
if (!box.easingFun) box.easingFun = Easing.easeInOutSine;
|
|
147
|
+
const result = Motion.spiral(
|
|
148
|
+
0, 0, // center
|
|
149
|
+
0, 40, // start/end radius
|
|
150
|
+
0, 2, // start angle, revolutions
|
|
151
|
+
box.animTime, 3,
|
|
152
|
+
true, true,
|
|
153
|
+
box.easingFun
|
|
154
|
+
);
|
|
155
|
+
// Use Transform API for position
|
|
156
|
+
box.innerShape.transform.position(result.x, result.y);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
orbit(box) {
|
|
160
|
+
const result = Motion.orbit(
|
|
161
|
+
0, 0, // center
|
|
162
|
+
-40, 30, // radius X/Y
|
|
163
|
+
Math.PI / 2, // start angle
|
|
164
|
+
box.animTime, 3,
|
|
165
|
+
true, true,
|
|
166
|
+
Easing.easeInOutSine
|
|
167
|
+
);
|
|
168
|
+
// Use Transform API for position
|
|
169
|
+
box.innerShape.transform.position(result.x, result.y);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
float(box, dt) {
|
|
173
|
+
if (box.animTime === undefined) box.animTime = 0;
|
|
174
|
+
box.animTime += dt;
|
|
175
|
+
|
|
176
|
+
const result = Motion.float(
|
|
177
|
+
{ x: 0, y: 0 },
|
|
178
|
+
box.animTime,
|
|
179
|
+
10, 0.8, 0.7, 30, true
|
|
180
|
+
);
|
|
181
|
+
// Use Transform API for position
|
|
182
|
+
box.innerShape.transform.position(result.x, result.y);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
waypoint(guard, dt) {
|
|
186
|
+
if (guard.animTime === undefined) guard.animTime = 0;
|
|
187
|
+
guard.animTime += dt;
|
|
188
|
+
|
|
189
|
+
const waypoints = [
|
|
190
|
+
[0, 0], [40, 0], [40, -30],
|
|
191
|
+
[-40, -30], [-40, 30], [40, 30],
|
|
192
|
+
];
|
|
193
|
+
|
|
194
|
+
const result = Motion.waypoint(
|
|
195
|
+
guard, guard.animTime, waypoints,
|
|
196
|
+
50, 1.5, true,
|
|
197
|
+
{ onWaypointReached: (index) => {} }
|
|
198
|
+
);
|
|
199
|
+
// Use Transform API for position
|
|
200
|
+
guard.innerShape.transform.position(result.x, result.y);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
patrol(guard, dt) {
|
|
204
|
+
if (guard.animTime === undefined) guard.animTime = 0;
|
|
205
|
+
guard.animTime += dt;
|
|
206
|
+
if (!guard.patrolState) guard.patrolState = null;
|
|
207
|
+
|
|
208
|
+
const result = Motion.patrol(
|
|
209
|
+
0, 0,
|
|
210
|
+
guard.animTime,
|
|
211
|
+
1.5, 2.0, 40, true,
|
|
212
|
+
guard.patrolState
|
|
213
|
+
);
|
|
214
|
+
guard.patrolState = result.state;
|
|
215
|
+
// Use Transform API for position
|
|
216
|
+
guard.innerShape.transform.position(result.x, result.y);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
spring(box, dt) {
|
|
220
|
+
if (box.animTime === undefined) box.animTime = 0;
|
|
221
|
+
box.animTime += dt;
|
|
222
|
+
|
|
223
|
+
const result = Motion.spring(
|
|
224
|
+
-15, 18,
|
|
225
|
+
box.animTime, 3,
|
|
226
|
+
true, true,
|
|
227
|
+
{ stiffness: 0.7, damping: 0.5 }
|
|
228
|
+
);
|
|
229
|
+
// Use Transform API for y position
|
|
230
|
+
box.innerShape.transform.y(result.value);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
bounce(box) {
|
|
234
|
+
const frame = Motion.bounce(
|
|
235
|
+
-20, 25, 3,
|
|
236
|
+
box.animTime, 3, true
|
|
237
|
+
);
|
|
238
|
+
// Use Transform API for position
|
|
239
|
+
box.innerShape.transform.position(0, frame.y);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
bezier(box, dt) {
|
|
243
|
+
if (box.animTime === undefined) box.animTime = 0;
|
|
244
|
+
box.animTime += dt;
|
|
245
|
+
|
|
246
|
+
const p0 = [-30, 30];
|
|
247
|
+
const p1 = [-75, 10];
|
|
248
|
+
const p2 = [100, 40];
|
|
249
|
+
const p3 = [-40, -40];
|
|
250
|
+
|
|
251
|
+
const pos = Motion.bezier(
|
|
252
|
+
p0, p1, p2, p3,
|
|
253
|
+
box.animTime, 10,
|
|
254
|
+
true, true,
|
|
255
|
+
Easing.easeInOutExpo
|
|
256
|
+
);
|
|
257
|
+
// Use Transform API for position
|
|
258
|
+
box.innerShape.transform.position(pos.x, pos.y);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
pulse(box, dt) {
|
|
262
|
+
if (box.animTime === undefined) box.animTime = 0;
|
|
263
|
+
box.animTime += dt;
|
|
264
|
+
|
|
265
|
+
const result = Motion.pulse(0.5, 1.5, box.animTime, 2, true);
|
|
266
|
+
// Use Transform API for scale and position
|
|
267
|
+
box.innerShape.transform
|
|
268
|
+
.scale(result.value)
|
|
269
|
+
.y(result.value * -25);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
shake(box, dt) {
|
|
273
|
+
if (box.animTime === undefined) box.animTime = 0;
|
|
274
|
+
box.animTime += dt;
|
|
275
|
+
|
|
276
|
+
const pos = Motion.shake(
|
|
277
|
+
0, 0, // center
|
|
278
|
+
20, 15, // max offset X/Y
|
|
279
|
+
5, 1, // frequency, decay
|
|
280
|
+
box.animTime, 5,
|
|
281
|
+
true,
|
|
282
|
+
Easing.easeInOutQuad
|
|
283
|
+
);
|
|
284
|
+
// Use Transform API for position
|
|
285
|
+
box.innerShape.transform.position(pos.x, pos.y);
|
|
286
|
+
box.innerShape.color = "white";
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
oscillate(box, dt) {
|
|
290
|
+
if (box.animTime === undefined) box.animTime = 0;
|
|
291
|
+
box.animTime += dt;
|
|
292
|
+
|
|
293
|
+
const result = Motion.oscillate(-270, 270, box.animTime, 3, true);
|
|
294
|
+
// Use Transform API for rotation
|
|
295
|
+
box.innerShape.transform.rotation(result.value);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
follow(box, dt) {
|
|
299
|
+
if (box.animTime === undefined) box.animTime = 0;
|
|
300
|
+
if (!box.followState) box.followState = null;
|
|
301
|
+
box.animTime += dt;
|
|
302
|
+
|
|
303
|
+
const pathPoints = [
|
|
304
|
+
[-30, 30], [30, 30], [30, -30], [-30, -30],
|
|
305
|
+
];
|
|
306
|
+
|
|
307
|
+
const result = Motion.follow(
|
|
308
|
+
pathPoints,
|
|
309
|
+
true, box.animTime, 6, true,
|
|
310
|
+
Easing.easeInOutSine,
|
|
311
|
+
{},
|
|
312
|
+
box.followState
|
|
313
|
+
);
|
|
314
|
+
box.followState = result.state;
|
|
315
|
+
|
|
316
|
+
// Use Transform API for position and rotation
|
|
317
|
+
box.innerShape.transform.position(result.x, result.y);
|
|
318
|
+
|
|
319
|
+
// Lerp the rotation for smooth turning
|
|
320
|
+
const currentRotation = box.innerShape.rotation * 180 / Math.PI; // Convert from radians to degrees
|
|
321
|
+
const targetRotation = result.angle;
|
|
322
|
+
const newRotation = Tween.lerpAngle(currentRotation, targetRotation, dt * 10);
|
|
323
|
+
box.innerShape.transform.rotation(newRotation);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* AnimationsDemo: A demo Scene that uses a TileLayout to arrange ShapeBoxes
|
|
329
|
+
* Each ShapeBox receives a different inner shape and animates using Transform API
|
|
330
|
+
*/
|
|
331
|
+
class AnimationsDemo extends TileLayout {
|
|
332
|
+
constructor(game, options = {}) {
|
|
333
|
+
super(game, options);
|
|
334
|
+
this.cellSize = 130;
|
|
335
|
+
this.maxColumns = 4;
|
|
336
|
+
this.boxDefinitions = [
|
|
337
|
+
{ type: "hop", innerShape: new Square(30, { color: "white" }) },
|
|
338
|
+
{ type: "spring", innerShape: new Square(30, { color: "white" }) },
|
|
339
|
+
{ type: "bounce", innerShape: new Square(30, { color: "white" }) },
|
|
340
|
+
{ type: "shake", innerShape: new Square(30, { color: "white" }) },
|
|
341
|
+
{ type: "parabolic", innerShape: new Circle(5, { x: -40, y: -40, color: "white" }) },
|
|
342
|
+
{ type: "spiral", innerShape: new Circle(5, { color: "white" }) },
|
|
343
|
+
{ type: "orbit", innerShape: new Circle(5, { color: "white" }) },
|
|
344
|
+
{ type: "float", innerShape: new Circle(5, { color: "white" }) },
|
|
345
|
+
{ type: "bezier", innerShape: new StickFigure(0.3, { stroke: "black" }) },
|
|
346
|
+
{ type: "patrol", innerShape: new StickFigure(0.3, { stroke: "black" }) },
|
|
347
|
+
{ type: "follow", innerShape: new StickFigure(0.3, { stroke: "black" }) },
|
|
348
|
+
{ type: "waypoint", innerShape: new StickFigure(0.3, { stroke: "black" }) },
|
|
349
|
+
{ type: "pulse", innerShape: new Heart({ width: 50, height: 50, color: "white", lineWidth: 3 }) },
|
|
350
|
+
{ type: "oscillate", innerShape: new Arc(20, 0, Math.PI * 1.5, { stroke: "white", lineWidth: 10 }) },
|
|
351
|
+
{ type: "swing", innerShape: new PieSlice(30, 0, Math.PI * 0.3, { color: "white" }) },
|
|
352
|
+
{ type: "pendulum", innerShape: new PieSlice(30, 0, Math.PI * 0.3, { color: "white" }) },
|
|
353
|
+
];
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
init() {
|
|
357
|
+
this.boxes = this.boxDefinitions.map((boxDef) => {
|
|
358
|
+
const innerShape = boxDef.innerShape;
|
|
359
|
+
const type = boxDef.type;
|
|
360
|
+
const shapeBox = new ShapeBox(game, innerShape, type, {
|
|
361
|
+
width: 100,
|
|
362
|
+
height: 100,
|
|
363
|
+
x: 0,
|
|
364
|
+
y: 0,
|
|
365
|
+
});
|
|
366
|
+
// Use Transform API to set dimensions
|
|
367
|
+
shapeBox.transform.size(100, 100);
|
|
368
|
+
shapeBox.animTime = 0;
|
|
369
|
+
this.add(shapeBox);
|
|
370
|
+
return shapeBox;
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
update(dt) {
|
|
375
|
+
if (this.boxes && this.boxes.length > 0) {
|
|
376
|
+
this.boxes.forEach((box) => {
|
|
377
|
+
box.animTime += dt;
|
|
378
|
+
box[box.type](box, dt);
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
super.update(dt);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
onResize() {
|
|
385
|
+
const margin = 40;
|
|
386
|
+
const availableWidth = this.game.width - margin;
|
|
387
|
+
const columns = Math.min(
|
|
388
|
+
this.maxColumns,
|
|
389
|
+
Math.max(1, Math.floor(availableWidth / this.cellSize))
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
if (this.columns !== columns) {
|
|
393
|
+
this.columns = columns;
|
|
394
|
+
this.markBoundsDirty();
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Center the layout
|
|
398
|
+
this.transform.position(
|
|
399
|
+
Math.round(this.game.width / 2),
|
|
400
|
+
Math.round(this.game.height / 2)
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Boilerplate game to run our scene
|
|
406
|
+
export class MyGame extends Game {
|
|
407
|
+
constructor(canvas) {
|
|
408
|
+
super(canvas);
|
|
409
|
+
this.backgroundColor = "black";
|
|
410
|
+
this.enableFluidSize();
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/** Override clear function to give pseudo trailing effect */
|
|
414
|
+
clear() {
|
|
415
|
+
this.ctx.fillStyle = "rgba(0, 0, 0, 0.21)";
|
|
416
|
+
this.ctx.fillRect(0, 0, this.width, this.height);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
init() {
|
|
420
|
+
super.init();
|
|
421
|
+
// Calculate initial columns based on screen width
|
|
422
|
+
const cellSize = 130;
|
|
423
|
+
const maxColumns = 4;
|
|
424
|
+
const margin = 40;
|
|
425
|
+
const initialColumns = Math.min(
|
|
426
|
+
maxColumns,
|
|
427
|
+
Math.max(1, Math.floor((this.width - margin) / cellSize))
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
this.animationsDemo = new AnimationsDemo(this, {
|
|
431
|
+
debug: true,
|
|
432
|
+
anchor: "center",
|
|
433
|
+
spacing: 30,
|
|
434
|
+
columns: initialColumns,
|
|
435
|
+
padding: 30,
|
|
436
|
+
align: "center",
|
|
437
|
+
});
|
|
438
|
+
this.pipeline.add(this.animationsDemo);
|
|
439
|
+
this.pipeline.add(
|
|
440
|
+
new FPSCounter(this, {
|
|
441
|
+
anchor: "bottom-right",
|
|
442
|
+
})
|
|
443
|
+
);
|
|
444
|
+
this.animationsDemo.onResize();
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
onResize() {
|
|
448
|
+
if (this.animationsDemo) {
|
|
449
|
+
this.animationsDemo.onResize();
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Game,
|
|
3
|
+
GameObject,
|
|
4
|
+
Rectangle,
|
|
5
|
+
TextShape,
|
|
6
|
+
Motion,
|
|
7
|
+
Easing,
|
|
8
|
+
Scene,
|
|
9
|
+
Circle,
|
|
10
|
+
Group,
|
|
11
|
+
FPSCounter,
|
|
12
|
+
} from "../../src/index";
|
|
13
|
+
/**
|
|
14
|
+
* HelloWorldBox - A simple GameObject that displays a box with text.
|
|
15
|
+
* The text pulses in and out with a simple animation.
|
|
16
|
+
*/
|
|
17
|
+
class HelloWorldBox extends GameObject {
|
|
18
|
+
/**
|
|
19
|
+
* Create a new HelloWorldBox
|
|
20
|
+
* @param {Game} game - Reference to the main game
|
|
21
|
+
* @param {Object} options - Configuration options
|
|
22
|
+
*/
|
|
23
|
+
constructor(game, options = {}) {
|
|
24
|
+
// Initialize GameObject with game and options
|
|
25
|
+
super(game, options);
|
|
26
|
+
|
|
27
|
+
// Create a group to hold our shapes
|
|
28
|
+
this.group = new Group({});
|
|
29
|
+
|
|
30
|
+
// Create the rectangle background
|
|
31
|
+
this.box = new Rectangle({
|
|
32
|
+
width: 200,
|
|
33
|
+
height: 80,
|
|
34
|
+
color: "#333",
|
|
35
|
+
debug: true,
|
|
36
|
+
debugColor: "#00FF00",
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Create the text label
|
|
40
|
+
this.label = new TextShape("Hello World!", {
|
|
41
|
+
x: 0,
|
|
42
|
+
y: 0,
|
|
43
|
+
font: "18px monospace",
|
|
44
|
+
color: "#0f0",
|
|
45
|
+
align: "center",
|
|
46
|
+
baseline: "middle",
|
|
47
|
+
debug: false,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Add shapes to our group
|
|
51
|
+
this.group.add(this.box);
|
|
52
|
+
this.group.add(this.label);
|
|
53
|
+
|
|
54
|
+
// Initialize animation state
|
|
55
|
+
this.animTime = 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
update(dt) {
|
|
59
|
+
this.animate(dt);
|
|
60
|
+
// Call parent update
|
|
61
|
+
super.update(dt);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Update logic - called each frame
|
|
66
|
+
* @param {number} dt - Delta time in seconds
|
|
67
|
+
*/
|
|
68
|
+
animate(dt) {
|
|
69
|
+
// Track animation time
|
|
70
|
+
if (this.animTime == null) this.animTime = 0;
|
|
71
|
+
this.animTime += dt;
|
|
72
|
+
// Create a pulsing effect on the label opacity
|
|
73
|
+
const result = Motion.pulse(
|
|
74
|
+
0, // Min opacity
|
|
75
|
+
1, // Max opacity
|
|
76
|
+
this.animTime,
|
|
77
|
+
2, // Duration (2 seconds)
|
|
78
|
+
true, // Loop
|
|
79
|
+
false, // No yoyo
|
|
80
|
+
Easing.easeInOutSine
|
|
81
|
+
);
|
|
82
|
+
// Apply the pulse animation
|
|
83
|
+
this.label.opacity = result.value;
|
|
84
|
+
// Add a floating motion to the entire group
|
|
85
|
+
const float = Motion.float(
|
|
86
|
+
{x: 0, y: 0}, // Center point
|
|
87
|
+
this.animTime,
|
|
88
|
+
5, // 5-second cycle
|
|
89
|
+
0.5, // Medium speed
|
|
90
|
+
0.5, // Medium randomness
|
|
91
|
+
50, // Radius of movement
|
|
92
|
+
true,
|
|
93
|
+
Easing.easeInOutSine
|
|
94
|
+
);
|
|
95
|
+
//console.log("float", float);
|
|
96
|
+
// Apply a slight random motion to the group
|
|
97
|
+
this.group.x = float.x;
|
|
98
|
+
this.group.y = float.y;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Render our box - called each frame after update
|
|
103
|
+
*/
|
|
104
|
+
draw() {
|
|
105
|
+
super.draw();
|
|
106
|
+
// Draw the group which contains our shapes
|
|
107
|
+
this.group.render();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* DemoGame - Main game class that sets up the demo
|
|
113
|
+
*/
|
|
114
|
+
export class DemoGame extends Game {
|
|
115
|
+
/**
|
|
116
|
+
* Create a new DemoGame
|
|
117
|
+
* @param {HTMLCanvasElement} canvas - The canvas element to render to
|
|
118
|
+
*/
|
|
119
|
+
constructor(canvas) {
|
|
120
|
+
super(canvas);
|
|
121
|
+
this.enableFluidSize();
|
|
122
|
+
this.backgroundColor = "black";
|
|
123
|
+
|
|
124
|
+
// Log that the game was created
|
|
125
|
+
//console.log("DemoGame created!");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Initialize the game
|
|
130
|
+
* Create scenes, game objects, and set up the game world
|
|
131
|
+
*/
|
|
132
|
+
init() {
|
|
133
|
+
// Call parent init to set up core systems
|
|
134
|
+
super.init();
|
|
135
|
+
// Create main game scene
|
|
136
|
+
this.gameScene = new Scene(this, { width: 400, height: 200 });
|
|
137
|
+
this.gameScene.name = "Game Scene";
|
|
138
|
+
// Create a HelloWorldBox and add it to the game scene
|
|
139
|
+
const box = new HelloWorldBox(this);
|
|
140
|
+
this.gameScene.add(box);
|
|
141
|
+
// Add scenes to the pipeline (order matters - last is on top)
|
|
142
|
+
this.pipeline.add(this.gameScene);
|
|
143
|
+
// Add a floating circle for visual interest
|
|
144
|
+
this.addFloatingCircle();
|
|
145
|
+
//
|
|
146
|
+
this.fpsCounter = new FPSCounter(this, {
|
|
147
|
+
color: "#00FF00",
|
|
148
|
+
debug: false,
|
|
149
|
+
anchor: "bottom-right",
|
|
150
|
+
});
|
|
151
|
+
// Add FPS counter
|
|
152
|
+
this.pipeline.add(this.fpsCounter);
|
|
153
|
+
//console.log("Game initialized with scenes and objects");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
update(dt) {
|
|
157
|
+
super.update(dt);
|
|
158
|
+
this.logger.groupCollapsed("DemoGame.update");
|
|
159
|
+
this.gameScene.x = this.width / 2;
|
|
160
|
+
this.gameScene.y = this.height / 2;
|
|
161
|
+
this.floatingCircle.animTime += dt;
|
|
162
|
+
// Calculate orbit position
|
|
163
|
+
const orbit = Motion.orbit(
|
|
164
|
+
this.gameScene.x,
|
|
165
|
+
this.gameScene.y, // Center Y
|
|
166
|
+
200, // X radius
|
|
167
|
+
200, // Y radius
|
|
168
|
+
0, // Start angle
|
|
169
|
+
this.floatingCircle.animTime, // Current time
|
|
170
|
+
8, // Duration (8 seconds)
|
|
171
|
+
true, // Loop
|
|
172
|
+
true // Clockwise
|
|
173
|
+
);
|
|
174
|
+
//console.log("orbit", orbit);
|
|
175
|
+
// Apply the orbital motion
|
|
176
|
+
this.floatingCircle.x = orbit.x;
|
|
177
|
+
this.floatingCircle.y = orbit.y;
|
|
178
|
+
this.logger.groupEnd();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Add a floating circle to the game.
|
|
183
|
+
* This method demonstrates how the shape and game object can be used interchangeably.
|
|
184
|
+
* Since a Shape is a Transformable, it can be added to the pipeline and will be rendered.
|
|
185
|
+
*/
|
|
186
|
+
addFloatingCircle() {
|
|
187
|
+
// Determine the center position for the orbit
|
|
188
|
+
const centerX = this.width / 2;
|
|
189
|
+
const centerY = this.height / 2;
|
|
190
|
+
|
|
191
|
+
// Create a circle that will float around - set initial position on the orbit path
|
|
192
|
+
this.floatingCircle = new Circle(30, {
|
|
193
|
+
name: "Floating Circle",
|
|
194
|
+
x: centerX + 100, // Start at right side of orbit (centerX + radiusX)
|
|
195
|
+
y: centerY, // Start at center Y
|
|
196
|
+
color: "#00FF00",
|
|
197
|
+
debug: false
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Initialize animation time
|
|
201
|
+
this.floatingCircle.animTime = 0;
|
|
202
|
+
this.pipeline.add(this.floatingCircle);
|
|
203
|
+
}
|
|
204
|
+
}
|