@guinetik/gcanvas 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gcanvas.es.js +25656 -0
- package/dist/gcanvas.es.min.js +1 -0
- package/dist/gcanvas.umd.js +1 -0
- package/dist/gcanvas.umd.min.js +1 -0
- package/package.json +23 -6
- package/src/game/objects/index.js +1 -0
- package/src/game/objects/spritesheet.js +260 -0
- package/src/game/ui/theme.js +6 -0
- package/src/io/keys.js +9 -1
- package/src/math/boolean.js +481 -0
- package/src/math/index.js +1 -0
- package/.github/workflows/release.yaml +0 -70
- package/.jshintrc +0 -4
- package/.vscode/settings.json +0 -22
- package/CLAUDE.md +0 -310
- package/blackhole.jpg +0 -0
- package/demo.png +0 -0
- package/demos/CNAME +0 -1
- package/demos/animations.html +0 -31
- package/demos/basic.html +0 -38
- package/demos/baskara.html +0 -31
- package/demos/bezier.html +0 -35
- package/demos/beziersignature.html +0 -29
- package/demos/blackhole.html +0 -28
- package/demos/blob.html +0 -35
- package/demos/coordinates.html +0 -698
- package/demos/cube3d.html +0 -23
- package/demos/demos.css +0 -303
- package/demos/dino.html +0 -42
- package/demos/easing.html +0 -28
- package/demos/events.html +0 -195
- package/demos/fluent.html +0 -647
- package/demos/fluid-simple.html +0 -22
- package/demos/fluid.html +0 -37
- package/demos/fractals.html +0 -36
- package/demos/gameobjects.html +0 -626
- package/demos/genart.html +0 -26
- package/demos/gendream.html +0 -26
- package/demos/group.html +0 -36
- package/demos/home.html +0 -587
- package/demos/index.html +0 -376
- package/demos/isometric.html +0 -34
- package/demos/js/animations.js +0 -452
- package/demos/js/basic.js +0 -204
- package/demos/js/baskara.js +0 -751
- package/demos/js/bezier.js +0 -692
- package/demos/js/beziersignature.js +0 -241
- package/demos/js/blackhole/accretiondisk.obj.js +0 -379
- package/demos/js/blackhole/blackhole.obj.js +0 -318
- package/demos/js/blackhole/index.js +0 -409
- package/demos/js/blackhole/particle.js +0 -56
- package/demos/js/blackhole/starfield.obj.js +0 -218
- package/demos/js/blob.js +0 -2276
- package/demos/js/coordinates.js +0 -840
- package/demos/js/cube3d.js +0 -789
- package/demos/js/dino.js +0 -1420
- package/demos/js/easing.js +0 -477
- package/demos/js/fluent.js +0 -183
- package/demos/js/fluid-simple.js +0 -253
- package/demos/js/fluid.js +0 -527
- package/demos/js/fractals.js +0 -931
- package/demos/js/fractalworker.js +0 -93
- package/demos/js/gameobjects.js +0 -176
- package/demos/js/genart.js +0 -268
- package/demos/js/gendream.js +0 -209
- package/demos/js/group.js +0 -140
- package/demos/js/info-toggle.js +0 -25
- package/demos/js/isometric.js +0 -863
- package/demos/js/kerr.js +0 -1556
- package/demos/js/lavalamp.js +0 -590
- package/demos/js/layout.js +0 -354
- package/demos/js/mondrian.js +0 -285
- package/demos/js/opacity.js +0 -275
- package/demos/js/painter.js +0 -484
- package/demos/js/particles-showcase.js +0 -514
- package/demos/js/particles.js +0 -299
- package/demos/js/patterns.js +0 -397
- package/demos/js/penrose/artifact.js +0 -69
- package/demos/js/penrose/blackhole.js +0 -121
- package/demos/js/penrose/constants.js +0 -73
- package/demos/js/penrose/game.js +0 -943
- package/demos/js/penrose/lore.js +0 -278
- package/demos/js/penrose/penrosescene.js +0 -892
- package/demos/js/penrose/ship.js +0 -216
- package/demos/js/penrose/sounds.js +0 -211
- package/demos/js/penrose/voidparticle.js +0 -55
- package/demos/js/penrose/voidscene.js +0 -258
- package/demos/js/penrose/voidship.js +0 -144
- package/demos/js/penrose/wormhole.js +0 -46
- package/demos/js/pipeline.js +0 -555
- package/demos/js/plane3d.js +0 -256
- package/demos/js/platformer.js +0 -1579
- package/demos/js/scene.js +0 -304
- package/demos/js/scenes.js +0 -320
- package/demos/js/schrodinger.js +0 -410
- package/demos/js/schwarzschild.js +0 -1023
- package/demos/js/shapes.js +0 -628
- package/demos/js/space/alien.js +0 -171
- package/demos/js/space/boom.js +0 -98
- package/demos/js/space/boss.js +0 -353
- package/demos/js/space/buff.js +0 -73
- package/demos/js/space/bullet.js +0 -102
- package/demos/js/space/constants.js +0 -85
- package/demos/js/space/game.js +0 -1884
- package/demos/js/space/hud.js +0 -112
- package/demos/js/space/laserbeam.js +0 -179
- package/demos/js/space/lightning.js +0 -277
- package/demos/js/space/minion.js +0 -192
- package/demos/js/space/missile.js +0 -212
- package/demos/js/space/player.js +0 -430
- package/demos/js/space/powerup.js +0 -90
- package/demos/js/space/starfield.js +0 -58
- package/demos/js/space/starpower.js +0 -90
- package/demos/js/spacetime.js +0 -559
- package/demos/js/sphere3d.js +0 -229
- package/demos/js/sprite.js +0 -473
- package/demos/js/svgtween.js +0 -204
- package/demos/js/tde/accretiondisk.js +0 -471
- package/demos/js/tde/blackhole.js +0 -219
- package/demos/js/tde/blackholescene.js +0 -209
- package/demos/js/tde/config.js +0 -59
- package/demos/js/tde/index.js +0 -820
- package/demos/js/tde/jets.js +0 -290
- package/demos/js/tde/lensedstarfield.js +0 -154
- package/demos/js/tde/tdestar.js +0 -297
- package/demos/js/tde/tidalstream.js +0 -372
- package/demos/js/tde_old/blackhole.obj.js +0 -354
- package/demos/js/tde_old/debris.obj.js +0 -791
- package/demos/js/tde_old/flare.obj.js +0 -239
- package/demos/js/tde_old/index.js +0 -448
- package/demos/js/tde_old/star.obj.js +0 -812
- package/demos/js/tiles.js +0 -312
- package/demos/js/tweendemo.js +0 -79
- package/demos/js/visibility.js +0 -102
- package/demos/kerr.html +0 -28
- package/demos/lavalamp.html +0 -27
- package/demos/layouts.html +0 -37
- package/demos/logo.svg +0 -4
- package/demos/loop.html +0 -84
- package/demos/mondrian.html +0 -32
- package/demos/og_image.png +0 -0
- package/demos/opacity.html +0 -36
- package/demos/painter.html +0 -39
- package/demos/particles-showcase.html +0 -28
- package/demos/particles.html +0 -24
- package/demos/patterns.html +0 -33
- package/demos/penrose-game.html +0 -31
- package/demos/pipeline.html +0 -737
- package/demos/plane3d.html +0 -24
- package/demos/platformer.html +0 -43
- package/demos/scene.html +0 -33
- package/demos/scenes.html +0 -96
- package/demos/schrodinger.html +0 -27
- package/demos/schwarzschild.html +0 -27
- package/demos/shapes.html +0 -16
- package/demos/space.html +0 -85
- package/demos/spacetime.html +0 -27
- package/demos/sphere3d.html +0 -24
- package/demos/sprite.html +0 -18
- package/demos/svgtween.html +0 -29
- package/demos/tde.html +0 -28
- package/demos/tiles.html +0 -28
- package/demos/transforms.html +0 -400
- package/demos/tween.html +0 -45
- package/demos/visibility.html +0 -33
- package/docs/README.md +0 -230
- package/docs/api/FluidSystem.md +0 -173
- package/docs/concepts/architecture-overview.md +0 -204
- package/docs/concepts/coordinate-system.md +0 -384
- package/docs/concepts/lifecycle.md +0 -255
- package/docs/concepts/rendering-pipeline.md +0 -279
- package/docs/concepts/shapes-vs-gameobjects.md +0 -187
- package/docs/concepts/tde-zorder.md +0 -106
- package/docs/concepts/two-layer-architecture.md +0 -229
- package/docs/fluid-dynamics.md +0 -99
- package/docs/getting-started/first-game.md +0 -354
- package/docs/getting-started/hello-world.md +0 -269
- package/docs/getting-started/installation.md +0 -175
- package/docs/modules/collision/README.md +0 -453
- package/docs/modules/fluent/README.md +0 -1075
- package/docs/modules/game/README.md +0 -303
- package/docs/modules/isometric-camera.md +0 -210
- package/docs/modules/isometric.md +0 -275
- package/docs/modules/painter/README.md +0 -328
- package/docs/modules/particle/README.md +0 -559
- package/docs/modules/shapes/README.md +0 -221
- package/docs/modules/shapes/base/euclidian.md +0 -123
- package/docs/modules/shapes/base/geometry2d.md +0 -204
- package/docs/modules/shapes/base/renderable.md +0 -215
- package/docs/modules/shapes/base/shape.md +0 -262
- package/docs/modules/shapes/base/transformable.md +0 -243
- package/docs/modules/shapes/hierarchy.md +0 -218
- package/docs/modules/state/README.md +0 -577
- package/docs/modules/util/README.md +0 -99
- package/docs/modules/util/camera3d.md +0 -412
- package/docs/modules/util/scene3d.md +0 -395
- package/index.html +0 -17
- package/jsdoc.json +0 -50
- package/scripts/build-demo.js +0 -69
- package/scripts/bundle4llm.js +0 -276
- package/scripts/clearconsole.js +0 -48
- package/test/math/orbital.test.js +0 -61
- package/test/math/tensor.test.js +0 -114
- package/test/particle/emitter.test.js +0 -204
- package/test/particle/particle-system.test.js +0 -310
- package/test/particle/particle.test.js +0 -116
- package/test/particle/updaters.test.js +0 -386
- package/test/setup.js +0 -120
- package/test/shapes/euclidian.test.js +0 -44
- package/test/shapes/geometry.test.js +0 -86
- package/test/shapes/group.test.js +0 -86
- package/test/shapes/rectangle.test.js +0 -64
- package/test/shapes/transform.test.js +0 -379
- package/test/util/camera3d.test.js +0 -428
- package/test/util/scene3d.test.js +0 -352
- package/vite.config.js +0 -50
- package/vitest.config.js +0 -13
|
@@ -1,453 +0,0 @@
|
|
|
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 '@guinetik/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 '@guinetik/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
|