@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,157 @@
|
|
|
1
|
+
# Installation
|
|
2
|
+
|
|
3
|
+
> How to set up GCanvas in your project.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js 18+ (for development)
|
|
8
|
+
- Modern browser with ES6 support
|
|
9
|
+
|
|
10
|
+
## Option 1: Clone Repository
|
|
11
|
+
|
|
12
|
+
The recommended way to get started:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
git clone https://github.com/guinetik/gcanvas.git
|
|
16
|
+
cd gcanvas
|
|
17
|
+
npm install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Run Development Server
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm run dev
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This starts Vite's dev server with hot reload. Open `http://localhost:5173` to see the demos.
|
|
27
|
+
|
|
28
|
+
### Build the Library
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm run build
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Outputs to `dist/`:
|
|
35
|
+
- `gcanvas.es.js` - ES Module
|
|
36
|
+
- `gcanvas.es.min.js` - ES Module (minified)
|
|
37
|
+
- `gcanvas.umd.js` - UMD bundle
|
|
38
|
+
- `gcanvas.umd.min.js` - UMD bundle (minified)
|
|
39
|
+
|
|
40
|
+
## Option 2: NPM (Coming Soon)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install gcanvas
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Then import in your project:
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
import { Game, Circle, Rectangle } from 'gcanvas';
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Option 3: Direct Script Include
|
|
53
|
+
|
|
54
|
+
### ES Module
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<script type="module">
|
|
58
|
+
import { Circle, Painter } from './dist/gcanvas.es.min.js';
|
|
59
|
+
|
|
60
|
+
const canvas = document.getElementById('canvas');
|
|
61
|
+
Painter.init(canvas.getContext('2d'));
|
|
62
|
+
|
|
63
|
+
const circle = new Circle(50, { x: 100, y: 100, color: 'red' });
|
|
64
|
+
circle.draw();
|
|
65
|
+
</script>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### UMD Bundle
|
|
69
|
+
|
|
70
|
+
```html
|
|
71
|
+
<script src="./dist/gcanvas.umd.min.js"></script>
|
|
72
|
+
<script>
|
|
73
|
+
const { Circle, Painter } = GCanvas;
|
|
74
|
+
|
|
75
|
+
const canvas = document.getElementById('canvas');
|
|
76
|
+
Painter.init(canvas.getContext('2d'));
|
|
77
|
+
|
|
78
|
+
const circle = new GCanvas.Circle(50, { x: 100, y: 100, color: 'red' });
|
|
79
|
+
circle.draw();
|
|
80
|
+
</script>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Project Structure
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
gcanvas/
|
|
87
|
+
├── src/ # Source code
|
|
88
|
+
│ ├── shapes/ # Shape classes
|
|
89
|
+
│ ├── game/ # Game loop, objects
|
|
90
|
+
│ ├── painter/ # Canvas abstraction
|
|
91
|
+
│ ├── motion/ # Animation
|
|
92
|
+
│ ├── io/ # Input handling
|
|
93
|
+
│ └── index.js # Main entry point
|
|
94
|
+
├── demos/ # Demo applications
|
|
95
|
+
├── dist/ # Built library
|
|
96
|
+
└── docs/ # Documentation
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## NPM Scripts
|
|
100
|
+
|
|
101
|
+
| Script | Description |
|
|
102
|
+
|--------|-------------|
|
|
103
|
+
| `npm run dev` | Start development server |
|
|
104
|
+
| `npm run build` | Build library |
|
|
105
|
+
| `npm run build:demo` | Build demos for deployment |
|
|
106
|
+
| `npm run docs` | Generate JSDoc documentation |
|
|
107
|
+
| `npm run test` | Run tests |
|
|
108
|
+
|
|
109
|
+
## TypeScript Support
|
|
110
|
+
|
|
111
|
+
TypeScript definitions are coming soon. For now, the library is written in JavaScript with JSDoc annotations.
|
|
112
|
+
|
|
113
|
+
## Browser Support
|
|
114
|
+
|
|
115
|
+
GCanvas works in all modern browsers:
|
|
116
|
+
|
|
117
|
+
- Chrome 60+
|
|
118
|
+
- Firefox 55+
|
|
119
|
+
- Safari 11+
|
|
120
|
+
- Edge 79+
|
|
121
|
+
|
|
122
|
+
## Next Steps
|
|
123
|
+
|
|
124
|
+
- [Hello World](./hello-world.md) - Draw your first shape
|
|
125
|
+
- [First Game](./first-game.md) - Create an interactive game
|
|
126
|
+
- [Architecture Overview](../concepts/architecture-overview.md) - Understand the design
|
|
127
|
+
|
|
128
|
+
## Troubleshooting
|
|
129
|
+
|
|
130
|
+
### Canvas not found
|
|
131
|
+
|
|
132
|
+
Make sure your canvas element has an ID and the script runs after DOM is ready:
|
|
133
|
+
|
|
134
|
+
```html
|
|
135
|
+
<canvas id="game"></canvas>
|
|
136
|
+
<script type="module">
|
|
137
|
+
// Script runs after DOM is parsed when using type="module"
|
|
138
|
+
const canvas = document.getElementById('game');
|
|
139
|
+
</script>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Module not found
|
|
143
|
+
|
|
144
|
+
When using ES modules, ensure paths are correct:
|
|
145
|
+
|
|
146
|
+
```js
|
|
147
|
+
// Relative path from your script
|
|
148
|
+
import { Circle } from './dist/gcanvas.es.min.js';
|
|
149
|
+
|
|
150
|
+
// Or absolute path
|
|
151
|
+
import { Circle } from '/dist/gcanvas.es.min.js';
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Related
|
|
155
|
+
|
|
156
|
+
- [Hello World](./hello-world.md)
|
|
157
|
+
- [Architecture Overview](../concepts/architecture-overview.md)
|
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
# Collision Module
|
|
2
|
+
|
|
3
|
+
> 2D collision detection utilities and group-based collision management.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The collision module provides both low-level collision detection algorithms and a high-level system for managing collision groups in games. It supports various collision shapes including rectangles, circles, lines, and multi-segment paths.
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import { Collision, CollisionSystem } from 'gcanvas';
|
|
13
|
+
|
|
14
|
+
// Low-level: Direct collision checks
|
|
15
|
+
const playerBounds = player.getBounds();
|
|
16
|
+
const enemyBounds = enemy.getBounds();
|
|
17
|
+
|
|
18
|
+
if (Collision.rectRect(playerBounds, enemyBounds)) {
|
|
19
|
+
console.log('Hit!');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// High-level: Group-based collision management
|
|
23
|
+
const collisions = new CollisionSystem()
|
|
24
|
+
.createGroup('players')
|
|
25
|
+
.createGroup('enemies')
|
|
26
|
+
.createGroup('bullets')
|
|
27
|
+
.onCollision('bullets', 'enemies', (bullet, enemy) => {
|
|
28
|
+
bullet.destroy();
|
|
29
|
+
enemy.takeDamage(10);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// In game loop
|
|
33
|
+
collisions.update();
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Core Classes
|
|
37
|
+
|
|
38
|
+
| Class | Description |
|
|
39
|
+
|-------|-------------|
|
|
40
|
+
| **Collision** | Static utility methods for collision detection |
|
|
41
|
+
| **CollisionSystem** | Group-based collision management with callbacks |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Collision Class
|
|
46
|
+
|
|
47
|
+
Static utility class with various collision detection algorithms. All methods work with bounds objects: `{ x, y, width, height }` for rectangles, `{ x, y, radius }` for circles.
|
|
48
|
+
|
|
49
|
+
### Rectangle vs Rectangle (AABB)
|
|
50
|
+
|
|
51
|
+
The most common collision check - axis-aligned bounding boxes.
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
const a = { x: 100, y: 100, width: 50, height: 50 };
|
|
55
|
+
const b = { x: 120, y: 120, width: 50, height: 50 };
|
|
56
|
+
|
|
57
|
+
if (Collision.rectRect(a, b)) {
|
|
58
|
+
console.log('Rectangles overlap!');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Alias
|
|
62
|
+
Collision.intersects(a, b);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Circle vs Circle
|
|
66
|
+
|
|
67
|
+
For circular hitboxes - more accurate for round objects.
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
const circleA = { x: 100, y: 100, radius: 30 };
|
|
71
|
+
const circleB = { x: 150, y: 100, radius: 25 };
|
|
72
|
+
|
|
73
|
+
if (Collision.circleCircle(circleA, circleB)) {
|
|
74
|
+
console.log('Circles overlap!');
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Circle vs Rectangle
|
|
79
|
+
|
|
80
|
+
Mixed shape collision - finds closest point on rectangle to circle center.
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
const circle = { x: 100, y: 100, radius: 30 };
|
|
84
|
+
const rect = { x: 120, y: 80, width: 60, height: 40 };
|
|
85
|
+
|
|
86
|
+
if (Collision.circleRect(circle, rect)) {
|
|
87
|
+
console.log('Circle and rectangle overlap!');
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Point Collision
|
|
92
|
+
|
|
93
|
+
Check if a point (like mouse cursor) is inside a shape.
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
// Point in rectangle
|
|
97
|
+
if (Collision.pointRect(mouseX, mouseY, button.getBounds())) {
|
|
98
|
+
button.highlight();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Point in circle
|
|
102
|
+
if (Collision.pointCircle(mouseX, mouseY, planet)) {
|
|
103
|
+
showTooltip('Planet selected');
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Line vs Rectangle
|
|
108
|
+
|
|
109
|
+
For laser beams, lightning bolts, and raycast-style collision.
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
// Basic line collision
|
|
113
|
+
if (Collision.lineRect(x1, y1, x2, y2, target.getBounds())) {
|
|
114
|
+
console.log('Line hits target!');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// With thickness (for thick beams)
|
|
118
|
+
if (Collision.lineRect(x1, y1, x2, y2, target.getBounds(), 10)) {
|
|
119
|
+
console.log('Thick beam hits target!');
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Line vs Line
|
|
124
|
+
|
|
125
|
+
Check if two line segments intersect.
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
if (Collision.lineLine(x1, y1, x2, y2, x3, y3, x4, y4)) {
|
|
129
|
+
console.log('Lines cross!');
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Multi-Segment Collision
|
|
134
|
+
|
|
135
|
+
For complex shapes like branching lightning or paths.
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
const lightningSegments = [
|
|
139
|
+
{ x1: 400, y1: 0, x2: 380, y2: 50 },
|
|
140
|
+
{ x1: 380, y1: 50, x2: 420, y2: 100 },
|
|
141
|
+
{ x1: 420, y1: 100, x2: 390, y2: 150 }
|
|
142
|
+
];
|
|
143
|
+
|
|
144
|
+
if (Collision.segmentsRect(lightningSegments, player.getBounds(), 8)) {
|
|
145
|
+
player.takeDamage();
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Collision Response
|
|
150
|
+
|
|
151
|
+
Get information needed to respond to collisions.
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
// Get overlap depth
|
|
155
|
+
const overlap = Collision.getOverlap(playerBounds, wallBounds);
|
|
156
|
+
if (overlap) {
|
|
157
|
+
console.log(`Overlap: ${overlap.x}px x ${overlap.y}px`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Get minimum translation vector (for pushing objects apart)
|
|
161
|
+
const mtv = Collision.getMTV(playerBounds, wallBounds);
|
|
162
|
+
if (mtv) {
|
|
163
|
+
player.x += mtv.x;
|
|
164
|
+
player.y += mtv.y;
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Sweep Test (Continuous Collision)
|
|
169
|
+
|
|
170
|
+
Prevents fast-moving objects from tunneling through thin walls.
|
|
171
|
+
|
|
172
|
+
```js
|
|
173
|
+
const bullet = { x: 100, y: 100, width: 10, height: 10 };
|
|
174
|
+
const wall = { x: 200, y: 50, width: 20, height: 200 };
|
|
175
|
+
const velocityX = 500;
|
|
176
|
+
const velocityY = 0;
|
|
177
|
+
|
|
178
|
+
const hit = Collision.sweep(bullet, velocityX, velocityY, wall);
|
|
179
|
+
if (hit) {
|
|
180
|
+
console.log(`Hit at time: ${hit.time}`);
|
|
181
|
+
console.log(`Normal: ${hit.normalX}, ${hit.normalY}`);
|
|
182
|
+
|
|
183
|
+
// Move to collision point
|
|
184
|
+
bullet.x += velocityX * hit.time;
|
|
185
|
+
bullet.y += velocityY * hit.time;
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Method Reference
|
|
190
|
+
|
|
191
|
+
| Method | Signature | Description |
|
|
192
|
+
|--------|-----------|-------------|
|
|
193
|
+
| `rectRect` | `(a, b)` | AABB collision |
|
|
194
|
+
| `intersects` | `(a, b)` | Alias for rectRect |
|
|
195
|
+
| `circleCircle` | `(a, b)` | Circle collision |
|
|
196
|
+
| `circleRect` | `(circle, rect)` | Mixed shape collision |
|
|
197
|
+
| `pointRect` | `(px, py, rect)` | Point in rectangle |
|
|
198
|
+
| `pointCircle` | `(px, py, circle)` | Point in circle |
|
|
199
|
+
| `lineRect` | `(x1, y1, x2, y2, rect, thickness?)` | Line segment vs rectangle |
|
|
200
|
+
| `lineLine` | `(x1, y1, x2, y2, x3, y3, x4, y4)` | Line vs line |
|
|
201
|
+
| `segmentsRect` | `(segments, rect, thickness?)` | Multi-segment vs rectangle |
|
|
202
|
+
| `getOverlap` | `(a, b)` | Get overlap depth |
|
|
203
|
+
| `getMTV` | `(a, b)` | Get minimum translation vector |
|
|
204
|
+
| `sweep` | `(rect, vx, vy, target)` | Continuous collision detection |
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## CollisionSystem Class
|
|
209
|
+
|
|
210
|
+
High-level system for managing collision groups and callbacks. Ideal for games with multiple entity types.
|
|
211
|
+
|
|
212
|
+
### Creating Groups
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
const collisions = new CollisionSystem();
|
|
216
|
+
|
|
217
|
+
// Create groups for different entity types
|
|
218
|
+
collisions.createGroup('players');
|
|
219
|
+
collisions.createGroup('enemies');
|
|
220
|
+
collisions.createGroup('bullets');
|
|
221
|
+
collisions.createGroup('pickups');
|
|
222
|
+
collisions.createGroup('walls');
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Adding Objects to Groups
|
|
226
|
+
|
|
227
|
+
Objects must have either a `getBounds()` method or a `bounds` property.
|
|
228
|
+
|
|
229
|
+
```js
|
|
230
|
+
// Add single object
|
|
231
|
+
collisions.add('players', player);
|
|
232
|
+
collisions.add('enemies', alien);
|
|
233
|
+
|
|
234
|
+
// Add multiple objects
|
|
235
|
+
aliens.forEach(alien => collisions.add('enemies', alien));
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Registering Collision Callbacks
|
|
239
|
+
|
|
240
|
+
```js
|
|
241
|
+
// When bullets hit enemies
|
|
242
|
+
collisions.onCollision('bullets', 'enemies', (bullet, enemy) => {
|
|
243
|
+
bullet.destroy();
|
|
244
|
+
enemy.takeDamage(10);
|
|
245
|
+
spawnExplosion(enemy.x, enemy.y);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// When player touches pickups
|
|
249
|
+
collisions.onCollision('players', 'pickups', (player, pickup) => {
|
|
250
|
+
pickup.collect();
|
|
251
|
+
player.score += pickup.value;
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// When player hits walls (for collision response)
|
|
255
|
+
collisions.onCollision('players', 'walls', (player, wall) => {
|
|
256
|
+
const mtv = Collision.getMTV(player.getBounds(), wall.getBounds());
|
|
257
|
+
if (mtv) {
|
|
258
|
+
player.x += mtv.x;
|
|
259
|
+
player.y += mtv.y;
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Update Loop
|
|
265
|
+
|
|
266
|
+
Call `update()` each frame to check all registered collision pairs.
|
|
267
|
+
|
|
268
|
+
```js
|
|
269
|
+
class MyGame extends Game {
|
|
270
|
+
update(dt) {
|
|
271
|
+
super.update(dt);
|
|
272
|
+
|
|
273
|
+
// Check all collisions
|
|
274
|
+
this.collisions.update();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Manual Collision Checks
|
|
280
|
+
|
|
281
|
+
For cases where you need more control than callbacks.
|
|
282
|
+
|
|
283
|
+
```js
|
|
284
|
+
// Check specific pair, get all collisions
|
|
285
|
+
const hits = collisions.check('bullets', 'enemies');
|
|
286
|
+
for (const [bullet, enemy] of hits) {
|
|
287
|
+
// Handle collision
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Check one object against a group
|
|
291
|
+
const enemy = collisions.checkAgainstGroup(bullet, 'enemies');
|
|
292
|
+
if (enemy) {
|
|
293
|
+
// First enemy hit
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Get all objects hit
|
|
297
|
+
const allEnemies = collisions.checkAllAgainstGroup(bullet, 'enemies');
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Removing Objects
|
|
301
|
+
|
|
302
|
+
```js
|
|
303
|
+
// Remove from specific group
|
|
304
|
+
collisions.remove('enemies', deadEnemy);
|
|
305
|
+
|
|
306
|
+
// Remove from all groups
|
|
307
|
+
collisions.removeFromAll(destroyedObject);
|
|
308
|
+
|
|
309
|
+
// Clear entire group
|
|
310
|
+
collisions.clearGroup('bullets');
|
|
311
|
+
|
|
312
|
+
// Clear everything
|
|
313
|
+
collisions.clearAll();
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Active Object Filtering
|
|
317
|
+
|
|
318
|
+
CollisionSystem automatically skips inactive objects. It checks for:
|
|
319
|
+
- `obj.active === false`
|
|
320
|
+
- `obj.destroyed === true`
|
|
321
|
+
- `obj.alive === false`
|
|
322
|
+
|
|
323
|
+
```js
|
|
324
|
+
// These objects are automatically skipped
|
|
325
|
+
enemy.active = false; // Skipped
|
|
326
|
+
bullet.destroyed = true; // Skipped
|
|
327
|
+
player.alive = false; // Skipped
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Method Reference
|
|
331
|
+
|
|
332
|
+
| Method | Returns | Description |
|
|
333
|
+
|--------|---------|-------------|
|
|
334
|
+
| `createGroup(name)` | `this` | Create a collision group |
|
|
335
|
+
| `add(group, obj)` | `this` | Add object to group |
|
|
336
|
+
| `remove(group, obj)` | `boolean` | Remove object from group |
|
|
337
|
+
| `removeFromAll(obj)` | `void` | Remove from all groups |
|
|
338
|
+
| `clearGroup(name)` | `void` | Clear all objects in group |
|
|
339
|
+
| `clearAll()` | `void` | Clear all groups |
|
|
340
|
+
| `getGroup(name)` | `Array` | Get all objects in group |
|
|
341
|
+
| `onCollision(a, b, callback)` | `this` | Register collision callback |
|
|
342
|
+
| `offCollision(a, b)` | `void` | Remove collision callback |
|
|
343
|
+
| `update()` | `void` | Check all collision pairs |
|
|
344
|
+
| `check(a, b)` | `Array<[obj, obj]>` | Get all colliding pairs |
|
|
345
|
+
| `checkAgainstGroup(obj, group)` | `Object\|null` | First collision in group |
|
|
346
|
+
| `checkAllAgainstGroup(obj, group)` | `Array` | All collisions in group |
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Complete Example
|
|
351
|
+
|
|
352
|
+
A Space Invaders-style collision setup:
|
|
353
|
+
|
|
354
|
+
```js
|
|
355
|
+
import { Game, CollisionSystem, Collision } from 'gcanvas';
|
|
356
|
+
|
|
357
|
+
class SpaceGame extends Game {
|
|
358
|
+
init() {
|
|
359
|
+
super.init();
|
|
360
|
+
|
|
361
|
+
// Set up collision system
|
|
362
|
+
this.collisions = new CollisionSystem()
|
|
363
|
+
.createGroup('player')
|
|
364
|
+
.createGroup('aliens')
|
|
365
|
+
.createGroup('playerBullets')
|
|
366
|
+
.createGroup('alienBullets')
|
|
367
|
+
.createGroup('shields');
|
|
368
|
+
|
|
369
|
+
// Player bullets hit aliens
|
|
370
|
+
this.collisions.onCollision('playerBullets', 'aliens', (bullet, alien) => {
|
|
371
|
+
bullet.destroy();
|
|
372
|
+
alien.hit();
|
|
373
|
+
this.score += 100;
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// Alien bullets hit player
|
|
377
|
+
this.collisions.onCollision('alienBullets', 'player', (bullet, player) => {
|
|
378
|
+
bullet.destroy();
|
|
379
|
+
this.handlePlayerHit();
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// Any bullet hits shields
|
|
383
|
+
this.collisions.onCollision('playerBullets', 'shields', (bullet, shield) => {
|
|
384
|
+
bullet.destroy();
|
|
385
|
+
shield.damage();
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
this.collisions.onCollision('alienBullets', 'shields', (bullet, shield) => {
|
|
389
|
+
bullet.destroy();
|
|
390
|
+
shield.damage();
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Register initial objects
|
|
394
|
+
this.collisions.add('player', this.player);
|
|
395
|
+
this.aliens.forEach(a => this.collisions.add('aliens', a));
|
|
396
|
+
this.shields.forEach(s => this.collisions.add('shields', s));
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
spawnBullet(bullet, group) {
|
|
400
|
+
this.bullets.push(bullet);
|
|
401
|
+
this.collisions.add(group, bullet);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
update(dt) {
|
|
405
|
+
super.update(dt);
|
|
406
|
+
|
|
407
|
+
// One line handles all collision logic!
|
|
408
|
+
this.collisions.update();
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## Architecture
|
|
416
|
+
|
|
417
|
+
```
|
|
418
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
419
|
+
│ CollisionSystem │
|
|
420
|
+
│ ┌─────────────────────────────────────────────────────┐ │
|
|
421
|
+
│ │ Groups │ │
|
|
422
|
+
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
|
|
423
|
+
│ │ │ players │ │ enemies │ │ bullets │ ... │ │
|
|
424
|
+
│ │ │ Set() │ │ Set() │ │ Set() │ │ │
|
|
425
|
+
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
|
|
426
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
427
|
+
│ │ │
|
|
428
|
+
│ ▼ │
|
|
429
|
+
│ ┌─────────────────────────────────────────────────────┐ │
|
|
430
|
+
│ │ Collision Pairs │ │
|
|
431
|
+
│ │ bullets vs enemies → callback │ │
|
|
432
|
+
│ │ bullets vs player → callback │ │
|
|
433
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
434
|
+
│ │ │
|
|
435
|
+
│ ▼ │
|
|
436
|
+
│ ┌─────────────────────────────────────────────────────┐ │
|
|
437
|
+
│ │ Collision (Static Utils) │ │
|
|
438
|
+
│ │ rectRect() | circleCircle() | lineRect() | ... │ │
|
|
439
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
440
|
+
└─────────────────────────────────────────────────────────────┘
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## Related
|
|
446
|
+
|
|
447
|
+
- [Game Module](../game/README.md) - Game loop and GameObjects
|
|
448
|
+
- [State Module](../state/README.md) - State machines for entity lifecycle
|
|
449
|
+
|
|
450
|
+
## See Also
|
|
451
|
+
|
|
452
|
+
- [Motion Module](../motion/README.md) - Animation and movement
|
|
453
|
+
- [Shapes Module](../shapes/README.md) - Drawing primitives with bounds
|