@caperjs/plugin-crunch 0.1.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) Relish Interactive
4
+ Copyright (c) 2026 Anthony Sapp
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,205 @@
1
+ # Crunch Physics Plugin
2
+
3
+ #### @caperjs/physics-crunch
4
+
5
+ A lightweight, grid-based AABB physics plugin for Caper games. Optimized for 2D platformers and games requiring precise, pixel-perfect collisions.
6
+
7
+ ## Features
8
+
9
+ - 🎯 Pixel-perfect AABB collision detection
10
+ - 📦 Grid-based spatial partitioning for efficient collision checks
11
+ - 🎮 Optimized for 2D platformers and action games
12
+ - 🧩 System supports Actors (Dynamic), Solids (Static), and Sensors (Trigger - Dynamic or Static)
13
+ - 🎨 Debug visualization tools
14
+ - 🔄 Object pooling support
15
+ - 🎬 Scene-based integration
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @caperjs/physics-crunch
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```typescript
26
+ // in caper.config.ts
27
+ defineConfig({
28
+ //... other config
29
+ plugins: ['crunch', { autoLoad: false }],
30
+ });
31
+
32
+ // in your scene file
33
+ import { Scene } from '@caperjs/core';
34
+
35
+ // exports
36
+ export const plugins = ['crunch']; // loads the plugin for your scene
37
+
38
+ // in your scene class
39
+ export default class MyCrunchScene extends Scene {
40
+ get physics() {
41
+ return this.app.getPlugin('crunch') as ICrunchPhysicsPlugin;
42
+ }
43
+
44
+ async initialize() {
45
+ await this.physics.initialize({
46
+ gridSize: 32,
47
+ gravity: 980,
48
+ maxVelocity: 1000,
49
+ debug: true,
50
+ });
51
+
52
+ // Create a player
53
+ const player = physics.createActor({
54
+ type: 'Player',
55
+ position: [100, 100],
56
+ size: [32, 64],
57
+ });
58
+
59
+ // Create a platform
60
+ const platform = physics.createSolid({
61
+ type: 'Platform',
62
+ position: [0, 500],
63
+ size: [800, 32],
64
+ });
65
+
66
+ // Create a coin pickup
67
+ const coin = physics.createSensor({
68
+ type: 'Coin',
69
+ position: [200, 400],
70
+ size: [32, 32],
71
+ });
72
+ }
73
+ }
74
+ ```
75
+
76
+ ## Core Components
77
+
78
+ ### Actors
79
+
80
+ Dynamic entities that can move and collide (players, enemies, projectiles).
81
+
82
+ ```typescript
83
+ class Player extends Actor {
84
+ update(dt: number) {
85
+ // Custom movement logic
86
+ if (this.app.input.isKeyDown('ArrowRight')) {
87
+ this.velocity.x = 200;
88
+ }
89
+ }
90
+
91
+ onCollide(result: CollisionResult) {
92
+ // Handle collisions
93
+ if (result.solid.type === 'Spikes') {
94
+ this.die();
95
+ }
96
+ }
97
+ }
98
+ ```
99
+
100
+ ### Solids
101
+
102
+ Static or moving collision objects (platforms, walls, obstacles).
103
+
104
+ ```typescript
105
+ // Create a moving platform
106
+ const platform = physics.createSolid({
107
+ type: 'Platform',
108
+ position: [100, 300],
109
+ size: [200, 32],
110
+ });
111
+
112
+ // Animate platform movement
113
+ gsap.to(platform, {
114
+ x: 500,
115
+ duration: 2,
116
+ yoyo: true,
117
+ repeat: -1,
118
+ });
119
+ ```
120
+
121
+ ### Sensors
122
+
123
+ Trigger zones for detecting overlaps (collectibles, checkpoints, damage zones).
124
+
125
+ ```typescript
126
+ class Coin extends Sensor {
127
+ onActorEnter(actor: Actor) {
128
+ if (actor.type === 'Player') {
129
+ increaseScore(10);
130
+ this.physics.removeSensor(this);
131
+ }
132
+ }
133
+ }
134
+ ```
135
+
136
+ ### Groups
137
+
138
+ Containers for managing collections of entities that move together.
139
+
140
+ ```typescript
141
+ // Create a moving platform with hazards
142
+ const group = physics.createGroup({
143
+ type: 'MovingPlatform',
144
+ position: [100, 300],
145
+ });
146
+
147
+ const platform = physics.createSolid({
148
+ type: 'Platform',
149
+ size: [200, 32],
150
+ });
151
+
152
+ const spikes = physics.createSensor({
153
+ type: 'Spikes',
154
+ position: [0, -32],
155
+ size: [200, 32],
156
+ });
157
+
158
+ group.add(platform);
159
+ group.add(spikes);
160
+ ```
161
+
162
+ ## Advanced Features
163
+
164
+ ### Spatial Partitioning
165
+
166
+ The plugin uses a grid-based spatial partitioning system to efficiently handle collision detection:
167
+
168
+ ```typescript
169
+ // Configure grid size for your game's scale
170
+ physics.system.gridSize = 32;
171
+ ```
172
+
173
+ ### Debug Visualization
174
+
175
+ Enable debug rendering to visualize collision boxes and the spatial grid:
176
+
177
+ ```typescript
178
+ physics.system.debug = true;
179
+ ```
180
+
181
+ ### Collision Resolution
182
+
183
+ Custom collision handling with type-based filtering:
184
+
185
+ ```typescript
186
+ physics.system.setCollisionResolver((collisions) => {
187
+ for (const collision of collisions) {
188
+ // Handle specific collision types
189
+ if (collision.type === 'Player|Enemy') {
190
+ handlePlayerEnemyCollision(collision);
191
+ }
192
+ }
193
+ });
194
+ ```
195
+
196
+ ## Performance Tips
197
+
198
+ - Use appropriate grid sizes for your game's scale
199
+ - Enable culling for large levels
200
+ - Utilize object pooling for frequently created/destroyed entities
201
+ - Use sensor overlaps instead of continuous collision checks where possible
202
+
203
+ ## License
204
+
205
+ MIT © Caper
package/lib/Actor.d.ts ADDED
@@ -0,0 +1,227 @@
1
+ import { Entity } from './Entity';
2
+ import { Solid } from './Solid';
3
+ import { ActorCollisionResult, CollisionResult, EntityData, PhysicsEntityConfig, PhysicsEntityType, Vector2 } from './types';
4
+ /**
5
+ * Dynamic physics entity that can move and collide with other entities.
6
+ * Actors are typically used for players, enemies, projectiles, and other moving game objects.
7
+ *
8
+ * Features:
9
+ * - Velocity-based movement with gravity
10
+ * - Collision detection and response
11
+ * - Solid surface detection (riding)
12
+ * - Automatic culling when out of bounds
13
+ * - Actor-to-actor collision detection
14
+ *
15
+ * @typeParam T - Application type, defaults to base Application
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // Create a player actor
20
+ * class Player extends Actor {
21
+ * constructor() {
22
+ * super({
23
+ * type: 'Player',
24
+ * position: [100, 100],
25
+ * size: [32, 64],
26
+ * view: playerSprite
27
+ * });
28
+ * }
29
+ *
30
+ * // Handle collisions
31
+ * onCollide(result: CollisionResult) {
32
+ * if (result.solid.type === 'Spike') {
33
+ * this.die();
34
+ * }
35
+ * }
36
+ *
37
+ * // Handle actor-to-actor collisions
38
+ * onActorCollide(result: ActorCollisionResult) {
39
+ * if (result.actor.type === 'Enemy') {
40
+ * this.takeDamage(10);
41
+ * }
42
+ * }
43
+ *
44
+ * // Custom movement
45
+ * update(dt: number) {
46
+ * super.update(dt);
47
+ *
48
+ * // Move left/right
49
+ * if (this.app.input.isKeyDown('ArrowLeft')) {
50
+ * this.velocity.x = -200;
51
+ * } else if (this.app.input.isKeyDown('ArrowRight')) {
52
+ * this.velocity.x = 200;
53
+ * }
54
+ *
55
+ * // Jump when on ground
56
+ * if (this.app.input.isKeyPressed('Space') && this.isRidingSolid()) {
57
+ * this.velocity.y = -400;
58
+ * }
59
+ * }
60
+ * }
61
+ * ```
62
+ */
63
+ export declare class Actor<D extends EntityData = EntityData> extends Entity<D> {
64
+ readonly entityType: PhysicsEntityType;
65
+ /** Current velocity in pixels per second */
66
+ velocity: Vector2;
67
+ /** Whether actor-to-actor collisions are disabled for this actor */
68
+ disableActorCollisions: boolean;
69
+ /** Whether the actor should be removed when culled (out of bounds) */
70
+ shouldRemoveOnCull: boolean;
71
+ /** List of current frame collisions */
72
+ collisions: CollisionResult[];
73
+ /** List of current frame actor-to-actor collisions */
74
+ actorCollisions: ActorCollisionResult[];
75
+ /** Cache for isRidingSolid check */
76
+ private _isRidingSolidCache;
77
+ /** Tracks which solid is currently carrying this actor in the current frame */
78
+ private _carriedBy;
79
+ private _carriedByOverlap;
80
+ /** Tracks the grid cells this actor currently occupies */
81
+ private _currentGridCells;
82
+ /**
83
+ * Initialize or reinitialize the actor with new configuration.
84
+ *
85
+ * @param config - Configuration for the actor
86
+ */
87
+ init(config: PhysicsEntityConfig<D>): void;
88
+ /**
89
+ * Called at the start of each update to prepare for collision checks.
90
+ */
91
+ preUpdate(): void;
92
+ /**
93
+ * Updates the actor's position based on velocity and handles collisions.
94
+ *
95
+ * @param dt - Delta time in seconds
96
+ */
97
+ update(dt: number): void;
98
+ /**
99
+ * Called after update to handle post-movement effects.
100
+ */
101
+ postUpdate(): void;
102
+ /**
103
+ * Resets the actor to its initial state.
104
+ */
105
+ reset(): void;
106
+ /**
107
+ * Called when the actor is culled (goes out of bounds).
108
+ * Override this to handle culling differently.
109
+ */
110
+ onCull(): void;
111
+ /**
112
+ * Called when this actor collides with a solid.
113
+ * Override this method to implement custom collision response.
114
+ *
115
+ * @param result - Information about the collision
116
+ */
117
+ onCollide(result: CollisionResult): void;
118
+ /**
119
+ * Called when this actor collides with another actor.
120
+ * Override this method to implement custom actor-to-actor collision response.
121
+ *
122
+ * @param result - Information about the actor collision
123
+ */
124
+ onActorCollide(result: ActorCollisionResult): void;
125
+ /**
126
+ * Checks if this actor is riding the given solid.
127
+ * An actor is riding if it's directly above the solid.
128
+ *
129
+ * @param solid - The solid to check against
130
+ * @returns True if riding the solid
131
+ */
132
+ isRiding(solid: Solid): boolean;
133
+ /**
134
+ * Checks if this actor is riding any solid in the physics system.
135
+ * Uses caching to optimize multiple checks per frame.
136
+ *
137
+ * @returns True if riding any solid
138
+ */
139
+ isRidingSolid(): boolean;
140
+ /**
141
+ * Called when the actor is squeezed between solids.
142
+ * Override this to handle squishing differently.
143
+ */
144
+ squish(result: CollisionResult): void;
145
+ /**
146
+ * Updates the actor's grid cells in the spatial partitioning system.
147
+ * This is called when the actor moves or when its size changes.
148
+ */
149
+ updateGridCells(): void;
150
+ /**
151
+ * Gets the current grid cells this actor occupies
152
+ */
153
+ get currentGridCells(): string[];
154
+ /**
155
+ * Sets the current grid cells this actor occupies
156
+ */
157
+ set currentGridCells(cells: string[]);
158
+ /**
159
+ * Moves the actor horizontally, checking for collisions with solids.
160
+ *
161
+ * @param amount - Distance to move in pixels
162
+ * @param collisionHandler - Optional callback for handling collisions
163
+ * @returns Array of collision results
164
+ */
165
+ moveX(amount: number, collisionHandler?: (result: CollisionResult) => void, pushingSolid?: Solid): CollisionResult[];
166
+ /**
167
+ * Moves the actor vertically, checking for collisions with solids.
168
+ *
169
+ * @param amount - Distance to move in pixels
170
+ * @param collisionHandler - Optional callback for handling collisions
171
+ * @returns Array of collision results
172
+ */
173
+ moveY(amount: number, collisionHandler?: (result: CollisionResult) => void, pushingSolid?: Solid): CollisionResult[];
174
+ /**
175
+ * Updates the actor's view position.
176
+ */
177
+ updateView(): void;
178
+ /**
179
+ * Gets all solids at the specified position that could collide with this actor.
180
+ *
181
+ * @param _x - X position to check
182
+ * @param _y - Y position to check
183
+ * @returns Array of solids at the position
184
+ */
185
+ protected getSolidsAt(_x: number, _y: number): Solid[];
186
+ /**
187
+ * Checks if this actor is colliding with another actor.
188
+ * The collision will only occur if:
189
+ * 1. Both actors are active
190
+ * 2. Neither actor has disabled actor collisions
191
+ * 3. The collision layers and masks match:
192
+ * - (this.collisionLayer & other.collisionMask) !== 0
193
+ * - (other.collisionLayer & this.collisionMask) !== 0
194
+ *
195
+ * @param actor - The actor to check collision with
196
+ * @returns Collision result with information about the collision
197
+ */
198
+ checkActorCollision(actor: Actor): ActorCollisionResult;
199
+ /**
200
+ * Resolves a collision with another actor.
201
+ *
202
+ * @param result - The collision result to resolve
203
+ * @param shouldMove - Whether this actor should move to resolve the collision
204
+ * @returns The updated collision result
205
+ */
206
+ resolveActorCollision(result: ActorCollisionResult): ActorCollisionResult;
207
+ /**
208
+ * Sets the actor's size and updates grid cells if needed.
209
+ *
210
+ * @param width - New width in pixels
211
+ * @param height - New height in pixels
212
+ */
213
+ setSize(width: number, height: number): void;
214
+ /**
215
+ * Sets the actor's width and updates grid cells if needed.
216
+ *
217
+ * @param value - New width in pixels
218
+ */
219
+ setWidth(value: number): void;
220
+ /**
221
+ * Sets the actor's height and updates grid cells if needed.
222
+ *
223
+ * @param value - New height in pixels
224
+ */
225
+ setHeight(value: number): void;
226
+ }
227
+ //# sourceMappingURL=Actor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Actor.d.ts","sourceRoot":"","sources":["../src/Actor.ts"],"names":[],"mappings":"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"}