@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,303 @@
|
|
|
1
|
+
# Game Module
|
|
2
|
+
|
|
3
|
+
> Core game loop, Pipeline, GameObjects, and Scenes.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The game module provides the interactive layer of GCanvas. It manages the game loop, object lifecycle, input handling, and scene organization.
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import { Game, Scene, GameObject, Circle } from 'gcanvas';
|
|
13
|
+
|
|
14
|
+
class Player extends GameObject {
|
|
15
|
+
constructor(game) {
|
|
16
|
+
super(game);
|
|
17
|
+
this.shape = new Circle(30, { color: 'blue' });
|
|
18
|
+
this.enableInteractivity(this.shape);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
update(dt) {
|
|
22
|
+
if (this.game.input.isKeyDown('ArrowRight')) {
|
|
23
|
+
this.shape.x += 200 * dt;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
render() {
|
|
28
|
+
this.shape.draw();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class MyGame extends Game {
|
|
33
|
+
init() {
|
|
34
|
+
super.init();
|
|
35
|
+
this.enableFluidSize();
|
|
36
|
+
|
|
37
|
+
const scene = new Scene(this);
|
|
38
|
+
scene.add(new Player(this));
|
|
39
|
+
this.pipeline.add(scene);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const game = new MyGame(document.getElementById('canvas'));
|
|
44
|
+
game.start();
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Core Classes
|
|
48
|
+
|
|
49
|
+
| Class | Description |
|
|
50
|
+
|-------|-------------|
|
|
51
|
+
| **Game** | Main loop, canvas management, input initialization |
|
|
52
|
+
| **Pipeline** | Manages object collections, update/render dispatch |
|
|
53
|
+
| **GameObject** | Base class for interactive entities |
|
|
54
|
+
| **Scene** | Hierarchical container for GameObjects |
|
|
55
|
+
|
|
56
|
+
## Game Class
|
|
57
|
+
|
|
58
|
+
The entry point for interactive applications.
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
class MyGame extends Game {
|
|
62
|
+
constructor(canvas) {
|
|
63
|
+
super(canvas);
|
|
64
|
+
this.enableFluidSize(); // Canvas fills viewport
|
|
65
|
+
this.backgroundColor = '#1a1a2e';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
init() {
|
|
69
|
+
super.init(); // Initialize input systems
|
|
70
|
+
// Create scenes and objects
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
update(dt) {
|
|
74
|
+
super.update(dt); // Update pipeline
|
|
75
|
+
// Custom game logic
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
render() {
|
|
79
|
+
super.render(); // Render pipeline
|
|
80
|
+
// Custom rendering
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const game = new MyGame(canvas);
|
|
85
|
+
game.setFPS(60); // Set target FPS
|
|
86
|
+
game.start(); // Begin game loop
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Key Properties
|
|
90
|
+
|
|
91
|
+
| Property | Type | Description |
|
|
92
|
+
|----------|------|-------------|
|
|
93
|
+
| `canvas` | `HTMLCanvasElement` | The canvas element |
|
|
94
|
+
| `ctx` | `CanvasRenderingContext2D` | 2D context |
|
|
95
|
+
| `pipeline` | `Pipeline` | Object manager |
|
|
96
|
+
| `events` | `EventEmitter` | Event system |
|
|
97
|
+
| `width` | `number` | Canvas width |
|
|
98
|
+
| `height` | `number` | Canvas height |
|
|
99
|
+
| `running` | `boolean` | Is loop running? |
|
|
100
|
+
| `dt` | `number` | Last delta time |
|
|
101
|
+
|
|
102
|
+
### Key Methods
|
|
103
|
+
|
|
104
|
+
| Method | Description |
|
|
105
|
+
|--------|-------------|
|
|
106
|
+
| `start()` | Begin the game loop |
|
|
107
|
+
| `stop()` | Stop the game loop |
|
|
108
|
+
| `init()` | Initialize game (override) |
|
|
109
|
+
| `update(dt)` | Update logic (override) |
|
|
110
|
+
| `render()` | Render logic (override) |
|
|
111
|
+
| `enableFluidSize()` | Auto-resize to window |
|
|
112
|
+
| `setFPS(fps)` | Set target frame rate |
|
|
113
|
+
| `enablePauseOnBlur(bool)` | Pause when tab loses focus |
|
|
114
|
+
|
|
115
|
+
## Pipeline Class
|
|
116
|
+
|
|
117
|
+
Manages collections of objects for update and render.
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
// Add objects
|
|
121
|
+
game.pipeline.add(scene);
|
|
122
|
+
game.pipeline.add(gameObject);
|
|
123
|
+
|
|
124
|
+
// Remove objects
|
|
125
|
+
game.pipeline.remove(object);
|
|
126
|
+
|
|
127
|
+
// Clear all
|
|
128
|
+
game.pipeline.clear();
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Pipeline automatically:
|
|
132
|
+
- Calls `update(dt)` on active objects
|
|
133
|
+
- Calls `render()` on visible objects
|
|
134
|
+
- Sorts by zIndex
|
|
135
|
+
- Dispatches input events
|
|
136
|
+
|
|
137
|
+
## GameObject Class
|
|
138
|
+
|
|
139
|
+
Base class for all interactive entities.
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
class Enemy extends GameObject {
|
|
143
|
+
constructor(game) {
|
|
144
|
+
super(game);
|
|
145
|
+
this.shape = new Rectangle({ width: 40, height: 40, color: 'red' });
|
|
146
|
+
this.enableInteractivity(this.shape);
|
|
147
|
+
this.speed = 100;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
update(dt) {
|
|
151
|
+
this.shape.x += this.speed * dt;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
render() {
|
|
155
|
+
this.shape.draw();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Input events
|
|
159
|
+
onPointerDown(e) { }
|
|
160
|
+
onPointerUp(e) { }
|
|
161
|
+
onPointerMove(e) { }
|
|
162
|
+
onMouseOver() { }
|
|
163
|
+
onMouseOut() { }
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Lifecycle Methods
|
|
168
|
+
|
|
169
|
+
| Method | When Called |
|
|
170
|
+
|--------|-------------|
|
|
171
|
+
| `update(dt)` | Every frame (if active) |
|
|
172
|
+
| `render()` | Every frame (if visible) |
|
|
173
|
+
| `destroy()` | When removed from pipeline |
|
|
174
|
+
|
|
175
|
+
### Input Methods
|
|
176
|
+
|
|
177
|
+
| Method | Event |
|
|
178
|
+
|--------|-------|
|
|
179
|
+
| `onPointerDown(e)` | Click/tap start |
|
|
180
|
+
| `onPointerUp(e)` | Click/tap end |
|
|
181
|
+
| `onPointerMove(e)` | Pointer movement |
|
|
182
|
+
| `onMouseOver()` | Hover enter |
|
|
183
|
+
| `onMouseOut()` | Hover leave |
|
|
184
|
+
|
|
185
|
+
## Scene Class
|
|
186
|
+
|
|
187
|
+
Hierarchical container for GameObjects.
|
|
188
|
+
|
|
189
|
+
```js
|
|
190
|
+
const gameScene = new Scene(game);
|
|
191
|
+
const uiScene = new Scene(game);
|
|
192
|
+
|
|
193
|
+
// Add objects to scenes
|
|
194
|
+
gameScene.add(player);
|
|
195
|
+
gameScene.add(enemy);
|
|
196
|
+
|
|
197
|
+
uiScene.add(healthBar);
|
|
198
|
+
uiScene.add(scoreDisplay);
|
|
199
|
+
|
|
200
|
+
// Add scenes to pipeline (order matters)
|
|
201
|
+
game.pipeline.add(gameScene); // Rendered first
|
|
202
|
+
game.pipeline.add(uiScene); // Rendered on top
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Scenes provide:
|
|
206
|
+
- Hierarchical organization
|
|
207
|
+
- Coordinate spaces
|
|
208
|
+
- Z-ordering of children
|
|
209
|
+
- Collective transforms
|
|
210
|
+
|
|
211
|
+
## UI Components
|
|
212
|
+
|
|
213
|
+
Built on GameObject and Scene:
|
|
214
|
+
|
|
215
|
+
| Component | Description |
|
|
216
|
+
|-----------|-------------|
|
|
217
|
+
| `Button` | Clickable with visual states |
|
|
218
|
+
| `ToggleButton` | On/off toggle |
|
|
219
|
+
| `Cursor` | Custom cursor |
|
|
220
|
+
| `FPSCounter` | FPS display |
|
|
221
|
+
|
|
222
|
+
```js
|
|
223
|
+
import { Button, FPSCounter } from 'gcanvas';
|
|
224
|
+
|
|
225
|
+
const button = new Button(game, 'Click Me', {
|
|
226
|
+
x: 400,
|
|
227
|
+
y: 300
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
button.on('click', () => {
|
|
231
|
+
console.log('Clicked!');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
scene.add(button);
|
|
235
|
+
scene.add(new FPSCounter(game, { anchor: 'bottom-right' }));
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Input Access
|
|
239
|
+
|
|
240
|
+
```js
|
|
241
|
+
// In GameObject or Game
|
|
242
|
+
update(dt) {
|
|
243
|
+
// Keyboard
|
|
244
|
+
if (this.game.input.isKeyDown('ArrowLeft')) { }
|
|
245
|
+
if (this.game.input.isKeyDown('Space')) { }
|
|
246
|
+
if (this.game.input.isKeyDown('KeyW')) { }
|
|
247
|
+
|
|
248
|
+
// Mouse position
|
|
249
|
+
const mx = this.game.mouse.x;
|
|
250
|
+
const my = this.game.mouse.y;
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Events
|
|
255
|
+
|
|
256
|
+
```js
|
|
257
|
+
// Custom events
|
|
258
|
+
game.events.on('player-died', (data) => {
|
|
259
|
+
console.log('Player died:', data);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
game.events.emit('player-died', { score: 100 });
|
|
263
|
+
|
|
264
|
+
// Remove listener
|
|
265
|
+
game.events.off('player-died', handler);
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Architecture Diagram
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
┌─────────────────────────────────────────────────────────┐
|
|
272
|
+
│ Game │
|
|
273
|
+
│ ┌────────────────────────────────────────────────────┐ │
|
|
274
|
+
│ │ Pipeline │ │
|
|
275
|
+
│ │ ┌──────────────────────────────────────────────┐ │ │
|
|
276
|
+
│ │ │ Scene │ │ │
|
|
277
|
+
│ │ │ ┌────────────┐ ┌────────────┐ │ │ │
|
|
278
|
+
│ │ │ │ GameObject │ │ GameObject │ ... │ │ │
|
|
279
|
+
│ │ │ │ + Shape │ │ + Shape │ │ │ │
|
|
280
|
+
│ │ │ └────────────┘ └────────────┘ │ │ │
|
|
281
|
+
│ │ └──────────────────────────────────────────────┘ │ │
|
|
282
|
+
│ └────────────────────────────────────────────────────┘ │
|
|
283
|
+
│ │ │
|
|
284
|
+
│ ▼ │
|
|
285
|
+
│ ┌────────────┐ │
|
|
286
|
+
│ │ Game Loop │ │
|
|
287
|
+
│ │ update(dt) │ │
|
|
288
|
+
│ │ render() │ │
|
|
289
|
+
│ └────────────┘ │
|
|
290
|
+
└─────────────────────────────────────────────────────────┘
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Related
|
|
294
|
+
|
|
295
|
+
- [Game Lifecycle](../../concepts/lifecycle.md) - Update/render cycle
|
|
296
|
+
- [Two-Layer Architecture](../../concepts/two-layer-architecture.md) - Shape vs Game layer
|
|
297
|
+
- [First Game Guide](../../getting-started/first-game.md)
|
|
298
|
+
|
|
299
|
+
## See Also
|
|
300
|
+
|
|
301
|
+
- [Shapes Module](../shapes/README.md)
|
|
302
|
+
- [IO Module](../io/README.md) - Input handling
|
|
303
|
+
- [Motion Module](../motion/README.md) - Animation
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# IsometricCamera
|
|
2
|
+
|
|
3
|
+
A camera for isometric views with step-based rotation and smooth animation.
|
|
4
|
+
|
|
5
|
+
Unlike `Camera3D` which provides free 3D rotation, `IsometricCamera` is designed for isometric games where the view rotates in fixed increments (e.g., 45° or 90°), similar to classic games like SimCity or Age of Empires.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Step-based rotation** - Rotate in fixed increments (default 45°)
|
|
10
|
+
- **Smooth animation** - Animated transitions between angles with easing
|
|
11
|
+
- **Easy integration** - Works seamlessly with `IsometricScene`
|
|
12
|
+
- **Multiple easing options** - Choose from various easing functions
|
|
13
|
+
- **Callbacks** - Get notified when rotation starts/ends
|
|
14
|
+
|
|
15
|
+
## Basic Usage
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import { IsometricCamera, IsometricScene } from 'gcanvas';
|
|
19
|
+
|
|
20
|
+
// Create camera with 90° rotation steps (recommended for isometric)
|
|
21
|
+
const camera = new IsometricCamera({
|
|
22
|
+
rotationStep: Math.PI / 2, // 90 degrees (default)
|
|
23
|
+
animationDuration: 0.5 // 500ms transition
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Create scene with camera attached
|
|
27
|
+
const scene = new IsometricScene(game, {
|
|
28
|
+
x: game.width / 2,
|
|
29
|
+
y: game.height / 2,
|
|
30
|
+
camera: camera
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Rotate the view
|
|
34
|
+
camera.rotateRight(); // Rotate 45° clockwise
|
|
35
|
+
camera.rotateLeft(); // Rotate 45° counter-clockwise
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Constructor Options
|
|
39
|
+
|
|
40
|
+
| Option | Type | Default | Description |
|
|
41
|
+
|--------|------|---------|-------------|
|
|
42
|
+
| `angle` | number | `0` | Initial viewing angle in radians |
|
|
43
|
+
| `rotationStep` | number | `Math.PI / 2` | Rotation step size (default 90°). Use 90° for proper isometric look. |
|
|
44
|
+
| `animationDuration` | number | `0.4` | Transition duration in seconds |
|
|
45
|
+
| `easing` | string | `'easeInOutCubic'` | Easing function name |
|
|
46
|
+
|
|
47
|
+
> **Note:** 45° rotation steps can cause visual flattening at certain angles due to how isometric projection works. 90° steps are recommended for the best visual results (like SimCity, Age of Empires).
|
|
48
|
+
|
|
49
|
+
## Available Easing Functions
|
|
50
|
+
|
|
51
|
+
- `linear` - No easing
|
|
52
|
+
- `easeInQuad`, `easeOutQuad`, `easeInOutQuad` - Quadratic
|
|
53
|
+
- `easeInCubic`, `easeOutCubic`, `easeInOutCubic` - Cubic
|
|
54
|
+
- `easeOutBack` - Overshoot effect
|
|
55
|
+
|
|
56
|
+
## API Reference
|
|
57
|
+
|
|
58
|
+
### Methods
|
|
59
|
+
|
|
60
|
+
#### `rotateRight()`
|
|
61
|
+
Rotate view clockwise by one step. Returns `this` for chaining.
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
camera.rotateRight(); // Rotate 45° right
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### `rotateLeft()`
|
|
68
|
+
Rotate view counter-clockwise by one step. Returns `this` for chaining.
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
camera.rotateLeft(); // Rotate 45° left
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### `rotateTo(angle)`
|
|
75
|
+
Rotate to a specific angle (animated).
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
camera.rotateTo(Math.PI / 2); // Rotate to 90°
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### `setAngle(angle)`
|
|
82
|
+
Set angle immediately (no animation).
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
camera.setAngle(0); // Jump to 0° instantly
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### `update(dt)`
|
|
89
|
+
Update camera animation. Call each frame with delta time in seconds.
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
// In your update loop
|
|
93
|
+
camera.update(dt);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
> Note: If using with `IsometricScene`, the scene calls this automatically.
|
|
97
|
+
|
|
98
|
+
#### `isAnimating()`
|
|
99
|
+
Check if camera is currently animating.
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
if (!camera.isAnimating()) {
|
|
103
|
+
// Safe to trigger another rotation
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### `getAngleDegrees()`
|
|
108
|
+
Get current angle in degrees (0-360).
|
|
109
|
+
|
|
110
|
+
#### `getNormalizedAngle()`
|
|
111
|
+
Get angle in radians, normalized to 0-2π range.
|
|
112
|
+
|
|
113
|
+
#### `reset()`
|
|
114
|
+
Reset camera to angle 0.
|
|
115
|
+
|
|
116
|
+
### Callbacks
|
|
117
|
+
|
|
118
|
+
#### `onRotationStart(callback)`
|
|
119
|
+
Set callback for when rotation begins.
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
camera.onRotationStart((startAngle, targetAngle) => {
|
|
123
|
+
console.log(`Rotating from ${startAngle} to ${targetAngle}`);
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### `onRotationEnd(callback)`
|
|
128
|
+
Set callback for when rotation completes.
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
camera.onRotationEnd((finalAngle) => {
|
|
132
|
+
console.log(`Rotation complete at ${finalAngle}`);
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Integration with IsometricScene
|
|
137
|
+
|
|
138
|
+
When attached to an `IsometricScene`, the camera's angle is automatically applied to the `toIsometric()` projection:
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
// Attach camera to scene
|
|
142
|
+
scene.setCamera(camera);
|
|
143
|
+
|
|
144
|
+
// The scene automatically:
|
|
145
|
+
// 1. Updates the camera each frame
|
|
146
|
+
// 2. Applies camera rotation to all projections
|
|
147
|
+
// 3. Handles depth sorting correctly during rotation
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### How It Works
|
|
151
|
+
|
|
152
|
+
The camera modifies the isometric projection by rotating grid coordinates before projecting:
|
|
153
|
+
|
|
154
|
+
```javascript
|
|
155
|
+
// Standard isometric projection
|
|
156
|
+
isoX = (x - y) * (tileWidth / 2)
|
|
157
|
+
isoY = (x + y) * (tileHeight / 2)
|
|
158
|
+
|
|
159
|
+
// With camera rotation
|
|
160
|
+
rotatedX = x * cos(angle) - y * sin(angle)
|
|
161
|
+
rotatedY = x * sin(angle) + y * cos(angle)
|
|
162
|
+
isoX = (rotatedX - rotatedY) * (tileWidth / 2)
|
|
163
|
+
isoY = (rotatedX + rotatedY) * (tileHeight / 2)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## UI Controls Example
|
|
167
|
+
|
|
168
|
+
Add rotation buttons to your game:
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
import { Button, Keys } from 'gcanvas';
|
|
172
|
+
|
|
173
|
+
// Arrow buttons
|
|
174
|
+
const leftBtn = new Button(game, {
|
|
175
|
+
x: 50, y: game.height - 50,
|
|
176
|
+
width: 50, height: 50,
|
|
177
|
+
text: "◀",
|
|
178
|
+
onClick: () => camera.rotateLeft()
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const rightBtn = new Button(game, {
|
|
182
|
+
x: 110, y: game.height - 50,
|
|
183
|
+
width: 50, height: 50,
|
|
184
|
+
text: "▶",
|
|
185
|
+
onClick: () => camera.rotateRight()
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
game.pipeline.add(leftBtn);
|
|
189
|
+
game.pipeline.add(rightBtn);
|
|
190
|
+
|
|
191
|
+
// Keyboard controls (Q/E)
|
|
192
|
+
game.events.on(Keys.Q, () => camera.rotateLeft());
|
|
193
|
+
game.events.on(Keys.E, () => camera.rotateRight());
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Why 90° Rotation Steps?
|
|
197
|
+
|
|
198
|
+
Isometric projection uses the formula:
|
|
199
|
+
- `screenX = (x - y) * tileWidth / 2`
|
|
200
|
+
- `screenY = (x + y) * tileHeight / 2`
|
|
201
|
+
|
|
202
|
+
At 45° rotation angles (like 45°, 135°, 225°, 315°), the `(x + y)` term can become very small, causing the view to appear flat. At 90° increments (0°, 90°, 180°, 270°), the rotation simply swaps axes, maintaining the proper 3D look.
|
|
203
|
+
|
|
204
|
+
This is why classic isometric games like SimCity and Age of Empires use 4-direction rotation (90° steps).
|
|
205
|
+
|
|
206
|
+
## See Also
|
|
207
|
+
|
|
208
|
+
- [IsometricScene](./isometric.md) - Isometric scene rendering
|
|
209
|
+
- [Camera3D](./camera3d.md) - Free 3D rotation camera
|
|
210
|
+
- [Button](./button.md) - UI buttons
|