@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,131 @@
|
|
|
1
|
+
import { GameObject } from "../game/index.js";
|
|
2
|
+
import { Position } from "../util/position.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Applies anchor positioning to a game object
|
|
6
|
+
*
|
|
7
|
+
* @param {GameObject} go - The game object to anchor
|
|
8
|
+
* @param {Object} options - Anchor configuration options
|
|
9
|
+
* @param {string} [options.anchor] - Anchor position (use Position constants)
|
|
10
|
+
* @param {number} [options.anchorMargin=10] - Margin from the edge when anchoring
|
|
11
|
+
* @param {number} [options.anchorOffsetX=0] - Additional X offset to apply after anchoring
|
|
12
|
+
* @param {number} [options.anchorOffsetY=0] - Additional Y offset to apply after anchoring
|
|
13
|
+
* @param {GameObject|boolean} [options.anchorRelative=false] - Object to anchor relative to, or true to use parent
|
|
14
|
+
* @param {boolean} [options.anchorSetTextAlign=true] - Whether to set text alignment properties if available
|
|
15
|
+
* @returns {GameObject} The original game object for chaining
|
|
16
|
+
*/
|
|
17
|
+
export function applyAnchor(go, options = {}) {
|
|
18
|
+
// Ensure we're only applying anchor to GameObjects
|
|
19
|
+
if (!go || !(go instanceof GameObject)) {
|
|
20
|
+
console.warn("applyAnchor can only be applied to GameObject instances");
|
|
21
|
+
return go;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Store anchor properties in a separate namespace to avoid conflicts
|
|
25
|
+
go._anchor = {
|
|
26
|
+
position: options.anchor ?? null,
|
|
27
|
+
margin: options.anchorMargin ?? 10,
|
|
28
|
+
offsetX: options.anchorOffsetX ?? 0,
|
|
29
|
+
offsetY: options.anchorOffsetY ?? 0,
|
|
30
|
+
relative: options.anchorRelative ?? false,
|
|
31
|
+
setTextAlign: options.anchorSetTextAlign !== false,
|
|
32
|
+
lastUpdate: 0, // Track when we last updated positioning
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Keep a reference to the original update method
|
|
36
|
+
const originalUpdate = go.update?.bind(go);
|
|
37
|
+
|
|
38
|
+
// Override the update method
|
|
39
|
+
go.update = function (dt) {
|
|
40
|
+
//console.log("Anchor.update", go.name || go.constructor.name, go.boundsDirty);
|
|
41
|
+
// Skip anchor updates if bounds aren't dirty
|
|
42
|
+
const relativeObj =
|
|
43
|
+
go._anchor.relative === true && go.parent
|
|
44
|
+
? go.parent
|
|
45
|
+
: go._anchor.relative;
|
|
46
|
+
|
|
47
|
+
// Only update positioning when bounds are dirty (geometry changed)
|
|
48
|
+
// or when related objects have changed
|
|
49
|
+
if (
|
|
50
|
+
go._anchor.position &&
|
|
51
|
+
(go.boundsDirty ||
|
|
52
|
+
(relativeObj && relativeObj.boundsDirty) ||
|
|
53
|
+
(go.parent && go.parent.boundsDirty))
|
|
54
|
+
) {
|
|
55
|
+
// Calculate position
|
|
56
|
+
let position;
|
|
57
|
+
|
|
58
|
+
if (relativeObj) {
|
|
59
|
+
// Position relative to another object
|
|
60
|
+
const containerObj = {
|
|
61
|
+
x: relativeObj.x,
|
|
62
|
+
y: relativeObj.y,
|
|
63
|
+
width: relativeObj.width,
|
|
64
|
+
height: relativeObj.height,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
position = Position.calculate(
|
|
68
|
+
go._anchor.position,
|
|
69
|
+
go,
|
|
70
|
+
containerObj,
|
|
71
|
+
go._anchor.margin,
|
|
72
|
+
go._anchor.offsetX,
|
|
73
|
+
go._anchor.offsetY
|
|
74
|
+
);
|
|
75
|
+
} else {
|
|
76
|
+
// Position absolute to the game canvas
|
|
77
|
+
position = Position.calculateAbsolute(
|
|
78
|
+
go._anchor.position,
|
|
79
|
+
go,
|
|
80
|
+
go.game,
|
|
81
|
+
go._anchor.margin,
|
|
82
|
+
go._anchor.offsetX,
|
|
83
|
+
go._anchor.offsetY
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
// Apply the calculated position
|
|
87
|
+
if (go.parent && !isPipelineRoot(go)) {
|
|
88
|
+
// If object has a parent AND is not directly in the pipeline
|
|
89
|
+
if (relativeObj === go.parent) {
|
|
90
|
+
// If anchored relative to parent, use local coordinates
|
|
91
|
+
// (parent position is already accounted for in rendering)
|
|
92
|
+
go.x = position.x - relativeObj.x;
|
|
93
|
+
go.y = position.y - relativeObj.y;
|
|
94
|
+
} else {
|
|
95
|
+
// If anchored to something else or absolutely, convert to local coordinates
|
|
96
|
+
go.x = position.x - go.parent.x;
|
|
97
|
+
go.y = position.y - go.parent.y;
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
// No parent or directly in pipeline - use absolute coordinates
|
|
101
|
+
go.x = position.x;
|
|
102
|
+
go.y = position.y;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Set text alignment if applicable and enabled
|
|
106
|
+
if (go._anchor.setTextAlign) {
|
|
107
|
+
if ("align" in go) go.align = position.align;
|
|
108
|
+
if ("baseline" in go) go.baseline = position.baseline;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Remember the time we last updated
|
|
112
|
+
go._anchor.lastUpdate = go.game ? go.game.lastTime : Date.now();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Call the original update method
|
|
116
|
+
if (originalUpdate) originalUpdate(dt);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// Helper function to determine if an object is directly in the pipeline
|
|
120
|
+
function isPipelineRoot(gameObject) {
|
|
121
|
+
return (
|
|
122
|
+
gameObject.game &&
|
|
123
|
+
gameObject.game.pipeline &&
|
|
124
|
+
gameObject.game.pipeline.gameObjects &&
|
|
125
|
+
gameObject.game.pipeline.gameObjects.includes(gameObject)
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Return the object for chaining
|
|
130
|
+
return go;
|
|
131
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export function applyDraggable(go, options = {}) {
|
|
2
|
+
const game = go.game;
|
|
3
|
+
|
|
4
|
+
// Clear any existing state to avoid duplicates
|
|
5
|
+
go.dragging = false;
|
|
6
|
+
go.dragOffset = { x: 0, y: 0 };
|
|
7
|
+
|
|
8
|
+
// Clean up any existing event handlers to prevent duplicates
|
|
9
|
+
if (go._dragInputMoveHandler) {
|
|
10
|
+
game.events.off("inputmove", go._dragInputMoveHandler);
|
|
11
|
+
}
|
|
12
|
+
if (go._dragInputUpHandler) {
|
|
13
|
+
game.events.off("inputup", go._dragInputUpHandler);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Make sure the object is interactive
|
|
17
|
+
if (typeof go.enableInteractivity === 'function') {
|
|
18
|
+
go.enableInteractivity(go);
|
|
19
|
+
} else {
|
|
20
|
+
go.interactive = true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Define the input handlers and store them on the object to allow cleanup
|
|
24
|
+
go._dragInputDownHandler = (e) => {
|
|
25
|
+
// console.log("Drag input down", go.constructor.name);
|
|
26
|
+
go.dragging = true;
|
|
27
|
+
|
|
28
|
+
// Calculate offset from mouse position to object center
|
|
29
|
+
go.dragOffset.x = go.x - e.x;
|
|
30
|
+
go.dragOffset.y = go.y - e.y;
|
|
31
|
+
|
|
32
|
+
if (options.onDragStart) options.onDragStart();
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
go._dragInputMoveHandler = (e) => {
|
|
36
|
+
//console.log("Drag input move", go.constructor.name, "dragging:", go.dragging);
|
|
37
|
+
if (go.dragging) {
|
|
38
|
+
//console.log("Actually dragging", go.x, go.y, "to", e.x + go.dragOffset.x, e.y + go.dragOffset.y);
|
|
39
|
+
// Directly update position
|
|
40
|
+
go.x = e.x + go.dragOffset.x;
|
|
41
|
+
go.y = e.y + go.dragOffset.y;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
go._dragInputUpHandler = (e) => {
|
|
46
|
+
//console.log("Drag input up", go.constructor.name, "dragging:", go.dragging);
|
|
47
|
+
if (!go.dragging) return;
|
|
48
|
+
|
|
49
|
+
go.dragging = false;
|
|
50
|
+
if (options.onDragEnd) options.onDragEnd();
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Bind the event handlers
|
|
54
|
+
go.on("inputdown", go._dragInputDownHandler);
|
|
55
|
+
game.events.on("inputmove", go._dragInputMoveHandler);
|
|
56
|
+
game.events.on("inputup", go._dragInputUpHandler);
|
|
57
|
+
|
|
58
|
+
// Return a cleanup function
|
|
59
|
+
return () => {
|
|
60
|
+
// Remove event listeners
|
|
61
|
+
go.off("inputdown", go._dragInputDownHandler);
|
|
62
|
+
game.events.off("inputmove", go._dragInputMoveHandler);
|
|
63
|
+
game.events.off("inputup", go._dragInputUpHandler);
|
|
64
|
+
|
|
65
|
+
// Clean up properties
|
|
66
|
+
delete go._dragInputDownHandler;
|
|
67
|
+
delete go._dragInputMoveHandler;
|
|
68
|
+
delete go._dragInputUpHandler;
|
|
69
|
+
delete go.dragging;
|
|
70
|
+
delete go.dragOffset;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { Motion } from "./motion";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Bezier curve motion animation with yoyo support
|
|
5
|
+
*
|
|
6
|
+
* @param {Array<number>} p0 - Start point [x, y]
|
|
7
|
+
* @param {Array<number>} p1 - Control point 1 [x, y]
|
|
8
|
+
* @param {Array<number>} p2 - Control point 2 [x, y]
|
|
9
|
+
* @param {Array<number>} p3 - End point [x, y]
|
|
10
|
+
* @param {number} elapsedTime - Total elapsed time in seconds
|
|
11
|
+
* @param {number} duration - Duration of animation in seconds
|
|
12
|
+
* @param {boolean} [loop=false] - Whether animation should loop
|
|
13
|
+
* @param {boolean} [yoyo=false] - Whether animation should return to start
|
|
14
|
+
* @param {Function} [easingFn=null] - Optional easing function to apply
|
|
15
|
+
* @param {Object} [callbacks] - Optional callback functions
|
|
16
|
+
* @param {Object} [state] - Internal state tracking for callbacks
|
|
17
|
+
* @returns {Object} Animation result with x, y coordinates and metadata
|
|
18
|
+
*/
|
|
19
|
+
export function bezierV1(
|
|
20
|
+
p0,
|
|
21
|
+
p1,
|
|
22
|
+
p2,
|
|
23
|
+
p3,
|
|
24
|
+
elapsedTime,
|
|
25
|
+
duration,
|
|
26
|
+
loop = false,
|
|
27
|
+
yoyo = false,
|
|
28
|
+
easingFn = null,
|
|
29
|
+
callbacks = {},
|
|
30
|
+
state = null
|
|
31
|
+
) {
|
|
32
|
+
// Early return for zero duration
|
|
33
|
+
if (duration <= 0) {
|
|
34
|
+
return Motion.animationResult(
|
|
35
|
+
{ x: p3[0], y: p3[1], phase: "complete" },
|
|
36
|
+
1,
|
|
37
|
+
false,
|
|
38
|
+
true
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Normalize time (0-1) within current cycle
|
|
43
|
+
let t = elapsedTime / duration;
|
|
44
|
+
let yoyoPhase = "forward";
|
|
45
|
+
let loopCount = 0;
|
|
46
|
+
|
|
47
|
+
// Handle looping vs. non-looping
|
|
48
|
+
if (loop) {
|
|
49
|
+
// Calculate loop count (for callbacks)
|
|
50
|
+
loopCount = Math.floor(t);
|
|
51
|
+
|
|
52
|
+
// Use only the fractional part for looping (0-1 repeating)
|
|
53
|
+
t = t % 1;
|
|
54
|
+
|
|
55
|
+
// Call onLoop callback if provided and we crossed a loop boundary
|
|
56
|
+
if (loopCount > 0 && callbacks.onLoop) {
|
|
57
|
+
callbacks.onLoop(loopCount);
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
// Clamp to 1 for non-looping animations
|
|
61
|
+
if (t > 1) t = 1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Call onStart callback if needed (only when animation begins)
|
|
65
|
+
if (t > 0 && elapsedTime <= duration && callbacks.onStart) {
|
|
66
|
+
callbacks.onStart();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Apply easing if provided
|
|
70
|
+
const easedT = easingFn ? easingFn(t) : t;
|
|
71
|
+
|
|
72
|
+
// Adjust time value for yoyo behavior
|
|
73
|
+
let adjustedT = easedT;
|
|
74
|
+
|
|
75
|
+
if (yoyo) {
|
|
76
|
+
// If in the second half of the animation, we're going back
|
|
77
|
+
if (t >= 0.5) {
|
|
78
|
+
// Rescale t to 0-1 for the second half, but reversed
|
|
79
|
+
adjustedT = 1 - (t - 0.5) * 2;
|
|
80
|
+
yoyoPhase = "return";
|
|
81
|
+
|
|
82
|
+
// Call onYoyoTurn callback at the turning point
|
|
83
|
+
if (t >= 0.5 && t < 0.51 && callbacks.onYoyoTurn) {
|
|
84
|
+
callbacks.onYoyoTurn();
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
// First half of animation
|
|
88
|
+
adjustedT = t * 2;
|
|
89
|
+
yoyoPhase = "forward";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Apply easing to the adjusted time if needed
|
|
93
|
+
adjustedT = easingFn ? easingFn(adjustedT) : adjustedT;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Cubic Bezier formula
|
|
97
|
+
const cx = 3 * (p1[0] - p0[0]);
|
|
98
|
+
const bx = 3 * (p2[0] - p1[0]) - cx;
|
|
99
|
+
const ax = p3[0] - p0[0] - cx - bx;
|
|
100
|
+
|
|
101
|
+
const cy = 3 * (p1[1] - p0[1]);
|
|
102
|
+
const by = 3 * (p2[1] - p1[1]) - cy;
|
|
103
|
+
const ay = p3[1] - p0[1] - cy - by;
|
|
104
|
+
|
|
105
|
+
const x =
|
|
106
|
+
ax * Math.pow(adjustedT, 3) +
|
|
107
|
+
bx * Math.pow(adjustedT, 2) +
|
|
108
|
+
cx * adjustedT +
|
|
109
|
+
p0[0];
|
|
110
|
+
const y =
|
|
111
|
+
ay * Math.pow(adjustedT, 3) +
|
|
112
|
+
by * Math.pow(adjustedT, 2) +
|
|
113
|
+
cy * adjustedT +
|
|
114
|
+
p0[1];
|
|
115
|
+
|
|
116
|
+
// Check if non-looping animation is complete
|
|
117
|
+
const isDone = !loop && t >= 1;
|
|
118
|
+
|
|
119
|
+
// Call onComplete if animation has completed
|
|
120
|
+
if (isDone && callbacks.onComplete) {
|
|
121
|
+
callbacks.onComplete();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Return standardized result with phase information
|
|
125
|
+
return Motion.animationResult(
|
|
126
|
+
{ x, y, phase: yoyoPhase },
|
|
127
|
+
t,
|
|
128
|
+
loop,
|
|
129
|
+
isDone,
|
|
130
|
+
state
|
|
131
|
+
);
|
|
132
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Motion } from "./motion";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Bounce animation - object drops and bounces with diminishing height
|
|
5
|
+
*
|
|
6
|
+
* @param {number} maxHeight - Maximum height (negative y value)
|
|
7
|
+
* @param {number} groundY - Ground position (positive y value)
|
|
8
|
+
* @param {number} bounceCount - Number of bounces to perform
|
|
9
|
+
* @param {number} elapsedTime - Total elapsed time in seconds
|
|
10
|
+
* @param {number} duration - Duration of animation in seconds
|
|
11
|
+
* @param {boolean} [loop=false] - Whether animation should loop
|
|
12
|
+
* @param {Function} [easingFn=null] - Optional easing function to apply
|
|
13
|
+
* @param {Object} [callbacks] - Optional callback functions
|
|
14
|
+
* @param {Object} [state] - Internal state tracking for callbacks
|
|
15
|
+
* @returns {Object} Animation result with y position and metadata
|
|
16
|
+
*/
|
|
17
|
+
export function bounceV1(
|
|
18
|
+
maxHeight,
|
|
19
|
+
groundY,
|
|
20
|
+
bounceCount,
|
|
21
|
+
elapsedTime,
|
|
22
|
+
duration,
|
|
23
|
+
loop = false,
|
|
24
|
+
easingFn = null,
|
|
25
|
+
callbacks = {},
|
|
26
|
+
state = null
|
|
27
|
+
) {
|
|
28
|
+
// Update animation time and apply easing
|
|
29
|
+
const {
|
|
30
|
+
t,
|
|
31
|
+
easedT,
|
|
32
|
+
completed,
|
|
33
|
+
state: newState,
|
|
34
|
+
} = Motion._frame(elapsedTime, duration, loop, easingFn, callbacks, state);
|
|
35
|
+
|
|
36
|
+
// Divide the animation into segments based on bounce count
|
|
37
|
+
const segmentSize = 1 / (bounceCount + 1);
|
|
38
|
+
const segment = Math.min(Math.floor(easedT / segmentSize), bounceCount);
|
|
39
|
+
const segmentT = (easedT % segmentSize) / segmentSize;
|
|
40
|
+
|
|
41
|
+
// Calculate bounce height for this segment
|
|
42
|
+
const bounceHeight = maxHeight * Math.pow(0.6, segment);
|
|
43
|
+
|
|
44
|
+
// Use a simple sine wave for each bounce
|
|
45
|
+
// Sin goes from 0 to 1 to 0, we want -maxHeight to groundY to -maxHeight
|
|
46
|
+
// Transform the sin function to get bounce effect
|
|
47
|
+
const normalized = Math.sin(segmentT * Math.PI);
|
|
48
|
+
const y = groundY - normalized * (groundY - bounceHeight);
|
|
49
|
+
|
|
50
|
+
// Return standardized result
|
|
51
|
+
return Motion.animationResult(
|
|
52
|
+
{ y, segment, bounceHeight },
|
|
53
|
+
t,
|
|
54
|
+
loop,
|
|
55
|
+
completed,
|
|
56
|
+
newState
|
|
57
|
+
);
|
|
58
|
+
}
|