infernojs 0.0.1 → 0.0.2
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/README.md +10 -52
- package/dist/index.d.mts +26 -81
- package/dist/index.d.ts +26 -81
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,25 +1,18 @@
|
|
|
1
|
-
#
|
|
1
|
+
# infernojs
|
|
2
2
|
|
|
3
|
-
A
|
|
4
|
-
|
|
5
|
-

|
|
3
|
+
A simple library for building 2D games in JavaScript.
|
|
6
4
|
|
|
7
5
|
## Features
|
|
8
6
|
|
|
9
|
-
- **
|
|
7
|
+
- **Collision Detection**
|
|
10
8
|
|
|
11
9
|
- Multiple collision detection strategies for different use cases
|
|
12
10
|
- Support for circles, rectangles, polygons, and line segments
|
|
13
11
|
- Spatial partitioning for optimal performance with large numbers of entities
|
|
14
12
|
- Precise contact point and collision normal information
|
|
15
13
|
|
|
16
|
-
- **
|
|
17
|
-
|
|
18
|
-
- Efficient shape rendering
|
|
19
|
-
- Input handling
|
|
20
|
-
- Animation system
|
|
21
|
-
- Simple physics
|
|
22
|
-
- Game loop management
|
|
14
|
+
- **Camera System**
|
|
15
|
+
- Convert global coordinates to camera coordinates
|
|
23
16
|
|
|
24
17
|
- **Developer-Friendly**
|
|
25
18
|
- Written in TypeScript with full type safety
|
|
@@ -29,7 +22,7 @@ A spicy, high-performance library for building 2D games in JavaScript.
|
|
|
29
22
|
## Installation
|
|
30
23
|
|
|
31
24
|
```bash
|
|
32
|
-
npm install
|
|
25
|
+
npm install infernojs
|
|
33
26
|
```
|
|
34
27
|
|
|
35
28
|
## Usage: Collision Detection
|
|
@@ -37,7 +30,7 @@ npm install pepperjs
|
|
|
37
30
|
### Using Collision Detectors
|
|
38
31
|
|
|
39
32
|
```typescript
|
|
40
|
-
import { BruteForceCollisionDetector, SpatialGridCollisionDetector } from "
|
|
33
|
+
import { BruteForceCollisionDetector, SpatialGridCollisionDetector } from "infernojs";
|
|
41
34
|
|
|
42
35
|
// Create some entities
|
|
43
36
|
const entities = [
|
|
@@ -96,7 +89,7 @@ const physics = new CollisionSystem({
|
|
|
96
89
|
const circleId = physics.addEntity({
|
|
97
90
|
type: "circle",
|
|
98
91
|
shape: {
|
|
99
|
-
center:
|
|
92
|
+
center: { x: 100, y: 100 },
|
|
100
93
|
radius: 50,
|
|
101
94
|
},
|
|
102
95
|
});
|
|
@@ -105,7 +98,7 @@ const circleId = physics.addEntity({
|
|
|
105
98
|
const rectId = physics.addEntity({
|
|
106
99
|
type: "rectangle",
|
|
107
100
|
shape: {
|
|
108
|
-
position:
|
|
101
|
+
position: { x: 120, y: 90 },
|
|
109
102
|
width: 80,
|
|
110
103
|
height: 60,
|
|
111
104
|
},
|
|
@@ -139,7 +132,7 @@ The library uses several techniques to ensure high performance:
|
|
|
139
132
|
|
|
140
133
|
## Choosing the Right Collision Detector
|
|
141
134
|
|
|
142
|
-
|
|
135
|
+
InfernoJS provides different collision detection strategies optimized for different scenarios:
|
|
143
136
|
|
|
144
137
|
- **BruteForceCollisionDetector**: Checks every entity against the given shape
|
|
145
138
|
- Best for small number of entities (< 100)
|
|
@@ -152,47 +145,12 @@ PepperJS provides different collision detection strategies optimized for differe
|
|
|
152
145
|
- Best when you need to check collisions frequently
|
|
153
146
|
- Allows tuning the cell size for optimal performance
|
|
154
147
|
|
|
155
|
-
## Roadmap
|
|
156
|
-
|
|
157
|
-
We're actively working on expanding pepperjs into a comprehensive 2D game development library. Here's what's coming:
|
|
158
|
-
|
|
159
148
|
### Version 0.1.0 (Current)
|
|
160
149
|
|
|
161
150
|
- ✅ High-performance collision detection
|
|
162
151
|
- ✅ Spatial partitioning for efficient collision handling
|
|
163
152
|
- ✅ Support for multiple shape types (circles, rectangles, polygons, line segments)
|
|
164
153
|
|
|
165
|
-
### Version 0.2.0 (Planned)
|
|
166
|
-
|
|
167
|
-
- 🔲 Canvas-based rendering system
|
|
168
|
-
- 🔲 Shape drawing utilities
|
|
169
|
-
- 🔲 Basic sprite support
|
|
170
|
-
- 🔲 Performance optimizations for rendering
|
|
171
|
-
|
|
172
|
-
### Version 0.3.0 (Planned)
|
|
173
|
-
|
|
174
|
-
- 🔲 Input handling (keyboard, mouse, touch)
|
|
175
|
-
- 🔲 Game loop management
|
|
176
|
-
- 🔲 Time-based animation system
|
|
177
|
-
|
|
178
|
-
### Version 0.4.0 (Planned)
|
|
179
|
-
|
|
180
|
-
- 🔲 Simple physics engine (forces, gravity, etc.)
|
|
181
|
-
- 🔲 Constraints and joints
|
|
182
|
-
- 🔲 Integration with collision system
|
|
183
|
-
|
|
184
|
-
### Version 0.5.0 (Planned)
|
|
185
|
-
|
|
186
|
-
- 🔲 Entity-component system
|
|
187
|
-
- 🔲 Particle systems
|
|
188
|
-
- 🔲 Camera and viewport management
|
|
189
|
-
|
|
190
|
-
### Future Additions
|
|
191
|
-
|
|
192
|
-
- 🔲 WebGL renderer option
|
|
193
|
-
- 🔲 Sound system
|
|
194
|
-
- 🔲 Tile maps and level loading
|
|
195
|
-
- 🔲 UI components
|
|
196
154
|
|
|
197
155
|
## Examples
|
|
198
156
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Entity, Shape,
|
|
2
|
-
export {
|
|
1
|
+
import { Entity, Shape, Vector2D, Point, Circle, Rectangle, AABB } from './types.mjs';
|
|
2
|
+
export { CollisionConfig, CollisionResult, ContactPoint, ShapeType } from './types.mjs';
|
|
3
3
|
export { aabbIntersect, add, cellToId, circleToAABB, cross, distance, distanceSquared, dot, length, lengthSquared, normalize, positionToCell, rectToAABB, scale, subtract, vec2 } from './utils.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -18,9 +18,9 @@ declare abstract class BaseCollisionDetector {
|
|
|
18
18
|
/**
|
|
19
19
|
* Get all entities that collide with the given shape
|
|
20
20
|
* @param shape The shape to check collisions against
|
|
21
|
-
* @returns Array of
|
|
21
|
+
* @returns Array of entities that collide with the shape
|
|
22
22
|
*/
|
|
23
|
-
abstract getCollisions(shape: Shape):
|
|
23
|
+
abstract getCollisions(shape: Shape): Entity[];
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -39,9 +39,9 @@ declare class BruteForceCollisionDetectorImpl extends BaseCollisionDetector {
|
|
|
39
39
|
/**
|
|
40
40
|
* Get all entities that collide with the given shape
|
|
41
41
|
* @param shape The shape to check collisions against
|
|
42
|
-
* @returns Array of
|
|
42
|
+
* @returns Array of entities that collide with the shape
|
|
43
43
|
*/
|
|
44
|
-
getCollisions(shape: Shape):
|
|
44
|
+
getCollisions(shape: Shape): Entity[];
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/**
|
|
@@ -75,7 +75,7 @@ declare class SpatialGridCollisionDetectorImpl extends BaseCollisionDetector {
|
|
|
75
75
|
/**
|
|
76
76
|
* Get all entities that collide with the given shape
|
|
77
77
|
*/
|
|
78
|
-
getCollisions(shape: Shape):
|
|
78
|
+
getCollisions(shape: Shape): Entity[];
|
|
79
79
|
/**
|
|
80
80
|
* Rebuild the spatial grid with the current entities
|
|
81
81
|
*/
|
|
@@ -107,90 +107,35 @@ declare class SpatialGridCollisionDetectorImpl extends BaseCollisionDetector {
|
|
|
107
107
|
declare function checkShapeCollision(shapeA: Shape, shapeB: Shape): boolean;
|
|
108
108
|
|
|
109
109
|
/**
|
|
110
|
-
*
|
|
111
|
-
*/
|
|
112
|
-
type
|
|
113
|
-
/**
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
|
|
121
|
-
/** Shadow blur radius */
|
|
122
|
-
shadowBlur?: number;
|
|
123
|
-
/** Shadow color */
|
|
124
|
-
shadowColor?: string;
|
|
125
|
-
/** Shadow offset X */
|
|
126
|
-
shadowOffsetX?: number;
|
|
127
|
-
/** Shadow offset Y */
|
|
128
|
-
shadowOffsetY?: number;
|
|
129
|
-
};
|
|
130
|
-
/**
|
|
131
|
-
* A renderable entity with shape and style
|
|
132
|
-
*/
|
|
133
|
-
type RenderableShape = {
|
|
134
|
-
shape: Shape;
|
|
135
|
-
style: ShapeStyle;
|
|
136
|
-
};
|
|
137
|
-
/**
|
|
138
|
-
* Configuration options for the renderer
|
|
139
|
-
*/
|
|
140
|
-
type RendererOptions = {
|
|
141
|
-
/** Background color of the canvas */
|
|
142
|
-
backgroundColor?: string;
|
|
143
|
-
/** Default style to apply to shapes without specific styling */
|
|
144
|
-
defaultStyle?: ShapeStyle;
|
|
145
|
-
/** Whether to clear the canvas before each render */
|
|
146
|
-
clearBeforeRender?: boolean;
|
|
110
|
+
* Configuration for the camera
|
|
111
|
+
*/
|
|
112
|
+
type CameraConfig = {
|
|
113
|
+
/** Center position of the camera in world coordinates */
|
|
114
|
+
position: Vector2D;
|
|
115
|
+
/** Width of the viewport/canvas in pixels */
|
|
116
|
+
width: number;
|
|
117
|
+
/** Height of the viewport/canvas in pixels */
|
|
118
|
+
height: number;
|
|
119
|
+
/** Rotation in degrees (optional, defaults to 0) */
|
|
120
|
+
rotation?: number;
|
|
147
121
|
};
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Apply style settings to the canvas context
|
|
151
|
-
*/
|
|
152
|
-
declare function applyStyle(ctx: CanvasRenderingContext2D, style: ShapeStyle): void;
|
|
153
|
-
/**
|
|
154
|
-
* Restore the canvas context to its previous state
|
|
155
|
-
*/
|
|
156
|
-
declare function restoreContext(ctx: CanvasRenderingContext2D): void;
|
|
157
|
-
/**
|
|
158
|
-
* Render a circle shape
|
|
159
|
-
*/
|
|
160
|
-
declare function renderCircle(ctx: CanvasRenderingContext2D, circle: Circle, style: ShapeStyle): void;
|
|
161
|
-
/**
|
|
162
|
-
* Render a point shape
|
|
163
|
-
*/
|
|
164
|
-
declare function renderPoint(ctx: CanvasRenderingContext2D, point: Point, style: ShapeStyle): void;
|
|
165
|
-
/**
|
|
166
|
-
* Render a rectangle shape
|
|
167
|
-
*/
|
|
168
|
-
declare function renderRectangle(ctx: CanvasRenderingContext2D, rectangle: Rectangle, style: ShapeStyle): void;
|
|
169
|
-
/**
|
|
170
|
-
* Render any shape based on its type
|
|
171
|
-
*/
|
|
172
|
-
declare function renderShape(ctx: CanvasRenderingContext2D, shape: Shape, style: ShapeStyle): void;
|
|
173
122
|
/**
|
|
174
|
-
*
|
|
123
|
+
* Converts a global coordinate object into a local camera coordinate system.
|
|
175
124
|
*/
|
|
176
|
-
declare function
|
|
125
|
+
declare function globalCoordinatesToCameraCoordinates(global: Vector2D, camera: CameraConfig): Vector2D;
|
|
126
|
+
declare function globalCoordinatesToCameraCoordinates(global: Point, camera: CameraConfig): Point;
|
|
127
|
+
declare function globalCoordinatesToCameraCoordinates(global: Circle, camera: CameraConfig): Circle;
|
|
128
|
+
declare function globalCoordinatesToCameraCoordinates(global: Rectangle, camera: CameraConfig): Rectangle;
|
|
129
|
+
declare function globalCoordinatesToCameraCoordinates(global: AABB, camera: CameraConfig): AABB;
|
|
177
130
|
|
|
178
131
|
/**
|
|
179
|
-
*
|
|
132
|
+
* InfernoJS
|
|
180
133
|
* A spicy, high-performance library for building 2D games in JavaScript
|
|
181
134
|
*
|
|
182
135
|
* @packageDocumentation
|
|
183
136
|
*/
|
|
184
137
|
|
|
185
138
|
declare const VERSION = "0.0.1";
|
|
186
|
-
/**
|
|
187
|
-
* @internal
|
|
188
|
-
* Rendering capabilities
|
|
189
|
-
*/
|
|
190
|
-
declare const Renderer: {
|
|
191
|
-
notImplemented: boolean;
|
|
192
|
-
info: string;
|
|
193
|
-
};
|
|
194
139
|
/**
|
|
195
140
|
* @internal
|
|
196
141
|
* Future game loop management API
|
|
@@ -208,4 +153,4 @@ declare const Input: {
|
|
|
208
153
|
info: string;
|
|
209
154
|
};
|
|
210
155
|
|
|
211
|
-
export { BaseCollisionDetector, BruteForceCollisionDetector, Circle, Entity, GameLoop, Input, Point, Rectangle,
|
|
156
|
+
export { AABB, BaseCollisionDetector, BruteForceCollisionDetector, type CameraConfig, Circle, Entity, GameLoop, Input, Point, Rectangle, Shape, SpatialGridCollisionDetector, type SpatialGridConfig, VERSION, Vector2D, checkShapeCollision, globalCoordinatesToCameraCoordinates };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Entity, Shape,
|
|
2
|
-
export {
|
|
1
|
+
import { Entity, Shape, Vector2D, Point, Circle, Rectangle, AABB } from './types.js';
|
|
2
|
+
export { CollisionConfig, CollisionResult, ContactPoint, ShapeType } from './types.js';
|
|
3
3
|
export { aabbIntersect, add, cellToId, circleToAABB, cross, distance, distanceSquared, dot, length, lengthSquared, normalize, positionToCell, rectToAABB, scale, subtract, vec2 } from './utils.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -18,9 +18,9 @@ declare abstract class BaseCollisionDetector {
|
|
|
18
18
|
/**
|
|
19
19
|
* Get all entities that collide with the given shape
|
|
20
20
|
* @param shape The shape to check collisions against
|
|
21
|
-
* @returns Array of
|
|
21
|
+
* @returns Array of entities that collide with the shape
|
|
22
22
|
*/
|
|
23
|
-
abstract getCollisions(shape: Shape):
|
|
23
|
+
abstract getCollisions(shape: Shape): Entity[];
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -39,9 +39,9 @@ declare class BruteForceCollisionDetectorImpl extends BaseCollisionDetector {
|
|
|
39
39
|
/**
|
|
40
40
|
* Get all entities that collide with the given shape
|
|
41
41
|
* @param shape The shape to check collisions against
|
|
42
|
-
* @returns Array of
|
|
42
|
+
* @returns Array of entities that collide with the shape
|
|
43
43
|
*/
|
|
44
|
-
getCollisions(shape: Shape):
|
|
44
|
+
getCollisions(shape: Shape): Entity[];
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/**
|
|
@@ -75,7 +75,7 @@ declare class SpatialGridCollisionDetectorImpl extends BaseCollisionDetector {
|
|
|
75
75
|
/**
|
|
76
76
|
* Get all entities that collide with the given shape
|
|
77
77
|
*/
|
|
78
|
-
getCollisions(shape: Shape):
|
|
78
|
+
getCollisions(shape: Shape): Entity[];
|
|
79
79
|
/**
|
|
80
80
|
* Rebuild the spatial grid with the current entities
|
|
81
81
|
*/
|
|
@@ -107,90 +107,35 @@ declare class SpatialGridCollisionDetectorImpl extends BaseCollisionDetector {
|
|
|
107
107
|
declare function checkShapeCollision(shapeA: Shape, shapeB: Shape): boolean;
|
|
108
108
|
|
|
109
109
|
/**
|
|
110
|
-
*
|
|
111
|
-
*/
|
|
112
|
-
type
|
|
113
|
-
/**
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
|
|
121
|
-
/** Shadow blur radius */
|
|
122
|
-
shadowBlur?: number;
|
|
123
|
-
/** Shadow color */
|
|
124
|
-
shadowColor?: string;
|
|
125
|
-
/** Shadow offset X */
|
|
126
|
-
shadowOffsetX?: number;
|
|
127
|
-
/** Shadow offset Y */
|
|
128
|
-
shadowOffsetY?: number;
|
|
129
|
-
};
|
|
130
|
-
/**
|
|
131
|
-
* A renderable entity with shape and style
|
|
132
|
-
*/
|
|
133
|
-
type RenderableShape = {
|
|
134
|
-
shape: Shape;
|
|
135
|
-
style: ShapeStyle;
|
|
136
|
-
};
|
|
137
|
-
/**
|
|
138
|
-
* Configuration options for the renderer
|
|
139
|
-
*/
|
|
140
|
-
type RendererOptions = {
|
|
141
|
-
/** Background color of the canvas */
|
|
142
|
-
backgroundColor?: string;
|
|
143
|
-
/** Default style to apply to shapes without specific styling */
|
|
144
|
-
defaultStyle?: ShapeStyle;
|
|
145
|
-
/** Whether to clear the canvas before each render */
|
|
146
|
-
clearBeforeRender?: boolean;
|
|
110
|
+
* Configuration for the camera
|
|
111
|
+
*/
|
|
112
|
+
type CameraConfig = {
|
|
113
|
+
/** Center position of the camera in world coordinates */
|
|
114
|
+
position: Vector2D;
|
|
115
|
+
/** Width of the viewport/canvas in pixels */
|
|
116
|
+
width: number;
|
|
117
|
+
/** Height of the viewport/canvas in pixels */
|
|
118
|
+
height: number;
|
|
119
|
+
/** Rotation in degrees (optional, defaults to 0) */
|
|
120
|
+
rotation?: number;
|
|
147
121
|
};
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Apply style settings to the canvas context
|
|
151
|
-
*/
|
|
152
|
-
declare function applyStyle(ctx: CanvasRenderingContext2D, style: ShapeStyle): void;
|
|
153
|
-
/**
|
|
154
|
-
* Restore the canvas context to its previous state
|
|
155
|
-
*/
|
|
156
|
-
declare function restoreContext(ctx: CanvasRenderingContext2D): void;
|
|
157
|
-
/**
|
|
158
|
-
* Render a circle shape
|
|
159
|
-
*/
|
|
160
|
-
declare function renderCircle(ctx: CanvasRenderingContext2D, circle: Circle, style: ShapeStyle): void;
|
|
161
|
-
/**
|
|
162
|
-
* Render a point shape
|
|
163
|
-
*/
|
|
164
|
-
declare function renderPoint(ctx: CanvasRenderingContext2D, point: Point, style: ShapeStyle): void;
|
|
165
|
-
/**
|
|
166
|
-
* Render a rectangle shape
|
|
167
|
-
*/
|
|
168
|
-
declare function renderRectangle(ctx: CanvasRenderingContext2D, rectangle: Rectangle, style: ShapeStyle): void;
|
|
169
|
-
/**
|
|
170
|
-
* Render any shape based on its type
|
|
171
|
-
*/
|
|
172
|
-
declare function renderShape(ctx: CanvasRenderingContext2D, shape: Shape, style: ShapeStyle): void;
|
|
173
122
|
/**
|
|
174
|
-
*
|
|
123
|
+
* Converts a global coordinate object into a local camera coordinate system.
|
|
175
124
|
*/
|
|
176
|
-
declare function
|
|
125
|
+
declare function globalCoordinatesToCameraCoordinates(global: Vector2D, camera: CameraConfig): Vector2D;
|
|
126
|
+
declare function globalCoordinatesToCameraCoordinates(global: Point, camera: CameraConfig): Point;
|
|
127
|
+
declare function globalCoordinatesToCameraCoordinates(global: Circle, camera: CameraConfig): Circle;
|
|
128
|
+
declare function globalCoordinatesToCameraCoordinates(global: Rectangle, camera: CameraConfig): Rectangle;
|
|
129
|
+
declare function globalCoordinatesToCameraCoordinates(global: AABB, camera: CameraConfig): AABB;
|
|
177
130
|
|
|
178
131
|
/**
|
|
179
|
-
*
|
|
132
|
+
* InfernoJS
|
|
180
133
|
* A spicy, high-performance library for building 2D games in JavaScript
|
|
181
134
|
*
|
|
182
135
|
* @packageDocumentation
|
|
183
136
|
*/
|
|
184
137
|
|
|
185
138
|
declare const VERSION = "0.0.1";
|
|
186
|
-
/**
|
|
187
|
-
* @internal
|
|
188
|
-
* Rendering capabilities
|
|
189
|
-
*/
|
|
190
|
-
declare const Renderer: {
|
|
191
|
-
notImplemented: boolean;
|
|
192
|
-
info: string;
|
|
193
|
-
};
|
|
194
139
|
/**
|
|
195
140
|
* @internal
|
|
196
141
|
* Future game loop management API
|
|
@@ -208,4 +153,4 @@ declare const Input: {
|
|
|
208
153
|
info: string;
|
|
209
154
|
};
|
|
210
155
|
|
|
211
|
-
export { BaseCollisionDetector, BruteForceCollisionDetector, Circle, Entity, GameLoop, Input, Point, Rectangle,
|
|
156
|
+
export { AABB, BaseCollisionDetector, BruteForceCollisionDetector, type CameraConfig, Circle, Entity, GameLoop, Input, Point, Rectangle, Shape, SpatialGridCollisionDetector, type SpatialGridConfig, VERSION, Vector2D, checkShapeCollision, globalCoordinatesToCameraCoordinates };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var B=Object.defineProperty;var
|
|
1
|
+
"use strict";var B=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var j=(t,o)=>{for(var n in o)B(t,n,{get:o[n],enumerable:!0})},z=(t,o,n,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let e of v(o))!F.call(t,e)&&e!==n&&B(t,e,{get:()=>o[e],enumerable:!(i=Y(o,e))||i.enumerable});return t};var k=t=>z(B({},"__esModule",{value:!0}),t);var et={};j(et,{BaseCollisionDetector:()=>m,BruteForceCollisionDetector:()=>Z,GameLoop:()=>nt,Input:()=>it,SpatialGridCollisionDetector:()=>_,VERSION:()=>ot,aabbIntersect:()=>S,add:()=>U,cellToId:()=>P,checkShapeCollision:()=>y,circleToAABB:()=>V,cross:()=>L,distance:()=>N,distanceSquared:()=>x,dot:()=>g,globalCoordinatesToCameraCoordinates:()=>tt,length:()=>b,lengthSquared:()=>E,normalize:()=>h,positionToCell:()=>R,rectToAABB:()=>d,scale:()=>H,subtract:()=>C,vec2:()=>O});module.exports=k(et);function O(t,o){return{x:t,y:o}}function U(t,o){return{x:t.x+o.x,y:t.y+o.y}}function C(t,o){return{x:t.x-o.x,y:t.y-o.y}}function H(t,o){return{x:t.x*o,y:t.y*o}}function g(t,o){return t.x*o.x+t.y*o.y}function L(t,o){return t.x*o.y-t.y*o.x}function E(t){return t.x*t.x+t.y*t.y}function b(t){return Math.sqrt(E(t))}function h(t){let o=b(t);return o<1e-10?{x:0,y:0}:{x:t.x/o,y:t.y/o}}function x(t,o){let n=o.x-t.x,i=o.y-t.y;return n*n+i*i}function N(t,o){return Math.sqrt(x(t,o))}function d(t){return{min:{x:t.position.x,y:t.position.y},max:{x:t.position.x+t.width,y:t.position.y+t.height}}}function V(t){return{min:{x:t.center.x-t.radius,y:t.center.y-t.radius},max:{x:t.center.x+t.radius,y:t.center.y+t.radius}}}function S(t,o){return!(t.max.x<o.min.x||t.min.x>o.max.x||t.max.y<o.min.y||t.min.y>o.max.y)}function R(t,o){return[Math.floor(t.x/o),Math.floor(t.y/o)]}function P(t,o){return(t+o)*(t+o+1)/2+o}var m=class{constructor(o){this.entities=o}};function T(t,o){let n=x(t.center,o.center),i=t.radius+o.radius;return{colliding:n<=i*i}}function M(t,o){return{colliding:x(t.center,o.position)<=t.radius*t.radius}}function D(t,o){if(o.rotationDeg!==0)return W(t,o);let n=Math.max(o.position.x,Math.min(t.center.x,o.position.x+o.width)),i=Math.max(o.position.y,Math.min(t.center.y,o.position.y+o.height));return{colliding:x(t.center,{x:n,y:i})<=t.radius*t.radius}}function W(t,o){let n=o.rotationDeg*Math.PI/180,i=Math.cos(-n),e=Math.sin(-n),r=o.position.x+o.width/2,s=o.position.y+o.height/2,c=t.center.x-r,l=t.center.y-s,a=i*c-e*l,u=e*c+i*l,f={type:"circle",center:{x:a+r,y:u+s},radius:t.radius},p={type:"rectangle",position:o.position,width:o.width,height:o.height,rotationDeg:0};return D(f,p)}function A(t,o){return t.rotationDeg!==0?$(t,o):{colliding:o.position.x>=t.position.x&&o.position.x<=t.position.x+t.width&&o.position.y>=t.position.y&&o.position.y<=t.position.y+t.height}}function $(t,o){let n=t.rotationDeg*Math.PI/180,i=Math.cos(-n),e=Math.sin(-n),r=t.position.x+t.width/2,s=t.position.y+t.height/2,c=o.position.x-r,l=o.position.y-s,a=i*c-e*l,u=e*c+i*l,f={type:"point",position:{x:a+r,y:u+s}},p={type:"rectangle",position:{x:t.position.x,y:t.position.y},width:t.width,height:t.height,rotationDeg:0};return A(p,f)}function X(t,o){return t.rotationDeg===0&&o.rotationDeg===0?J(t,o):Q(t,o)}function J(t,o){return{colliding:S(d(t),d(o))}}function q(t){let{position:o,width:n,height:i,rotationDeg:e}=t,r=n/2,s=i/2,c={x:o.x+r,y:o.y+s},l=e*Math.PI/180,a=Math.cos(l),u=Math.sin(l);return[{x:-r,y:-s},{x:r,y:-s},{x:r,y:s},{x:-r,y:s}].map(p=>({x:c.x+(p.x*a-p.y*u),y:c.y+(p.x*u+p.y*a)}))}function K(t,o){let n=[];for(let i=0;i<t.length;i++){let e=t[i],r=t[(i+1)%t.length],s=C(r,e),c=h({x:-s.y,y:s.x});n.push(c)}for(let i=0;i<o.length;i++){let e=o[i],r=o[(i+1)%o.length],s=C(r,e),c=h({x:-s.y,y:s.x});n.push(c)}return n}function G(t,o){let n=g(t[0],o),i=n;for(let e=1;e<t.length;e++){let r=g(t[e],o);r<n&&(n=r),r>i&&(i=r)}return{min:n,max:i}}function Q(t,o){let n=q(t),i=q(o),e=K(n,i);for(let r of e){let s=G(n,r),c=G(i,r);if(s.max<c.min||c.max<s.min)return{colliding:!1}}return{colliding:!0}}function y(t,o){let n=t.type,i=o.type;return n==="circle"&&i==="circle"?T(t,o).colliding:n==="circle"&&i==="point"?M(t,o).colliding:n==="point"&&i==="circle"?M(o,t).colliding:n==="circle"&&i==="rectangle"?D(t,o).colliding:n==="rectangle"&&i==="circle"?D(o,t).colliding:n==="rectangle"&&i==="rectangle"?X(t,o).colliding:n==="rectangle"&&i==="point"?A(t,o).colliding:n==="point"&&i==="rectangle"?A(o,t).colliding:!1}function Z({entities:t}){return new I(t)}var I=class extends m{getCollisions(o){let n=[];for(let i of this.entities)y(o,i.shape)&&n.push(i);return n}};function _({entities:t,cellSize:o=64}){return new w(t,{cellSize:o})}var w=class extends m{constructor(o,n){super(o),this.config=n,this.grid=new Map,this.rebuildGrid()}getCollisions(o){let n=this.getAABBForShape(o),i=this.getCellsForAABB(n),e=new Set;for(let s of i){let c=this.grid.get(s);if(c)for(let l of c)e.add(l)}let r=[];for(let s of e)y(o,s.shape)&&r.push(s);return r}rebuildGrid(){this.grid.clear();for(let o of this.entities)this.insertEntityIntoGrid(o)}insertEntityIntoGrid(o){let n=this.getAABB(o),i=this.getCellsForAABB(n);for(let e of i)this.grid.has(e)||this.grid.set(e,[]),this.grid.get(e).push(o)}getCellsForAABB(o){let{cellSize:n}=this.config,[i,e]=R(o.min,n),[r,s]=R(o.max,n),c=new Array((r-i+1)*(s-e+1)),l=0;for(let a=i;a<=r;a++)for(let u=e;u<=s;u++)c[l++]=P(a,u);return c}getAABB(o){return this.getAABBForShape(o.shape)}getAABBForShape(o){let n=o.type;if(n==="circle")return V(o);if(n==="rectangle")return d(o);if(n==="point")return{min:{x:o.position.x,y:o.position.y},max:{x:o.position.x,y:o.position.y}};throw new Error(`Unsupported shape type: ${n}`)}};function tt(t,o){let n=i=>{let e=i.x-o.position.x,r=i.y-o.position.y;if(o.rotation){let c=-(o.rotation*Math.PI/180),l=Math.cos(c),a=Math.sin(c),u=e*l-r*a,f=e*a+r*l;e=u,r=f}return e+=o.width/2,r+=o.height/2,{x:e,y:r}};if("type"in t){if(t.type==="point")return{...t,position:n(t.position)};if(t.type==="circle")return{...t,center:n(t.center)};if(t.type==="rectangle")return{...t,position:n(t.position),rotationDeg:t.rotationDeg-(o.rotation??0)}}if("min"in t&&"max"in t){if(!o.rotation)return{min:n(t.min),max:n(t.max)};let e=[{x:t.min.x,y:t.min.y},{x:t.max.x,y:t.min.y},{x:t.max.x,y:t.max.y},{x:t.min.x,y:t.max.y}].map(n),r=1/0,s=1/0,c=-1/0,l=-1/0;for(let a of e)r=Math.min(r,a.x),s=Math.min(s,a.y),c=Math.max(c,a.x),l=Math.max(l,a.y);return{min:{x:r,y:s},max:{x:c,y:l}}}if("x"in t&&"y"in t)return n(t);throw new Error("Unsupported type passed to globalCoordinatesToCameraCoordinates")}var ot="0.0.1",nt={notImplemented:!0,info:"Game loop management will be added in a future version"},it={notImplemented:!0,info:"Input handling will be added in a future version"};0&&(module.exports={BaseCollisionDetector,BruteForceCollisionDetector,GameLoop,Input,SpatialGridCollisionDetector,VERSION,aabbIntersect,add,cellToId,checkShapeCollision,circleToAABB,cross,distance,distanceSquared,dot,globalCoordinatesToCameraCoordinates,length,lengthSquared,normalize,positionToCell,rectToAABB,scale,subtract,vec2});
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/collision/CollisionDetector.ts","../src/collision/shapeCollisions/circleCircle/index.ts","../src/collision/shapeCollisions/circlePoint/index.ts","../src/collision/shapeCollisions/circleRect/index.ts","../src/collision/shapeCollisions/rectPoint/index.ts","../src/collision/shapeCollisions/rectRect/index.ts","../src/collision/shapeCollisions/checkShapeCollision.ts","../src/collision/BruteForceCollisionDetector.ts","../src/collision/SpatialGridCollisionDetector.ts","../src/render/index.ts"],"sourcesContent":["/**\n * pepperjs\n * A spicy, high-performance library for building 2D games in JavaScript\n *\n * @packageDocumentation\n */\n\n// ----- Collision Detection System -----\n// Export types\nexport * from \"./types\";\n\n// Export utility functions\nexport * from \"./utils\";\n\n// Export collision detection system\nexport * from \"./collision\";\n\n// Export rendering system\nexport * from \"./render\";\n\n// ----- Library Information -----\nexport const VERSION = \"0.0.1\";\n\n// ----- Future modules (placeholders) -----\n// These will be implemented in future versions\n\n/**\n * @internal\n * Rendering capabilities\n */\nexport const Renderer = {\n // Renderer is now implemented\n notImplemented: false,\n\n // Information about implementation\n info: \"Basic rendering capabilities are now available\",\n};\n\n/**\n * @internal\n * Future game loop management API\n */\nexport const GameLoop = {\n // Placeholder for future game loop module\n notImplemented: true,\n\n // Information about planned implementation\n info: \"Game loop management will be added in a future version\",\n};\n\n/**\n * @internal\n * Future input handling API\n */\nexport const Input = {\n // Placeholder for future input handling module\n notImplemented: true,\n\n // Information about planned implementation\n info: \"Input handling will be added in a future version\",\n};\n","import { Vector2D, AABB, Circle, Rectangle } from \"./types\";\n\n/**\n * Create a new vector\n */\nexport function vec2(x: number, y: number): Vector2D {\n return { x, y };\n}\n\n/**\n * Vector addition\n */\nexport function add(a: Vector2D, b: Vector2D): Vector2D {\n return { x: a.x + b.x, y: a.y + b.y };\n}\n\n/**\n * Vector subtraction\n */\nexport function subtract(a: Vector2D, b: Vector2D): Vector2D {\n return { x: a.x - b.x, y: a.y - b.y };\n}\n\n/**\n * Vector scaling\n */\nexport function scale(v: Vector2D, scalar: number): Vector2D {\n return { x: v.x * scalar, y: v.y * scalar };\n}\n\n/**\n * Dot product of two vectors\n */\nexport function dot(a: Vector2D, b: Vector2D): number {\n return a.x * b.x + a.y * b.y;\n}\n\n/**\n * Cross product magnitude of two 2D vectors\n */\nexport function cross(a: Vector2D, b: Vector2D): number {\n return a.x * b.y - a.y * b.x;\n}\n\n/**\n * Get squared length of a vector (avoids sqrt for performance)\n */\nexport function lengthSquared(v: Vector2D): number {\n return v.x * v.x + v.y * v.y;\n}\n\n/**\n * Get vector length\n */\nexport function length(v: Vector2D): number {\n return Math.sqrt(lengthSquared(v));\n}\n\n/**\n * Normalize a vector (make it unit length)\n */\nexport function normalize(v: Vector2D): Vector2D {\n const len = length(v);\n // Avoid division by zero\n if (len < 1e-10) return { x: 0, y: 0 };\n return { x: v.x / len, y: v.y / len };\n}\n\n/**\n * Distance squared between two points (avoids sqrt for performance)\n */\nexport function distanceSquared(a: Vector2D, b: Vector2D): number {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n return dx * dx + dy * dy;\n}\n\n/**\n * Distance between two points\n */\nexport function distance(a: Vector2D, b: Vector2D): number {\n return Math.sqrt(distanceSquared(a, b));\n}\n\n/**\n * Create an AABB from a rectangle\n */\nexport function rectToAABB(rect: Rectangle): AABB {\n return {\n min: { x: rect.position.x, y: rect.position.y },\n max: { x: rect.position.x + rect.width, y: rect.position.y + rect.height },\n };\n}\n\n/**\n * Create an AABB from a circle\n */\nexport function circleToAABB(circle: Circle): AABB {\n return {\n min: {\n x: circle.center.x - circle.radius,\n y: circle.center.y - circle.radius,\n },\n max: {\n x: circle.center.x + circle.radius,\n y: circle.center.y + circle.radius,\n },\n };\n}\n\n/**\n * Check if two AABBs intersect\n */\nexport function aabbIntersect(a: AABB, b: AABB): boolean {\n // Exit with no intersection if separated along an axis\n if (a.max.x < b.min.x || a.min.x > b.max.x) return false;\n if (a.max.y < b.min.y || a.min.y > b.max.y) return false;\n\n // Overlapping on all axes means AABBs are intersecting\n return true;\n}\n\n/**\n * Calculate cell indices for a position in a spatial grid\n */\nexport function positionToCell(\n position: Vector2D,\n cellSize: number,\n): [number, number] {\n return [Math.floor(position.x / cellSize), Math.floor(position.y / cellSize)];\n}\n\n/**\n * Calculate a unique cell ID from grid coordinates\n * Uses a spatial hashing function to convert 2D coordinates to 1D\n */\nexport function cellToId(x: number, y: number): number {\n // Cantor pairing function - maps two non-negative integers to a unique non-negative integer\n return ((x + y) * (x + y + 1)) / 2 + y;\n}\n","import { Entity, Shape } from \"../types\";\n\n/**\n * Base class for collision detectors that implements common functionality\n */\nexport abstract class BaseCollisionDetector {\n /**\n * The entities to check collisions against\n */\n protected entities: Entity[];\n\n /**\n * Create a new collision detector\n * @param entities The entities to check collisions against\n */\n constructor(entities: Entity[]) {\n this.entities = entities;\n }\n\n /**\n * Get all entities that collide with the given shape\n * @param shape The shape to check collisions against\n * @returns Array of entity IDs that collide with the shape\n */\n abstract getCollisions(shape: Shape): (string | number)[];\n}\n","import { Circle, CollisionResult } from \"../../../types\";\nimport { distanceSquared } from \"../../../utils\";\n\n/**\n * Detects collision between two circles\n * @param circleA First circle\n * @param circleB Second circle\n * @returns Collision result with contact information\n */\nexport function circleCircleCollision(\n circleA: Circle,\n circleB: Circle,\n): CollisionResult {\n const distSquared = distanceSquared(circleA.center, circleB.center);\n\n const radiusSum = circleA.radius + circleB.radius;\n\n const colliding = distSquared <= radiusSum * radiusSum;\n\n return {\n colliding,\n };\n}\n","import { Circle, CollisionResult, Point } from \"../../../types\";\nimport { distanceSquared } from \"../../../utils\";\n\n/**\n * Detects collision between a circle and a point\n * @param circle Circle\n * @param point Point\n * @returns Collision result with contact information\n */\nexport function circlePointCollision(\n circle: Circle,\n point: Point,\n): CollisionResult {\n const distSquared = distanceSquared(circle.center, point.position);\n\n const colliding = distSquared <= circle.radius * circle.radius;\n\n return {\n colliding,\n };\n}\n","import { Circle, CollisionResult, Rectangle } from \"../../../types\";\nimport { distanceSquared } from \"../../../utils\";\n\n/**\n * Detects collision between a circle and a rectangle\n * @param circle Circle\n * @param rect Rectangle\n * @returns Collision result with contact information\n */\nexport function circleRectCollision(\n circle: Circle,\n rect: Rectangle,\n): CollisionResult {\n // Handle rotation if present\n if (rect.rotationDeg !== 0) {\n return circleRotatedRectCollision(circle, rect);\n }\n\n // Find the closest point on the rectangle to the circle center\n const closestX = Math.max(\n rect.position.x,\n Math.min(circle.center.x, rect.position.x + rect.width),\n );\n const closestY = Math.max(\n rect.position.y,\n Math.min(circle.center.y, rect.position.y + rect.height),\n );\n\n const distSquared = distanceSquared(circle.center, {\n x: closestX,\n y: closestY,\n });\n\n // Check if the circle is colliding with the rectangle\n const colliding = distSquared <= circle.radius * circle.radius;\n\n return {\n colliding,\n };\n}\n\n/**\n * Detects collision between a circle and a rotated rectangle\n * @param circle Circle\n * @param rect Rotated rectangle\n * @returns Collision result with contact information\n */\nfunction circleRotatedRectCollision(\n circle: Circle,\n rect: Rectangle,\n): CollisionResult {\n // Convert rotation from degrees to radians\n const rotationRad = (rect.rotationDeg * Math.PI) / 180;\n const cos = Math.cos(-rotationRad);\n const sin = Math.sin(-rotationRad);\n\n // Translate circle center to rectangle's local space (unrotated)\n const rectCenterX = rect.position.x + rect.width / 2;\n const rectCenterY = rect.position.y + rect.height / 2;\n\n // Vector from rectangle center to circle center\n const dx = circle.center.x - rectCenterX;\n const dy = circle.center.y - rectCenterY;\n\n // Rotate the vector to align with the rectangle's local axes\n const rotatedX = cos * dx - sin * dy;\n const rotatedY = sin * dx + cos * dy;\n\n // Create a circle in the rectangle's local space\n const localCircle: Circle = {\n type: \"circle\",\n center: {\n x: rotatedX + rectCenterX,\n y: rotatedY + rectCenterY,\n },\n radius: circle.radius,\n };\n\n // Create an unrotated rectangle\n const localRect: Rectangle = {\n type: \"rectangle\",\n position: rect.position,\n width: rect.width,\n height: rect.height,\n rotationDeg: 0,\n };\n\n // Check collision with the unrotated rectangle\n return circleRectCollision(localCircle, localRect);\n}\n","import { CollisionResult, Point, Rectangle } from \"../../../types\";\n\n/**\n * Detects collision between a rectangle and a point\n * @param rect Rectangle\n * @param point Point\n * @returns Collision result with contact information\n */\nexport function rectPointCollision(\n rect: Rectangle,\n point: Point,\n): CollisionResult {\n // Handle rotation if present\n if (rect.rotationDeg !== 0) {\n return rotatedRectPointCollision(rect, point);\n }\n\n // Check if the point is inside the rectangle\n const colliding =\n point.position.x >= rect.position.x &&\n point.position.x <= rect.position.x + rect.width &&\n point.position.y >= rect.position.y &&\n point.position.y <= rect.position.y + rect.height;\n\n return {\n colliding,\n };\n}\n\n/**\n * Detects collision between a rotated rectangle and a point\n * @param rect Rotated rectangle\n * @param point Point\n * @returns Collision result with contact information\n */\nfunction rotatedRectPointCollision(\n rect: Rectangle,\n point: Point,\n): CollisionResult {\n // Convert rotation from degrees to radians\n const rotationRad = (rect.rotationDeg * Math.PI) / 180;\n const cos = Math.cos(-rotationRad);\n const sin = Math.sin(-rotationRad);\n\n // Calculate rectangle center\n const rectCenterX = rect.position.x + rect.width / 2;\n const rectCenterY = rect.position.y + rect.height / 2;\n\n // Vector from rectangle center to point\n const dx = point.position.x - rectCenterX;\n const dy = point.position.y - rectCenterY;\n\n // Rotate the vector to align with the rectangle's local axes\n const rotatedX = cos * dx - sin * dy;\n const rotatedY = sin * dx + cos * dy;\n\n // Create a point in the rectangle's local space\n const localPoint: Point = {\n type: \"point\",\n position: {\n x: rotatedX + rectCenterX,\n y: rotatedY + rectCenterY,\n },\n };\n\n // Create an unrotated rectangle\n const localRect: Rectangle = {\n type: \"rectangle\",\n position: {\n x: rect.position.x,\n y: rect.position.y,\n },\n width: rect.width,\n height: rect.height,\n rotationDeg: 0,\n };\n\n // Check collision with the unrotated rectangle\n return rectPointCollision(localRect, localPoint);\n}\n","import { Rectangle, CollisionResult, Vector2D } from \"../../../types\";\nimport {\n subtract,\n normalize,\n dot,\n rectToAABB,\n aabbIntersect,\n} from \"../../../utils\";\n\n/**\n * Detect collision between two rectangles\n * This implementation handles rotated rectangles using the Separating Axis Theorem (SAT)\n */\nexport function rectRectCollision(\n rectA: Rectangle,\n rectB: Rectangle,\n): CollisionResult {\n // If both rectangles have zero rotation, use a simpler AABB check\n if (rectA.rotationDeg === 0 && rectB.rotationDeg === 0) {\n return aabbRectRectCollision(rectA, rectB);\n }\n\n // For rotated rectangles, use Separating Axis Theorem (SAT)\n return satRectRectCollision(rectA, rectB);\n}\n\n/**\n * Collision detection for axis-aligned (non-rotated) rectangles\n */\nfunction aabbRectRectCollision(\n rectA: Rectangle,\n rectB: Rectangle,\n): CollisionResult {\n return {\n colliding: aabbIntersect(rectToAABB(rectA), rectToAABB(rectB)),\n };\n}\n\n/**\n * Get the corners of a rotated rectangle\n */\nfunction getRectangleCorners(rect: Rectangle): Vector2D[] {\n const { position, width, height, rotationDeg } = rect;\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n\n // Calculate center of the rectangle\n const center = {\n x: position.x + halfWidth,\n y: position.y + halfHeight,\n };\n\n // Convert rotation to radians\n const rotationRad = (rotationDeg * Math.PI) / 180;\n const cos = Math.cos(rotationRad);\n const sin = Math.sin(rotationRad);\n\n // Calculate corners relative to center\n const corners: Vector2D[] = [\n { x: -halfWidth, y: -halfHeight }, // Top-left\n { x: halfWidth, y: -halfHeight }, // Top-right\n { x: halfWidth, y: halfHeight }, // Bottom-right\n { x: -halfWidth, y: halfHeight }, // Bottom-left\n ];\n\n // Rotate and translate corners\n return corners.map((corner) => ({\n x: center.x + (corner.x * cos - corner.y * sin),\n y: center.y + (corner.x * sin + corner.y * cos),\n }));\n}\n\n/**\n * Get the axes to test for the SAT algorithm\n */\nfunction getAxes(cornersA: Vector2D[], cornersB: Vector2D[]): Vector2D[] {\n const axes: Vector2D[] = [];\n\n // Add the normals of each edge of the first rectangle\n for (let i = 0; i < cornersA.length; i++) {\n const p1 = cornersA[i];\n const p2 = cornersA[(i + 1) % cornersA.length];\n const edge = subtract(p2, p1);\n // The normal is perpendicular to the edge\n const normal = normalize({ x: -edge.y, y: edge.x });\n axes.push(normal);\n }\n\n // Add the normals of each edge of the second rectangle\n for (let i = 0; i < cornersB.length; i++) {\n const p1 = cornersB[i];\n const p2 = cornersB[(i + 1) % cornersB.length];\n const edge = subtract(p2, p1);\n // The normal is perpendicular to the edge\n const normal = normalize({ x: -edge.y, y: edge.x });\n axes.push(normal);\n }\n\n return axes;\n}\n\n/**\n * Project a shape onto an axis\n */\nfunction projectShapeOntoAxis(\n corners: Vector2D[],\n axis: Vector2D,\n): { min: number; max: number } {\n let min = dot(corners[0], axis);\n let max = min;\n\n for (let i = 1; i < corners.length; i++) {\n const projection = dot(corners[i], axis);\n if (projection < min) min = projection;\n if (projection > max) max = projection;\n }\n\n return { min, max };\n}\n\n/**\n * Collision detection for rotated rectangles using Separating Axis Theorem (SAT)\n */\nfunction satRectRectCollision(\n rectA: Rectangle,\n rectB: Rectangle,\n): CollisionResult {\n // Get corners of both rectangles\n const cornersA = getRectangleCorners(rectA);\n const cornersB = getRectangleCorners(rectB);\n\n // Get axes to test\n const axes = getAxes(cornersA, cornersB);\n\n // Test each axis\n for (const axis of axes) {\n const projectionA = projectShapeOntoAxis(cornersA, axis);\n const projectionB = projectShapeOntoAxis(cornersB, axis);\n\n // Check for separation\n if (\n projectionA.max < projectionB.min ||\n projectionB.max < projectionA.min\n ) {\n // Shapes are separated along this axis\n return { colliding: false };\n }\n }\n\n // If we get here, the shapes are colliding\n return { colliding: true };\n}\n","import { Circle, Point, Rectangle, Shape } from \"../../types\";\nimport { circleCircleCollision } from \"./circleCircle\";\nimport { circlePointCollision } from \"./circlePoint\";\nimport { circleRectCollision } from \"./circleRect\";\nimport { rectPointCollision } from \"./rectPoint\";\nimport { rectRectCollision } from \"./rectRect\";\n\n/**\n * Check if two entities are colliding\n * @param shapeA First shape\n * @param shapeB Second shape\n * @returns True if the shapes are colliding\n */\nexport function checkShapeCollision(shapeA: Shape, shapeB: Shape): boolean {\n const shapeAType = shapeA.type;\n const shapeBType = shapeB.type;\n\n // Circle vs Circle\n if (shapeAType === \"circle\" && shapeBType === \"circle\") {\n return circleCircleCollision(shapeA as Circle, shapeB as Circle).colliding;\n }\n\n if (shapeAType === \"circle\" && shapeBType === \"point\") {\n return circlePointCollision(shapeA as Circle, shapeB as Point).colliding;\n }\n if (shapeAType === \"point\" && shapeBType === \"circle\") {\n return circlePointCollision(shapeB as Circle, shapeA as Point).colliding;\n }\n\n if (shapeAType === \"circle\" && shapeBType === \"rectangle\") {\n return circleRectCollision(shapeA as Circle, shapeB as Rectangle).colliding;\n }\n if (shapeAType === \"rectangle\" && shapeBType === \"circle\") {\n return circleRectCollision(shapeB as Circle, shapeA as Rectangle).colliding;\n }\n\n if (shapeAType === \"rectangle\" && shapeBType === \"rectangle\") {\n return rectRectCollision(shapeA as Rectangle, shapeB as Rectangle)\n .colliding;\n }\n\n if (shapeAType === \"rectangle\" && shapeBType === \"point\") {\n return rectPointCollision(shapeA as Rectangle, shapeB as Point).colliding;\n }\n if (shapeAType === \"point\" && shapeBType === \"rectangle\") {\n return rectPointCollision(shapeB as Rectangle, shapeA as Point).colliding;\n }\n\n return false;\n}\n","import { Entity, Shape } from \"../types\";\nimport { BaseCollisionDetector } from \"./CollisionDetector\";\nimport { checkShapeCollision } from \"./shapeCollisions/checkShapeCollision\";\n\n/**\n * Collision detector that uses a brute force approach\n * Checks every entity against the given shape\n *\n * Best used when:\n * - You have a small number of entities\n * - You only need to check collisions occasionally\n * - You want the simplest implementation\n */\nexport function BruteForceCollisionDetector({\n entities,\n}: {\n entities: Entity[];\n}) {\n return new BruteForceCollisionDetectorImpl(entities);\n}\n\nclass BruteForceCollisionDetectorImpl extends BaseCollisionDetector {\n /**\n * Get all entities that collide with the given shape\n * @param shape The shape to check collisions against\n * @returns Array of entity IDs that collide with the shape\n */\n getCollisions(shape: Shape): (string | number)[] {\n const collisions: (string | number)[] = [];\n\n // Check each entity against the given shape\n for (const entity of this.entities) {\n // Check if the shapes collide\n if (checkShapeCollision(shape, entity.shape)) {\n collisions.push(entity.id);\n }\n }\n\n return collisions;\n }\n}\n","import { AABB, Circle, Entity, Point, Rectangle, Shape } from \"../types\";\nimport { BaseCollisionDetector } from \"./CollisionDetector\";\nimport { checkShapeCollision } from \"./shapeCollisions/checkShapeCollision\";\nimport { cellToId, circleToAABB, positionToCell, rectToAABB } from \"../utils\";\n\ntype CellId = number;\n\n/**\n * Configuration options for the spatial grid collision detector\n */\nexport interface SpatialGridConfig {\n /** Size of each grid cell */\n cellSize: number;\n}\n\n/**\n * Collision detector that uses spatial partitioning for efficient collision detection\n *\n * Best used when:\n * - You have a large number of entities\n * - Entities are distributed across the space\n * - You need to check collisions frequently\n */\nexport function SpatialGridCollisionDetector({\n entities,\n cellSize = 64,\n}: {\n entities: Entity[];\n cellSize?: number;\n}) {\n return new SpatialGridCollisionDetectorImpl(entities, { cellSize });\n}\n\nclass SpatialGridCollisionDetectorImpl extends BaseCollisionDetector {\n /** The spatial hash grid for quick lookups */\n private grid: Map<CellId, Entity[]>;\n /** Configuration for the spatial grid */\n private config: SpatialGridConfig;\n\n /**\n * Create a new spatial grid collision detector\n */\n constructor(entities: Entity[], config: SpatialGridConfig) {\n super(entities);\n this.config = config;\n this.grid = new Map();\n\n // Initialize the grid with entities\n this.rebuildGrid();\n }\n\n /**\n * Get all entities that collide with the given shape\n */\n getCollisions(shape: Shape): (string | number)[] {\n // Get the AABB for the shape\n const aabb = this.getAABBForShape(shape);\n\n // Get all cells that the AABB overlaps\n const cells = this.getCellsForAABB(aabb);\n\n // Get all entities in those cells\n const potentialCollisions = new Set<Entity>();\n\n for (const cellId of cells) {\n const entitiesInCell = this.grid.get(cellId);\n if (entitiesInCell) {\n for (const entity of entitiesInCell) {\n potentialCollisions.add(entity);\n }\n }\n }\n\n // Check for actual collisions\n const collisions: (string | number)[] = [];\n\n for (const entity of potentialCollisions) {\n if (checkShapeCollision(shape, entity.shape)) {\n collisions.push(entity.id);\n }\n }\n\n return collisions;\n }\n\n /**\n * Rebuild the spatial grid with the current entities\n */\n rebuildGrid(): void {\n // Clear the grid\n this.grid.clear();\n\n // Add all entities to the grid\n for (const entity of this.entities) {\n this.insertEntityIntoGrid(entity);\n }\n }\n\n /**\n * Insert an entity into the spatial grid\n */\n private insertEntityIntoGrid(entity: Entity): void {\n // Get the AABB for the entity\n const aabb = this.getAABB(entity);\n\n // Get all cells that the AABB overlaps\n const cells = this.getCellsForAABB(aabb);\n\n // Add the entity to each cell\n for (const cellId of cells) {\n if (!this.grid.has(cellId)) {\n this.grid.set(cellId, []);\n }\n\n this.grid.get(cellId)!.push(entity);\n }\n }\n\n /**\n * Get all cells that an AABB overlaps\n */\n private getCellsForAABB(aabb: AABB): CellId[] {\n const { cellSize } = this.config;\n\n // Calculate the min and max cell coordinates\n const [minCellX, minCellY] = positionToCell(aabb.min, cellSize);\n const [maxCellX, maxCellY] = positionToCell(aabb.max, cellSize);\n\n // Get all cells in the range\n const cells: CellId[] = new Array(\n (maxCellX - minCellX + 1) * (maxCellY - minCellY + 1),\n );\n let index = 0;\n\n for (let x = minCellX; x <= maxCellX; x++) {\n for (let y = minCellY; y <= maxCellY; y++) {\n cells[index++] = cellToId(x, y);\n }\n }\n\n return cells;\n }\n\n /**\n * Get the AABB for an entity\n */\n private getAABB(entity: Entity): AABB {\n return this.getAABBForShape(entity.shape);\n }\n\n /**\n * Get the AABB for a shape\n */\n private getAABBForShape(shape: Shape): AABB {\n const shapeType = shape.type;\n\n if (shapeType === \"circle\") {\n return circleToAABB(shape as Circle);\n } else if (shapeType === \"rectangle\") {\n return rectToAABB(shape as Rectangle);\n } else if (shapeType === \"point\") {\n // For a point, create a tiny AABB\n return {\n min: { x: (shape as Point).position.x, y: (shape as Point).position.y },\n max: { x: (shape as Point).position.x, y: (shape as Point).position.y },\n };\n }\n\n throw new Error(`Unsupported shape type: ${shapeType}`);\n }\n}\n","import { Circle, Point, Rectangle, Shape } from \"../types\";\nimport { ShapeStyle, RendererOptions, RenderableShape } from \"./types\";\n\n/**\n * Apply style settings to the canvas context\n */\nexport function applyStyle(ctx: CanvasRenderingContext2D, style: ShapeStyle) {\n // Save the current context state\n ctx.save();\n\n // Apply fill and stroke styles\n if (style.fillColor) {\n ctx.fillStyle = style.fillColor;\n }\n\n if (style.strokeColor) {\n ctx.strokeStyle = style.strokeColor;\n }\n\n if (style.strokeWidth !== undefined) {\n ctx.lineWidth = style.strokeWidth;\n }\n\n if (style.alpha !== undefined) {\n ctx.globalAlpha = style.alpha;\n }\n\n // Apply shadow settings if provided\n if (style.shadowBlur !== undefined) {\n ctx.shadowBlur = style.shadowBlur;\n }\n\n if (style.shadowColor) {\n ctx.shadowColor = style.shadowColor;\n }\n\n if (style.shadowOffsetX !== undefined) {\n ctx.shadowOffsetX = style.shadowOffsetX;\n }\n\n if (style.shadowOffsetY !== undefined) {\n ctx.shadowOffsetY = style.shadowOffsetY;\n }\n}\n\n/**\n * Restore the canvas context to its previous state\n */\nexport function restoreContext(ctx: CanvasRenderingContext2D) {\n ctx.restore();\n}\n\n/**\n * Render a circle shape\n */\nexport function renderCircle(\n ctx: CanvasRenderingContext2D,\n circle: Circle,\n style: ShapeStyle,\n) {\n applyStyle(ctx, style);\n\n ctx.beginPath();\n ctx.arc(circle.center.x, circle.center.y, circle.radius, 0, Math.PI * 2);\n\n if (style.fillColor) {\n ctx.fill();\n }\n\n if (style.strokeColor && style.strokeWidth && style.strokeWidth > 0) {\n ctx.stroke();\n }\n\n restoreContext(ctx);\n}\n\n/**\n * Render a point shape\n */\nexport function renderPoint(\n ctx: CanvasRenderingContext2D,\n point: Point,\n style: ShapeStyle,\n) {\n // Points are rendered as small circles\n const pointSize = style.strokeWidth || 4;\n\n applyStyle(ctx, style);\n\n ctx.beginPath();\n ctx.arc(point.position.x, point.position.y, pointSize / 2, 0, Math.PI * 2);\n\n if (style.fillColor) {\n ctx.fill();\n }\n\n if (style.strokeColor && style.strokeWidth && style.strokeWidth > 0) {\n ctx.stroke();\n }\n\n restoreContext(ctx);\n}\n\n/**\n * Render a rectangle shape\n */\nexport function renderRectangle(\n ctx: CanvasRenderingContext2D,\n rectangle: Rectangle,\n style: ShapeStyle,\n) {\n applyStyle(ctx, style);\n\n // Save the current transformation matrix\n ctx.save();\n\n // Translate to the rectangle's position\n ctx.translate(rectangle.position.x, rectangle.position.y);\n\n // Rotate if needed\n if (rectangle.rotationDeg !== 0) {\n const rotationRad = (rectangle.rotationDeg * Math.PI) / 180;\n ctx.rotate(rotationRad);\n }\n\n // Draw the rectangle centered at the origin\n const halfWidth = rectangle.width / 2;\n const halfHeight = rectangle.height / 2;\n\n if (style.fillColor) {\n ctx.fillRect(-halfWidth, -halfHeight, rectangle.width, rectangle.height);\n }\n\n if (style.strokeColor && style.strokeWidth && style.strokeWidth > 0) {\n ctx.strokeRect(-halfWidth, -halfHeight, rectangle.width, rectangle.height);\n }\n\n // Restore the transformation matrix\n ctx.restore();\n\n // Restore the style context\n restoreContext(ctx);\n}\n\n/**\n * Render any shape based on its type\n */\nexport function renderShape(\n ctx: CanvasRenderingContext2D,\n shape: Shape,\n style: ShapeStyle,\n) {\n switch (shape.type) {\n case \"circle\":\n renderCircle(ctx, shape, style);\n break;\n case \"rectangle\":\n renderRectangle(ctx, shape, style);\n break;\n case \"point\":\n renderPoint(ctx, shape, style);\n break;\n default:\n // This should never happen if all shape types are handled\n console.warn(\"Unknown shape type encountered\");\n break;\n }\n}\n\n/**\n * Main renderer function to render multiple shapes\n */\nexport function renderShapes(\n ctx: CanvasRenderingContext2D,\n shapes: RenderableShape[],\n options: RendererOptions,\n) {\n // Render each shape\n for (const { shape, style } of shapes) {\n // Merge with default style if provided\n const mergedStyle = {\n ...options.defaultStyle,\n ...style,\n };\n\n renderShape(ctx, shape, mergedStyle);\n }\n}\n"],"mappings":"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","names":["index_exports","__export","BaseCollisionDetector","BruteForceCollisionDetector","GameLoop","Input","Renderer","SpatialGridCollisionDetector","VERSION","aabbIntersect","add","applyStyle","cellToId","checkShapeCollision","circleToAABB","cross","distance","distanceSquared","dot","length","lengthSquared","normalize","positionToCell","rectToAABB","renderCircle","renderPoint","renderRectangle","renderShape","renderShapes","restoreContext","scale","subtract","vec2","__toCommonJS","vec2","x","y","add","a","b","subtract","scale","v","scalar","dot","cross","lengthSquared","length","normalize","len","distanceSquared","dx","dy","distance","rectToAABB","rect","circleToAABB","circle","aabbIntersect","positionToCell","position","cellSize","cellToId","BaseCollisionDetector","entities","circleCircleCollision","circleA","circleB","distSquared","distanceSquared","radiusSum","circlePointCollision","circle","point","distanceSquared","circleRectCollision","circle","rect","circleRotatedRectCollision","closestX","closestY","distanceSquared","rotationRad","cos","sin","rectCenterX","rectCenterY","dx","dy","rotatedX","rotatedY","localCircle","localRect","rectPointCollision","rect","point","rotatedRectPointCollision","rotationRad","cos","sin","rectCenterX","rectCenterY","dx","dy","rotatedX","rotatedY","localPoint","localRect","rectRectCollision","rectA","rectB","aabbRectRectCollision","satRectRectCollision","aabbIntersect","rectToAABB","getRectangleCorners","rect","position","width","height","rotationDeg","halfWidth","halfHeight","center","rotationRad","cos","sin","corner","getAxes","cornersA","cornersB","axes","i","p1","p2","edge","subtract","normal","normalize","projectShapeOntoAxis","corners","axis","min","dot","max","projection","projectionA","projectionB","checkShapeCollision","shapeA","shapeB","shapeAType","shapeBType","circleCircleCollision","circlePointCollision","circleRectCollision","rectRectCollision","rectPointCollision","BruteForceCollisionDetector","entities","BruteForceCollisionDetectorImpl","BaseCollisionDetector","shape","collisions","entity","checkShapeCollision","SpatialGridCollisionDetector","entities","cellSize","SpatialGridCollisionDetectorImpl","BaseCollisionDetector","config","shape","aabb","cells","potentialCollisions","cellId","entitiesInCell","entity","collisions","checkShapeCollision","minCellX","minCellY","positionToCell","maxCellX","maxCellY","index","x","y","cellToId","shapeType","circleToAABB","rectToAABB","applyStyle","ctx","style","restoreContext","renderCircle","circle","renderPoint","point","pointSize","renderRectangle","rectangle","rotationRad","halfWidth","halfHeight","renderShape","shape","renderShapes","shapes","options","mergedStyle","VERSION","Renderer","GameLoop","Input"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/collision/CollisionDetector.ts","../src/collision/shapeCollisions/circleCircle/index.ts","../src/collision/shapeCollisions/circlePoint/index.ts","../src/collision/shapeCollisions/circleRect/index.ts","../src/collision/shapeCollisions/rectPoint/index.ts","../src/collision/shapeCollisions/rectRect/index.ts","../src/collision/shapeCollisions/index.ts","../src/collision/BruteForceCollisionDetector.ts","../src/collision/SpatialGridCollisionDetector.ts","../src/camera/Camera.ts"],"sourcesContent":["/**\n * InfernoJS\n * A spicy, high-performance library for building 2D games in JavaScript\n *\n * @packageDocumentation\n */\n\n// ----- Collision Detection System -----\n// Export types\nexport * from \"./types\";\n\n// Export utility functions\nexport * from \"./utils\";\n\n// Export collision detection system\nexport * from \"./collision\";\n\n// Export camera system\nexport * from \"./camera\";\n\n// ----- Library Information -----\nexport const VERSION = \"0.0.1\";\n\n// ----- Future modules (placeholders) -----\n// These will be implemented in future versions\n\n/**\n * @internal\n * Future game loop management API\n */\nexport const GameLoop = {\n // Placeholder for future game loop module\n notImplemented: true,\n\n // Information about planned implementation\n info: \"Game loop management will be added in a future version\",\n};\n\n/**\n * @internal\n * Future input handling API\n */\nexport const Input = {\n // Placeholder for future input handling module\n notImplemented: true,\n\n // Information about planned implementation\n info: \"Input handling will be added in a future version\",\n};\n","import { Vector2D, AABB, Circle, Rectangle } from \"./types\";\n\n/**\n * Create a new vector\n */\nexport function vec2(x: number, y: number): Vector2D {\n return { x, y };\n}\n\n/**\n * Vector addition\n */\nexport function add(a: Vector2D, b: Vector2D): Vector2D {\n return { x: a.x + b.x, y: a.y + b.y };\n}\n\n/**\n * Vector subtraction\n */\nexport function subtract(a: Vector2D, b: Vector2D): Vector2D {\n return { x: a.x - b.x, y: a.y - b.y };\n}\n\n/**\n * Vector scaling\n */\nexport function scale(v: Vector2D, scalar: number): Vector2D {\n return { x: v.x * scalar, y: v.y * scalar };\n}\n\n/**\n * Dot product of two vectors\n */\nexport function dot(a: Vector2D, b: Vector2D): number {\n return a.x * b.x + a.y * b.y;\n}\n\n/**\n * Cross product magnitude of two 2D vectors\n */\nexport function cross(a: Vector2D, b: Vector2D): number {\n return a.x * b.y - a.y * b.x;\n}\n\n/**\n * Get squared length of a vector (avoids sqrt for performance)\n */\nexport function lengthSquared(v: Vector2D): number {\n return v.x * v.x + v.y * v.y;\n}\n\n/**\n * Get vector length\n */\nexport function length(v: Vector2D): number {\n return Math.sqrt(lengthSquared(v));\n}\n\n/**\n * Normalize a vector (make it unit length)\n */\nexport function normalize(v: Vector2D): Vector2D {\n const len = length(v);\n // Avoid division by zero\n if (len < 1e-10) return { x: 0, y: 0 };\n return { x: v.x / len, y: v.y / len };\n}\n\n/**\n * Distance squared between two points (avoids sqrt for performance)\n */\nexport function distanceSquared(a: Vector2D, b: Vector2D): number {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n return dx * dx + dy * dy;\n}\n\n/**\n * Distance between two points\n */\nexport function distance(a: Vector2D, b: Vector2D): number {\n return Math.sqrt(distanceSquared(a, b));\n}\n\n/**\n * Create an AABB from a rectangle\n */\nexport function rectToAABB(rect: Rectangle): AABB {\n return {\n min: { x: rect.position.x, y: rect.position.y },\n max: { x: rect.position.x + rect.width, y: rect.position.y + rect.height },\n };\n}\n\n/**\n * Create an AABB from a circle\n */\nexport function circleToAABB(circle: Circle): AABB {\n return {\n min: {\n x: circle.center.x - circle.radius,\n y: circle.center.y - circle.radius,\n },\n max: {\n x: circle.center.x + circle.radius,\n y: circle.center.y + circle.radius,\n },\n };\n}\n\n/**\n * Check if two AABBs intersect\n */\nexport function aabbIntersect(a: AABB, b: AABB): boolean {\n // Exit with no intersection if separated along an axis\n if (a.max.x < b.min.x || a.min.x > b.max.x) return false;\n if (a.max.y < b.min.y || a.min.y > b.max.y) return false;\n\n // Overlapping on all axes means AABBs are intersecting\n return true;\n}\n\n/**\n * Calculate cell indices for a position in a spatial grid\n */\nexport function positionToCell(\n position: Vector2D,\n cellSize: number,\n): [number, number] {\n return [Math.floor(position.x / cellSize), Math.floor(position.y / cellSize)];\n}\n\n/**\n * Calculate a unique cell ID from grid coordinates\n * Uses a spatial hashing function to convert 2D coordinates to 1D\n */\nexport function cellToId(x: number, y: number): number {\n // Cantor pairing function - maps two non-negative integers to a unique non-negative integer\n return ((x + y) * (x + y + 1)) / 2 + y;\n}\n","import { Entity, Shape } from \"../types\";\n\n/**\n * Base class for collision detectors that implements common functionality\n */\nexport abstract class BaseCollisionDetector {\n /**\n * The entities to check collisions against\n */\n protected entities: Entity[];\n\n /**\n * Create a new collision detector\n * @param entities The entities to check collisions against\n */\n constructor(entities: Entity[]) {\n this.entities = entities;\n }\n\n /**\n * Get all entities that collide with the given shape\n * @param shape The shape to check collisions against\n * @returns Array of entities that collide with the shape\n */\n abstract getCollisions(shape: Shape): Entity[];\n}\n","import { Circle, CollisionResult } from \"../../../types\";\nimport { distanceSquared } from \"../../../utils\";\n\n/**\n * Detects collision between two circles\n * @param circleA First circle\n * @param circleB Second circle\n * @returns Collision result with contact information\n */\nexport function circleCircleCollision(\n circleA: Circle,\n circleB: Circle,\n): CollisionResult {\n const distSquared = distanceSquared(circleA.center, circleB.center);\n\n const radiusSum = circleA.radius + circleB.radius;\n\n const colliding = distSquared <= radiusSum * radiusSum;\n\n return {\n colliding,\n };\n}\n","import { Circle, CollisionResult, Point } from \"../../../types\";\nimport { distanceSquared } from \"../../../utils\";\n\n/**\n * Detects collision between a circle and a point\n * @param circle Circle\n * @param point Point\n * @returns Collision result with contact information\n */\nexport function circlePointCollision(\n circle: Circle,\n point: Point,\n): CollisionResult {\n const distSquared = distanceSquared(circle.center, point.position);\n\n const colliding = distSquared <= circle.radius * circle.radius;\n\n return {\n colliding,\n };\n}\n","import { Circle, CollisionResult, Rectangle } from \"../../../types\";\nimport { distanceSquared } from \"../../../utils\";\n\n/**\n * Detects collision between a circle and a rectangle\n * @param circle Circle\n * @param rect Rectangle\n * @returns Collision result with contact information\n */\nexport function circleRectCollision(\n circle: Circle,\n rect: Rectangle,\n): CollisionResult {\n // Handle rotation if present\n if (rect.rotationDeg !== 0) {\n return circleRotatedRectCollision(circle, rect);\n }\n\n // Find the closest point on the rectangle to the circle center\n const closestX = Math.max(\n rect.position.x,\n Math.min(circle.center.x, rect.position.x + rect.width),\n );\n const closestY = Math.max(\n rect.position.y,\n Math.min(circle.center.y, rect.position.y + rect.height),\n );\n\n const distSquared = distanceSquared(circle.center, {\n x: closestX,\n y: closestY,\n });\n\n // Check if the circle is colliding with the rectangle\n const colliding = distSquared <= circle.radius * circle.radius;\n\n return {\n colliding,\n };\n}\n\n/**\n * Detects collision between a circle and a rotated rectangle\n * @param circle Circle\n * @param rect Rotated rectangle\n * @returns Collision result with contact information\n */\nfunction circleRotatedRectCollision(\n circle: Circle,\n rect: Rectangle,\n): CollisionResult {\n // Convert rotation from degrees to radians\n const rotationRad = (rect.rotationDeg * Math.PI) / 180;\n const cos = Math.cos(-rotationRad);\n const sin = Math.sin(-rotationRad);\n\n // Translate circle center to rectangle's local space (unrotated)\n const rectCenterX = rect.position.x + rect.width / 2;\n const rectCenterY = rect.position.y + rect.height / 2;\n\n // Vector from rectangle center to circle center\n const dx = circle.center.x - rectCenterX;\n const dy = circle.center.y - rectCenterY;\n\n // Rotate the vector to align with the rectangle's local axes\n const rotatedX = cos * dx - sin * dy;\n const rotatedY = sin * dx + cos * dy;\n\n // Create a circle in the rectangle's local space\n const localCircle: Circle = {\n type: \"circle\",\n center: {\n x: rotatedX + rectCenterX,\n y: rotatedY + rectCenterY,\n },\n radius: circle.radius,\n };\n\n // Create an unrotated rectangle\n const localRect: Rectangle = {\n type: \"rectangle\",\n position: rect.position,\n width: rect.width,\n height: rect.height,\n rotationDeg: 0,\n };\n\n // Check collision with the unrotated rectangle\n return circleRectCollision(localCircle, localRect);\n}\n","import { CollisionResult, Point, Rectangle } from \"../../../types\";\n\n/**\n * Detects collision between a rectangle and a point\n * @param rect Rectangle\n * @param point Point\n * @returns Collision result with contact information\n */\nexport function rectPointCollision(\n rect: Rectangle,\n point: Point,\n): CollisionResult {\n // Handle rotation if present\n if (rect.rotationDeg !== 0) {\n return rotatedRectPointCollision(rect, point);\n }\n\n // Check if the point is inside the rectangle\n const colliding =\n point.position.x >= rect.position.x &&\n point.position.x <= rect.position.x + rect.width &&\n point.position.y >= rect.position.y &&\n point.position.y <= rect.position.y + rect.height;\n\n return {\n colliding,\n };\n}\n\n/**\n * Detects collision between a rotated rectangle and a point\n * @param rect Rotated rectangle\n * @param point Point\n * @returns Collision result with contact information\n */\nfunction rotatedRectPointCollision(\n rect: Rectangle,\n point: Point,\n): CollisionResult {\n // Convert rotation from degrees to radians\n const rotationRad = (rect.rotationDeg * Math.PI) / 180;\n const cos = Math.cos(-rotationRad);\n const sin = Math.sin(-rotationRad);\n\n // Calculate rectangle center\n const rectCenterX = rect.position.x + rect.width / 2;\n const rectCenterY = rect.position.y + rect.height / 2;\n\n // Vector from rectangle center to point\n const dx = point.position.x - rectCenterX;\n const dy = point.position.y - rectCenterY;\n\n // Rotate the vector to align with the rectangle's local axes\n const rotatedX = cos * dx - sin * dy;\n const rotatedY = sin * dx + cos * dy;\n\n // Create a point in the rectangle's local space\n const localPoint: Point = {\n type: \"point\",\n position: {\n x: rotatedX + rectCenterX,\n y: rotatedY + rectCenterY,\n },\n };\n\n // Create an unrotated rectangle\n const localRect: Rectangle = {\n type: \"rectangle\",\n position: {\n x: rect.position.x,\n y: rect.position.y,\n },\n width: rect.width,\n height: rect.height,\n rotationDeg: 0,\n };\n\n // Check collision with the unrotated rectangle\n return rectPointCollision(localRect, localPoint);\n}\n","import { Rectangle, CollisionResult, Vector2D } from \"../../../types\";\nimport {\n subtract,\n normalize,\n dot,\n rectToAABB,\n aabbIntersect,\n} from \"../../../utils\";\n\n/**\n * Detect collision between two rectangles\n * This implementation handles rotated rectangles using the Separating Axis Theorem (SAT)\n */\nexport function rectRectCollision(\n rectA: Rectangle,\n rectB: Rectangle,\n): CollisionResult {\n // If both rectangles have zero rotation, use a simpler AABB check\n if (rectA.rotationDeg === 0 && rectB.rotationDeg === 0) {\n return aabbRectRectCollision(rectA, rectB);\n }\n\n // For rotated rectangles, use Separating Axis Theorem (SAT)\n return satRectRectCollision(rectA, rectB);\n}\n\n/**\n * Collision detection for axis-aligned (non-rotated) rectangles\n */\nfunction aabbRectRectCollision(\n rectA: Rectangle,\n rectB: Rectangle,\n): CollisionResult {\n return {\n colliding: aabbIntersect(rectToAABB(rectA), rectToAABB(rectB)),\n };\n}\n\n/**\n * Get the corners of a rotated rectangle\n */\nfunction getRectangleCorners(rect: Rectangle): Vector2D[] {\n const { position, width, height, rotationDeg } = rect;\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n\n // Calculate center of the rectangle\n const center = {\n x: position.x + halfWidth,\n y: position.y + halfHeight,\n };\n\n // Convert rotation to radians\n const rotationRad = (rotationDeg * Math.PI) / 180;\n const cos = Math.cos(rotationRad);\n const sin = Math.sin(rotationRad);\n\n // Calculate corners relative to center\n const corners: Vector2D[] = [\n { x: -halfWidth, y: -halfHeight }, // Top-left\n { x: halfWidth, y: -halfHeight }, // Top-right\n { x: halfWidth, y: halfHeight }, // Bottom-right\n { x: -halfWidth, y: halfHeight }, // Bottom-left\n ];\n\n // Rotate and translate corners\n return corners.map((corner) => ({\n x: center.x + (corner.x * cos - corner.y * sin),\n y: center.y + (corner.x * sin + corner.y * cos),\n }));\n}\n\n/**\n * Get the axes to test for the SAT algorithm\n */\nfunction getAxes(cornersA: Vector2D[], cornersB: Vector2D[]): Vector2D[] {\n const axes: Vector2D[] = [];\n\n // Add the normals of each edge of the first rectangle\n for (let i = 0; i < cornersA.length; i++) {\n const p1 = cornersA[i];\n const p2 = cornersA[(i + 1) % cornersA.length];\n const edge = subtract(p2, p1);\n // The normal is perpendicular to the edge\n const normal = normalize({ x: -edge.y, y: edge.x });\n axes.push(normal);\n }\n\n // Add the normals of each edge of the second rectangle\n for (let i = 0; i < cornersB.length; i++) {\n const p1 = cornersB[i];\n const p2 = cornersB[(i + 1) % cornersB.length];\n const edge = subtract(p2, p1);\n // The normal is perpendicular to the edge\n const normal = normalize({ x: -edge.y, y: edge.x });\n axes.push(normal);\n }\n\n return axes;\n}\n\n/**\n * Project a shape onto an axis\n */\nfunction projectShapeOntoAxis(\n corners: Vector2D[],\n axis: Vector2D,\n): { min: number; max: number } {\n let min = dot(corners[0], axis);\n let max = min;\n\n for (let i = 1; i < corners.length; i++) {\n const projection = dot(corners[i], axis);\n if (projection < min) min = projection;\n if (projection > max) max = projection;\n }\n\n return { min, max };\n}\n\n/**\n * Collision detection for rotated rectangles using Separating Axis Theorem (SAT)\n */\nfunction satRectRectCollision(\n rectA: Rectangle,\n rectB: Rectangle,\n): CollisionResult {\n // Get corners of both rectangles\n const cornersA = getRectangleCorners(rectA);\n const cornersB = getRectangleCorners(rectB);\n\n // Get axes to test\n const axes = getAxes(cornersA, cornersB);\n\n // Test each axis\n for (const axis of axes) {\n const projectionA = projectShapeOntoAxis(cornersA, axis);\n const projectionB = projectShapeOntoAxis(cornersB, axis);\n\n // Check for separation\n if (\n projectionA.max < projectionB.min ||\n projectionB.max < projectionA.min\n ) {\n // Shapes are separated along this axis\n return { colliding: false };\n }\n }\n\n // If we get here, the shapes are colliding\n return { colliding: true };\n}\n","import { Circle, Point, Rectangle, Shape } from \"../../types\";\nimport { circleCircleCollision } from \"./circleCircle\";\nimport { circlePointCollision } from \"./circlePoint\";\nimport { circleRectCollision } from \"./circleRect\";\nimport { rectPointCollision } from \"./rectPoint\";\nimport { rectRectCollision } from \"./rectRect\";\n\n/**\n * Check if two entities are colliding\n * @param shapeA First shape\n * @param shapeB Second shape\n * @returns True if the shapes are colliding\n */\nexport function checkShapeCollision(shapeA: Shape, shapeB: Shape): boolean {\n const shapeAType = shapeA.type;\n const shapeBType = shapeB.type;\n\n // Circle vs Circle\n if (shapeAType === \"circle\" && shapeBType === \"circle\") {\n return circleCircleCollision(shapeA as Circle, shapeB as Circle).colliding;\n }\n\n if (shapeAType === \"circle\" && shapeBType === \"point\") {\n return circlePointCollision(shapeA as Circle, shapeB as Point).colliding;\n }\n if (shapeAType === \"point\" && shapeBType === \"circle\") {\n return circlePointCollision(shapeB as Circle, shapeA as Point).colliding;\n }\n\n if (shapeAType === \"circle\" && shapeBType === \"rectangle\") {\n return circleRectCollision(shapeA as Circle, shapeB as Rectangle).colliding;\n }\n if (shapeAType === \"rectangle\" && shapeBType === \"circle\") {\n return circleRectCollision(shapeB as Circle, shapeA as Rectangle).colliding;\n }\n\n if (shapeAType === \"rectangle\" && shapeBType === \"rectangle\") {\n return rectRectCollision(shapeA as Rectangle, shapeB as Rectangle)\n .colliding;\n }\n\n if (shapeAType === \"rectangle\" && shapeBType === \"point\") {\n return rectPointCollision(shapeA as Rectangle, shapeB as Point).colliding;\n }\n if (shapeAType === \"point\" && shapeBType === \"rectangle\") {\n return rectPointCollision(shapeB as Rectangle, shapeA as Point).colliding;\n }\n\n return false;\n}\n","import { Entity, Shape } from \"../types\";\nimport { BaseCollisionDetector } from \"./CollisionDetector\";\nimport { checkShapeCollision } from \"./shapeCollisions\";\n\n/**\n * Collision detector that uses a brute force approach\n * Checks every entity against the given shape\n *\n * Best used when:\n * - You have a small number of entities\n * - You only need to check collisions occasionally\n * - You want the simplest implementation\n */\nexport function BruteForceCollisionDetector({\n entities,\n}: {\n entities: Entity[];\n}) {\n return new BruteForceCollisionDetectorImpl(entities);\n}\n\nclass BruteForceCollisionDetectorImpl extends BaseCollisionDetector {\n /**\n * Get all entities that collide with the given shape\n * @param shape The shape to check collisions against\n * @returns Array of entities that collide with the shape\n */\n getCollisions(shape: Shape): Entity[] {\n const collisions: Entity[] = [];\n\n // Check each entity against the given shape\n for (const entity of this.entities) {\n // Check if the shapes collide\n if (checkShapeCollision(shape, entity.shape)) {\n collisions.push(entity);\n }\n }\n\n return collisions;\n }\n}\n","import { AABB, Circle, Entity, Point, Rectangle, Shape } from \"../types\";\nimport { BaseCollisionDetector } from \"./CollisionDetector\";\nimport { checkShapeCollision } from \"./shapeCollisions\";\nimport { cellToId, circleToAABB, positionToCell, rectToAABB } from \"../utils\";\n\ntype CellId = number;\n\n/**\n * Configuration options for the spatial grid collision detector\n */\nexport interface SpatialGridConfig {\n /** Size of each grid cell */\n cellSize: number;\n}\n\n/**\n * Collision detector that uses spatial partitioning for efficient collision detection\n *\n * Best used when:\n * - You have a large number of entities\n * - Entities are distributed across the space\n * - You need to check collisions frequently\n */\nexport function SpatialGridCollisionDetector({\n entities,\n cellSize = 64,\n}: {\n entities: Entity[];\n cellSize?: number;\n}) {\n return new SpatialGridCollisionDetectorImpl(entities, { cellSize });\n}\n\nclass SpatialGridCollisionDetectorImpl extends BaseCollisionDetector {\n /** The spatial hash grid for quick lookups */\n private grid: Map<CellId, Entity[]>;\n /** Configuration for the spatial grid */\n private config: SpatialGridConfig;\n\n /**\n * Create a new spatial grid collision detector\n */\n constructor(entities: Entity[], config: SpatialGridConfig) {\n super(entities);\n this.config = config;\n this.grid = new Map();\n\n // Initialize the grid with entities\n this.rebuildGrid();\n }\n\n /**\n * Get all entities that collide with the given shape\n */\n getCollisions(shape: Shape): Entity[] {\n // Get the AABB for the shape\n const aabb = this.getAABBForShape(shape);\n\n // Get all cells that the AABB overlaps\n const cells = this.getCellsForAABB(aabb);\n\n // Get all entities in those cells\n const potentialCollisions = new Set<Entity>();\n\n for (const cellId of cells) {\n const entitiesInCell = this.grid.get(cellId);\n if (entitiesInCell) {\n for (const entity of entitiesInCell) {\n potentialCollisions.add(entity);\n }\n }\n }\n\n // Check for actual collisions\n const collisions: Entity[] = [];\n\n for (const entity of potentialCollisions) {\n if (checkShapeCollision(shape, entity.shape)) {\n collisions.push(entity);\n }\n }\n\n return collisions;\n }\n\n /**\n * Rebuild the spatial grid with the current entities\n */\n rebuildGrid(): void {\n // Clear the grid\n this.grid.clear();\n\n // Add all entities to the grid\n for (const entity of this.entities) {\n this.insertEntityIntoGrid(entity);\n }\n }\n\n /**\n * Insert an entity into the spatial grid\n */\n private insertEntityIntoGrid(entity: Entity): void {\n // Get the AABB for the entity\n const aabb = this.getAABB(entity);\n\n // Get all cells that the AABB overlaps\n const cells = this.getCellsForAABB(aabb);\n\n // Add the entity to each cell\n for (const cellId of cells) {\n if (!this.grid.has(cellId)) {\n this.grid.set(cellId, []);\n }\n\n this.grid.get(cellId)!.push(entity);\n }\n }\n\n /**\n * Get all cells that an AABB overlaps\n */\n private getCellsForAABB(aabb: AABB): CellId[] {\n const { cellSize } = this.config;\n\n // Calculate the min and max cell coordinates\n const [minCellX, minCellY] = positionToCell(aabb.min, cellSize);\n const [maxCellX, maxCellY] = positionToCell(aabb.max, cellSize);\n\n // Get all cells in the range\n const cells: CellId[] = new Array(\n (maxCellX - minCellX + 1) * (maxCellY - minCellY + 1),\n );\n let index = 0;\n\n for (let x = minCellX; x <= maxCellX; x++) {\n for (let y = minCellY; y <= maxCellY; y++) {\n cells[index++] = cellToId(x, y);\n }\n }\n\n return cells;\n }\n\n /**\n * Get the AABB for an entity\n */\n private getAABB(entity: Entity): AABB {\n return this.getAABBForShape(entity.shape);\n }\n\n /**\n * Get the AABB for a shape\n */\n private getAABBForShape(shape: Shape): AABB {\n const shapeType = shape.type;\n\n if (shapeType === \"circle\") {\n return circleToAABB(shape as Circle);\n } else if (shapeType === \"rectangle\") {\n return rectToAABB(shape as Rectangle);\n } else if (shapeType === \"point\") {\n // For a point, create a tiny AABB\n return {\n min: { x: (shape as Point).position.x, y: (shape as Point).position.y },\n max: { x: (shape as Point).position.x, y: (shape as Point).position.y },\n };\n }\n\n throw new Error(`Unsupported shape type: ${shapeType}`);\n }\n}\n","import { Vector2D, AABB, Point, Circle, Rectangle } from \"../types\";\n\n/**\n * Configuration for the camera\n */\nexport type CameraConfig = {\n /** Center position of the camera in world coordinates */\n position: Vector2D;\n /** Width of the viewport/canvas in pixels */\n width: number;\n /** Height of the viewport/canvas in pixels */\n height: number;\n /** Rotation in degrees (optional, defaults to 0) */\n rotation?: number;\n};\n\n/**\n * Converts a global coordinate object into a local camera coordinate system.\n */\nexport function globalCoordinatesToCameraCoordinates(\n global: Vector2D,\n camera: CameraConfig,\n): Vector2D;\nexport function globalCoordinatesToCameraCoordinates(\n global: Point,\n camera: CameraConfig,\n): Point;\nexport function globalCoordinatesToCameraCoordinates(\n global: Circle,\n camera: CameraConfig,\n): Circle;\nexport function globalCoordinatesToCameraCoordinates(\n global: Rectangle,\n camera: CameraConfig,\n): Rectangle;\nexport function globalCoordinatesToCameraCoordinates(\n global: AABB,\n camera: CameraConfig,\n): AABB;\nexport function globalCoordinatesToCameraCoordinates(\n global: Vector2D | Point | Circle | Rectangle | AABB,\n camera: CameraConfig,\n): Vector2D | Point | Circle | Rectangle | AABB {\n // Helper to transform a single point\n const transformPoint = (p: Vector2D): Vector2D => {\n // 1. Translate relative to camera position\n // If camera is at (100,100), world point (150,150) becomes (50,50)\n let x = p.x - camera.position.x;\n let y = p.y - camera.position.y;\n\n // 2. Rotate if needed\n if (camera.rotation) {\n const rad = (camera.rotation * Math.PI) / 180;\n // We rotate by -camera.rotation to bring world into camera space\n // If camera rotates +90 (clockwise), world appears to rotate -90 (counter-clockwise)\n const invRad = -rad;\n const cos = Math.cos(invRad);\n const sin = Math.sin(invRad);\n\n const rx = x * cos - y * sin;\n const ry = x * sin + y * cos;\n x = rx;\n y = ry;\n }\n\n // 3. Offset to viewport center\n // Camera position corresponds to the center of the screen\n x += camera.width / 2;\n y += camera.height / 2;\n\n return { x, y };\n };\n\n // Determine type and transform accordingly\n\n // Check for Shapes with 'type' property\n if (\"type\" in global) {\n if (global.type === \"point\") {\n return {\n ...global,\n position: transformPoint(global.position),\n };\n }\n\n if (global.type === \"circle\") {\n return {\n ...global,\n center: transformPoint(global.center),\n };\n }\n\n if (global.type === \"rectangle\") {\n return {\n ...global,\n position: transformPoint(global.position),\n // Rotation relative to camera\n rotationDeg: global.rotationDeg - (camera.rotation ?? 0),\n };\n }\n }\n\n // Check for AABB (min/max)\n if (\"min\" in global && \"max\" in global) {\n // For AABB, we must transform all corners and find the new AABB\n // because rotation might make it not axis-aligned in the original sense,\n // but the return type must be AABB.\n\n // If there is no rotation, we can just transform min/max\n if (!camera.rotation) {\n return {\n min: transformPoint(global.min),\n max: transformPoint(global.max),\n };\n }\n\n // With rotation, we need to transform all 4 corners\n const corners = [\n { x: global.min.x, y: global.min.y },\n { x: global.max.x, y: global.min.y },\n { x: global.max.x, y: global.max.y },\n { x: global.min.x, y: global.max.y },\n ];\n\n const transformed = corners.map(transformPoint);\n\n let minX = Infinity,\n minY = Infinity;\n let maxX = -Infinity,\n maxY = -Infinity;\n\n for (const p of transformed) {\n minX = Math.min(minX, p.x);\n minY = Math.min(minY, p.y);\n maxX = Math.max(maxX, p.x);\n maxY = Math.max(maxY, p.y);\n }\n\n return {\n min: { x: minX, y: minY },\n max: { x: maxX, y: maxY },\n };\n }\n\n // Check for Vector2D (x, y)\n // We check this last or ensure the other checks are exhaustive for types that might structurally overlap\n if (\"x\" in global && \"y\" in global) {\n return transformPoint(global);\n }\n\n throw new Error(\n \"Unsupported type passed to globalCoordinatesToCameraCoordinates\",\n );\n}\n"],"mappings":"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","names":["index_exports","__export","BaseCollisionDetector","BruteForceCollisionDetector","GameLoop","Input","SpatialGridCollisionDetector","VERSION","aabbIntersect","add","cellToId","checkShapeCollision","circleToAABB","cross","distance","distanceSquared","dot","globalCoordinatesToCameraCoordinates","length","lengthSquared","normalize","positionToCell","rectToAABB","scale","subtract","vec2","__toCommonJS","vec2","x","y","add","a","b","subtract","scale","v","scalar","dot","cross","lengthSquared","length","normalize","len","distanceSquared","dx","dy","distance","rectToAABB","rect","circleToAABB","circle","aabbIntersect","positionToCell","position","cellSize","cellToId","BaseCollisionDetector","entities","circleCircleCollision","circleA","circleB","distSquared","distanceSquared","radiusSum","circlePointCollision","circle","point","distanceSquared","circleRectCollision","circle","rect","circleRotatedRectCollision","closestX","closestY","distanceSquared","rotationRad","cos","sin","rectCenterX","rectCenterY","dx","dy","rotatedX","rotatedY","localCircle","localRect","rectPointCollision","rect","point","rotatedRectPointCollision","rotationRad","cos","sin","rectCenterX","rectCenterY","dx","dy","rotatedX","rotatedY","localPoint","localRect","rectRectCollision","rectA","rectB","aabbRectRectCollision","satRectRectCollision","aabbIntersect","rectToAABB","getRectangleCorners","rect","position","width","height","rotationDeg","halfWidth","halfHeight","center","rotationRad","cos","sin","corner","getAxes","cornersA","cornersB","axes","p1","p2","edge","subtract","normal","normalize","projectShapeOntoAxis","corners","axis","min","dot","max","i","projection","projectionA","projectionB","checkShapeCollision","shapeA","shapeB","shapeAType","shapeBType","circleCircleCollision","circlePointCollision","circleRectCollision","rectRectCollision","rectPointCollision","BruteForceCollisionDetector","entities","BruteForceCollisionDetectorImpl","BaseCollisionDetector","shape","collisions","entity","checkShapeCollision","SpatialGridCollisionDetector","entities","cellSize","SpatialGridCollisionDetectorImpl","BaseCollisionDetector","config","shape","aabb","cells","potentialCollisions","cellId","entitiesInCell","entity","collisions","checkShapeCollision","minCellX","minCellY","positionToCell","maxCellX","maxCellY","index","x","y","cellToId","shapeType","circleToAABB","rectToAABB","globalCoordinatesToCameraCoordinates","global","camera","transformPoint","p","x","y","invRad","cos","sin","rx","ry","transformed","minX","minY","maxX","maxY","VERSION","GameLoop","Input"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function
|
|
1
|
+
function z(t,o){return{x:t,y:o}}function k(t,o){return{x:t.x+o.x,y:t.y+o.y}}function h(t,o){return{x:t.x-o.x,y:t.y-o.y}}function O(t,o){return{x:t.x*o,y:t.y*o}}function R(t,o){return t.x*o.x+t.y*o.y}function U(t,o){return t.x*o.y-t.y*o.x}function q(t){return t.x*t.x+t.y*t.y}function G(t){return Math.sqrt(q(t))}function D(t){let o=G(t);return o<1e-10?{x:0,y:0}:{x:t.x/o,y:t.y/o}}function x(t,o){let n=o.x-t.x,i=o.y-t.y;return n*n+i*i}function H(t,o){return Math.sqrt(x(t,o))}function d(t){return{min:{x:t.position.x,y:t.position.y},max:{x:t.position.x+t.width,y:t.position.y+t.height}}}function P(t){return{min:{x:t.center.x-t.radius,y:t.center.y-t.radius},max:{x:t.center.x+t.radius,y:t.center.y+t.radius}}}function M(t,o){return!(t.max.x<o.min.x||t.min.x>o.max.x||t.max.y<o.min.y||t.min.y>o.max.y)}function A(t,o){return[Math.floor(t.x/o),Math.floor(t.y/o)]}function I(t,o){return(t+o)*(t+o+1)/2+o}var f=class{constructor(o){this.entities=o}};function w(t,o){let n=x(t.center,o.center),i=t.radius+o.radius;return{colliding:n<=i*i}}function B(t,o){return{colliding:x(t.center,o.position)<=t.radius*t.radius}}function y(t,o){if(o.rotationDeg!==0)return X(t,o);let n=Math.max(o.position.x,Math.min(t.center.x,o.position.x+o.width)),i=Math.max(o.position.y,Math.min(t.center.y,o.position.y+o.height));return{colliding:x(t.center,{x:n,y:i})<=t.radius*t.radius}}function X(t,o){let n=o.rotationDeg*Math.PI/180,i=Math.cos(-n),r=Math.sin(-n),e=o.position.x+o.width/2,s=o.position.y+o.height/2,c=t.center.x-e,l=t.center.y-s,a=i*c-r*l,u=r*c+i*l,m={type:"circle",center:{x:a+e,y:u+s},radius:t.radius},p={type:"rectangle",position:o.position,width:o.width,height:o.height,rotationDeg:0};return y(m,p)}function C(t,o){return t.rotationDeg!==0?Y(t,o):{colliding:o.position.x>=t.position.x&&o.position.x<=t.position.x+t.width&&o.position.y>=t.position.y&&o.position.y<=t.position.y+t.height}}function Y(t,o){let n=t.rotationDeg*Math.PI/180,i=Math.cos(-n),r=Math.sin(-n),e=t.position.x+t.width/2,s=t.position.y+t.height/2,c=o.position.x-e,l=o.position.y-s,a=i*c-r*l,u=r*c+i*l,m={type:"point",position:{x:a+e,y:u+s}},p={type:"rectangle",position:{x:t.position.x,y:t.position.y},width:t.width,height:t.height,rotationDeg:0};return C(p,m)}function T(t,o){return t.rotationDeg===0&&o.rotationDeg===0?v(t,o):j(t,o)}function v(t,o){return{colliding:M(d(t),d(o))}}function E(t){let{position:o,width:n,height:i,rotationDeg:r}=t,e=n/2,s=i/2,c={x:o.x+e,y:o.y+s},l=r*Math.PI/180,a=Math.cos(l),u=Math.sin(l);return[{x:-e,y:-s},{x:e,y:-s},{x:e,y:s},{x:-e,y:s}].map(p=>({x:c.x+(p.x*a-p.y*u),y:c.y+(p.x*u+p.y*a)}))}function F(t,o){let n=[];for(let i=0;i<t.length;i++){let r=t[i],e=t[(i+1)%t.length],s=h(e,r),c=D({x:-s.y,y:s.x});n.push(c)}for(let i=0;i<o.length;i++){let r=o[i],e=o[(i+1)%o.length],s=h(e,r),c=D({x:-s.y,y:s.x});n.push(c)}return n}function b(t,o){let n=R(t[0],o),i=n;for(let r=1;r<t.length;r++){let e=R(t[r],o);e<n&&(n=e),e>i&&(i=e)}return{min:n,max:i}}function j(t,o){let n=E(t),i=E(o),r=F(n,i);for(let e of r){let s=b(n,e),c=b(i,e);if(s.max<c.min||c.max<s.min)return{colliding:!1}}return{colliding:!0}}function g(t,o){let n=t.type,i=o.type;return n==="circle"&&i==="circle"?w(t,o).colliding:n==="circle"&&i==="point"?B(t,o).colliding:n==="point"&&i==="circle"?B(o,t).colliding:n==="circle"&&i==="rectangle"?y(t,o).colliding:n==="rectangle"&&i==="circle"?y(o,t).colliding:n==="rectangle"&&i==="rectangle"?T(t,o).colliding:n==="rectangle"&&i==="point"?C(t,o).colliding:n==="point"&&i==="rectangle"?C(o,t).colliding:!1}function ut({entities:t}){return new V(t)}var V=class extends f{getCollisions(o){let n=[];for(let i of this.entities)g(o,i.shape)&&n.push(i);return n}};function dt({entities:t,cellSize:o=64}){return new S(t,{cellSize:o})}var S=class extends f{constructor(o,n){super(o),this.config=n,this.grid=new Map,this.rebuildGrid()}getCollisions(o){let n=this.getAABBForShape(o),i=this.getCellsForAABB(n),r=new Set;for(let s of i){let c=this.grid.get(s);if(c)for(let l of c)r.add(l)}let e=[];for(let s of r)g(o,s.shape)&&e.push(s);return e}rebuildGrid(){this.grid.clear();for(let o of this.entities)this.insertEntityIntoGrid(o)}insertEntityIntoGrid(o){let n=this.getAABB(o),i=this.getCellsForAABB(n);for(let r of i)this.grid.has(r)||this.grid.set(r,[]),this.grid.get(r).push(o)}getCellsForAABB(o){let{cellSize:n}=this.config,[i,r]=A(o.min,n),[e,s]=A(o.max,n),c=new Array((e-i+1)*(s-r+1)),l=0;for(let a=i;a<=e;a++)for(let u=r;u<=s;u++)c[l++]=I(a,u);return c}getAABB(o){return this.getAABBForShape(o.shape)}getAABBForShape(o){let n=o.type;if(n==="circle")return P(o);if(n==="rectangle")return d(o);if(n==="point")return{min:{x:o.position.x,y:o.position.y},max:{x:o.position.x,y:o.position.y}};throw new Error(`Unsupported shape type: ${n}`)}};function At(t,o){let n=i=>{let r=i.x-o.position.x,e=i.y-o.position.y;if(o.rotation){let c=-(o.rotation*Math.PI/180),l=Math.cos(c),a=Math.sin(c),u=r*l-e*a,m=r*a+e*l;r=u,e=m}return r+=o.width/2,e+=o.height/2,{x:r,y:e}};if("type"in t){if(t.type==="point")return{...t,position:n(t.position)};if(t.type==="circle")return{...t,center:n(t.center)};if(t.type==="rectangle")return{...t,position:n(t.position),rotationDeg:t.rotationDeg-(o.rotation??0)}}if("min"in t&&"max"in t){if(!o.rotation)return{min:n(t.min),max:n(t.max)};let r=[{x:t.min.x,y:t.min.y},{x:t.max.x,y:t.min.y},{x:t.max.x,y:t.max.y},{x:t.min.x,y:t.max.y}].map(n),e=1/0,s=1/0,c=-1/0,l=-1/0;for(let a of r)e=Math.min(e,a.x),s=Math.min(s,a.y),c=Math.max(c,a.x),l=Math.max(l,a.y);return{min:{x:e,y:s},max:{x:c,y:l}}}if("x"in t&&"y"in t)return n(t);throw new Error("Unsupported type passed to globalCoordinatesToCameraCoordinates")}var Pt="0.0.1",Mt={notImplemented:!0,info:"Game loop management will be added in a future version"},It={notImplemented:!0,info:"Input handling will be added in a future version"};export{f as BaseCollisionDetector,ut as BruteForceCollisionDetector,Mt as GameLoop,It as Input,dt as SpatialGridCollisionDetector,Pt as VERSION,M as aabbIntersect,k as add,I as cellToId,g as checkShapeCollision,P as circleToAABB,U as cross,H as distance,x as distanceSquared,R as dot,At as globalCoordinatesToCameraCoordinates,G as length,q as lengthSquared,D as normalize,A as positionToCell,d as rectToAABB,O as scale,h as subtract,z as vec2};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts","../src/collision/CollisionDetector.ts","../src/collision/shapeCollisions/circleCircle/index.ts","../src/collision/shapeCollisions/circlePoint/index.ts","../src/collision/shapeCollisions/circleRect/index.ts","../src/collision/shapeCollisions/rectPoint/index.ts","../src/collision/shapeCollisions/rectRect/index.ts","../src/collision/shapeCollisions/checkShapeCollision.ts","../src/collision/BruteForceCollisionDetector.ts","../src/collision/SpatialGridCollisionDetector.ts","../src/render/index.ts","../src/index.ts"],"sourcesContent":["import { Vector2D, AABB, Circle, Rectangle } from \"./types\";\n\n/**\n * Create a new vector\n */\nexport function vec2(x: number, y: number): Vector2D {\n return { x, y };\n}\n\n/**\n * Vector addition\n */\nexport function add(a: Vector2D, b: Vector2D): Vector2D {\n return { x: a.x + b.x, y: a.y + b.y };\n}\n\n/**\n * Vector subtraction\n */\nexport function subtract(a: Vector2D, b: Vector2D): Vector2D {\n return { x: a.x - b.x, y: a.y - b.y };\n}\n\n/**\n * Vector scaling\n */\nexport function scale(v: Vector2D, scalar: number): Vector2D {\n return { x: v.x * scalar, y: v.y * scalar };\n}\n\n/**\n * Dot product of two vectors\n */\nexport function dot(a: Vector2D, b: Vector2D): number {\n return a.x * b.x + a.y * b.y;\n}\n\n/**\n * Cross product magnitude of two 2D vectors\n */\nexport function cross(a: Vector2D, b: Vector2D): number {\n return a.x * b.y - a.y * b.x;\n}\n\n/**\n * Get squared length of a vector (avoids sqrt for performance)\n */\nexport function lengthSquared(v: Vector2D): number {\n return v.x * v.x + v.y * v.y;\n}\n\n/**\n * Get vector length\n */\nexport function length(v: Vector2D): number {\n return Math.sqrt(lengthSquared(v));\n}\n\n/**\n * Normalize a vector (make it unit length)\n */\nexport function normalize(v: Vector2D): Vector2D {\n const len = length(v);\n // Avoid division by zero\n if (len < 1e-10) return { x: 0, y: 0 };\n return { x: v.x / len, y: v.y / len };\n}\n\n/**\n * Distance squared between two points (avoids sqrt for performance)\n */\nexport function distanceSquared(a: Vector2D, b: Vector2D): number {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n return dx * dx + dy * dy;\n}\n\n/**\n * Distance between two points\n */\nexport function distance(a: Vector2D, b: Vector2D): number {\n return Math.sqrt(distanceSquared(a, b));\n}\n\n/**\n * Create an AABB from a rectangle\n */\nexport function rectToAABB(rect: Rectangle): AABB {\n return {\n min: { x: rect.position.x, y: rect.position.y },\n max: { x: rect.position.x + rect.width, y: rect.position.y + rect.height },\n };\n}\n\n/**\n * Create an AABB from a circle\n */\nexport function circleToAABB(circle: Circle): AABB {\n return {\n min: {\n x: circle.center.x - circle.radius,\n y: circle.center.y - circle.radius,\n },\n max: {\n x: circle.center.x + circle.radius,\n y: circle.center.y + circle.radius,\n },\n };\n}\n\n/**\n * Check if two AABBs intersect\n */\nexport function aabbIntersect(a: AABB, b: AABB): boolean {\n // Exit with no intersection if separated along an axis\n if (a.max.x < b.min.x || a.min.x > b.max.x) return false;\n if (a.max.y < b.min.y || a.min.y > b.max.y) return false;\n\n // Overlapping on all axes means AABBs are intersecting\n return true;\n}\n\n/**\n * Calculate cell indices for a position in a spatial grid\n */\nexport function positionToCell(\n position: Vector2D,\n cellSize: number,\n): [number, number] {\n return [Math.floor(position.x / cellSize), Math.floor(position.y / cellSize)];\n}\n\n/**\n * Calculate a unique cell ID from grid coordinates\n * Uses a spatial hashing function to convert 2D coordinates to 1D\n */\nexport function cellToId(x: number, y: number): number {\n // Cantor pairing function - maps two non-negative integers to a unique non-negative integer\n return ((x + y) * (x + y + 1)) / 2 + y;\n}\n","import { Entity, Shape } from \"../types\";\n\n/**\n * Base class for collision detectors that implements common functionality\n */\nexport abstract class BaseCollisionDetector {\n /**\n * The entities to check collisions against\n */\n protected entities: Entity[];\n\n /**\n * Create a new collision detector\n * @param entities The entities to check collisions against\n */\n constructor(entities: Entity[]) {\n this.entities = entities;\n }\n\n /**\n * Get all entities that collide with the given shape\n * @param shape The shape to check collisions against\n * @returns Array of entity IDs that collide with the shape\n */\n abstract getCollisions(shape: Shape): (string | number)[];\n}\n","import { Circle, CollisionResult } from \"../../../types\";\nimport { distanceSquared } from \"../../../utils\";\n\n/**\n * Detects collision between two circles\n * @param circleA First circle\n * @param circleB Second circle\n * @returns Collision result with contact information\n */\nexport function circleCircleCollision(\n circleA: Circle,\n circleB: Circle,\n): CollisionResult {\n const distSquared = distanceSquared(circleA.center, circleB.center);\n\n const radiusSum = circleA.radius + circleB.radius;\n\n const colliding = distSquared <= radiusSum * radiusSum;\n\n return {\n colliding,\n };\n}\n","import { Circle, CollisionResult, Point } from \"../../../types\";\nimport { distanceSquared } from \"../../../utils\";\n\n/**\n * Detects collision between a circle and a point\n * @param circle Circle\n * @param point Point\n * @returns Collision result with contact information\n */\nexport function circlePointCollision(\n circle: Circle,\n point: Point,\n): CollisionResult {\n const distSquared = distanceSquared(circle.center, point.position);\n\n const colliding = distSquared <= circle.radius * circle.radius;\n\n return {\n colliding,\n };\n}\n","import { Circle, CollisionResult, Rectangle } from \"../../../types\";\nimport { distanceSquared } from \"../../../utils\";\n\n/**\n * Detects collision between a circle and a rectangle\n * @param circle Circle\n * @param rect Rectangle\n * @returns Collision result with contact information\n */\nexport function circleRectCollision(\n circle: Circle,\n rect: Rectangle,\n): CollisionResult {\n // Handle rotation if present\n if (rect.rotationDeg !== 0) {\n return circleRotatedRectCollision(circle, rect);\n }\n\n // Find the closest point on the rectangle to the circle center\n const closestX = Math.max(\n rect.position.x,\n Math.min(circle.center.x, rect.position.x + rect.width),\n );\n const closestY = Math.max(\n rect.position.y,\n Math.min(circle.center.y, rect.position.y + rect.height),\n );\n\n const distSquared = distanceSquared(circle.center, {\n x: closestX,\n y: closestY,\n });\n\n // Check if the circle is colliding with the rectangle\n const colliding = distSquared <= circle.radius * circle.radius;\n\n return {\n colliding,\n };\n}\n\n/**\n * Detects collision between a circle and a rotated rectangle\n * @param circle Circle\n * @param rect Rotated rectangle\n * @returns Collision result with contact information\n */\nfunction circleRotatedRectCollision(\n circle: Circle,\n rect: Rectangle,\n): CollisionResult {\n // Convert rotation from degrees to radians\n const rotationRad = (rect.rotationDeg * Math.PI) / 180;\n const cos = Math.cos(-rotationRad);\n const sin = Math.sin(-rotationRad);\n\n // Translate circle center to rectangle's local space (unrotated)\n const rectCenterX = rect.position.x + rect.width / 2;\n const rectCenterY = rect.position.y + rect.height / 2;\n\n // Vector from rectangle center to circle center\n const dx = circle.center.x - rectCenterX;\n const dy = circle.center.y - rectCenterY;\n\n // Rotate the vector to align with the rectangle's local axes\n const rotatedX = cos * dx - sin * dy;\n const rotatedY = sin * dx + cos * dy;\n\n // Create a circle in the rectangle's local space\n const localCircle: Circle = {\n type: \"circle\",\n center: {\n x: rotatedX + rectCenterX,\n y: rotatedY + rectCenterY,\n },\n radius: circle.radius,\n };\n\n // Create an unrotated rectangle\n const localRect: Rectangle = {\n type: \"rectangle\",\n position: rect.position,\n width: rect.width,\n height: rect.height,\n rotationDeg: 0,\n };\n\n // Check collision with the unrotated rectangle\n return circleRectCollision(localCircle, localRect);\n}\n","import { CollisionResult, Point, Rectangle } from \"../../../types\";\n\n/**\n * Detects collision between a rectangle and a point\n * @param rect Rectangle\n * @param point Point\n * @returns Collision result with contact information\n */\nexport function rectPointCollision(\n rect: Rectangle,\n point: Point,\n): CollisionResult {\n // Handle rotation if present\n if (rect.rotationDeg !== 0) {\n return rotatedRectPointCollision(rect, point);\n }\n\n // Check if the point is inside the rectangle\n const colliding =\n point.position.x >= rect.position.x &&\n point.position.x <= rect.position.x + rect.width &&\n point.position.y >= rect.position.y &&\n point.position.y <= rect.position.y + rect.height;\n\n return {\n colliding,\n };\n}\n\n/**\n * Detects collision between a rotated rectangle and a point\n * @param rect Rotated rectangle\n * @param point Point\n * @returns Collision result with contact information\n */\nfunction rotatedRectPointCollision(\n rect: Rectangle,\n point: Point,\n): CollisionResult {\n // Convert rotation from degrees to radians\n const rotationRad = (rect.rotationDeg * Math.PI) / 180;\n const cos = Math.cos(-rotationRad);\n const sin = Math.sin(-rotationRad);\n\n // Calculate rectangle center\n const rectCenterX = rect.position.x + rect.width / 2;\n const rectCenterY = rect.position.y + rect.height / 2;\n\n // Vector from rectangle center to point\n const dx = point.position.x - rectCenterX;\n const dy = point.position.y - rectCenterY;\n\n // Rotate the vector to align with the rectangle's local axes\n const rotatedX = cos * dx - sin * dy;\n const rotatedY = sin * dx + cos * dy;\n\n // Create a point in the rectangle's local space\n const localPoint: Point = {\n type: \"point\",\n position: {\n x: rotatedX + rectCenterX,\n y: rotatedY + rectCenterY,\n },\n };\n\n // Create an unrotated rectangle\n const localRect: Rectangle = {\n type: \"rectangle\",\n position: {\n x: rect.position.x,\n y: rect.position.y,\n },\n width: rect.width,\n height: rect.height,\n rotationDeg: 0,\n };\n\n // Check collision with the unrotated rectangle\n return rectPointCollision(localRect, localPoint);\n}\n","import { Rectangle, CollisionResult, Vector2D } from \"../../../types\";\nimport {\n subtract,\n normalize,\n dot,\n rectToAABB,\n aabbIntersect,\n} from \"../../../utils\";\n\n/**\n * Detect collision between two rectangles\n * This implementation handles rotated rectangles using the Separating Axis Theorem (SAT)\n */\nexport function rectRectCollision(\n rectA: Rectangle,\n rectB: Rectangle,\n): CollisionResult {\n // If both rectangles have zero rotation, use a simpler AABB check\n if (rectA.rotationDeg === 0 && rectB.rotationDeg === 0) {\n return aabbRectRectCollision(rectA, rectB);\n }\n\n // For rotated rectangles, use Separating Axis Theorem (SAT)\n return satRectRectCollision(rectA, rectB);\n}\n\n/**\n * Collision detection for axis-aligned (non-rotated) rectangles\n */\nfunction aabbRectRectCollision(\n rectA: Rectangle,\n rectB: Rectangle,\n): CollisionResult {\n return {\n colliding: aabbIntersect(rectToAABB(rectA), rectToAABB(rectB)),\n };\n}\n\n/**\n * Get the corners of a rotated rectangle\n */\nfunction getRectangleCorners(rect: Rectangle): Vector2D[] {\n const { position, width, height, rotationDeg } = rect;\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n\n // Calculate center of the rectangle\n const center = {\n x: position.x + halfWidth,\n y: position.y + halfHeight,\n };\n\n // Convert rotation to radians\n const rotationRad = (rotationDeg * Math.PI) / 180;\n const cos = Math.cos(rotationRad);\n const sin = Math.sin(rotationRad);\n\n // Calculate corners relative to center\n const corners: Vector2D[] = [\n { x: -halfWidth, y: -halfHeight }, // Top-left\n { x: halfWidth, y: -halfHeight }, // Top-right\n { x: halfWidth, y: halfHeight }, // Bottom-right\n { x: -halfWidth, y: halfHeight }, // Bottom-left\n ];\n\n // Rotate and translate corners\n return corners.map((corner) => ({\n x: center.x + (corner.x * cos - corner.y * sin),\n y: center.y + (corner.x * sin + corner.y * cos),\n }));\n}\n\n/**\n * Get the axes to test for the SAT algorithm\n */\nfunction getAxes(cornersA: Vector2D[], cornersB: Vector2D[]): Vector2D[] {\n const axes: Vector2D[] = [];\n\n // Add the normals of each edge of the first rectangle\n for (let i = 0; i < cornersA.length; i++) {\n const p1 = cornersA[i];\n const p2 = cornersA[(i + 1) % cornersA.length];\n const edge = subtract(p2, p1);\n // The normal is perpendicular to the edge\n const normal = normalize({ x: -edge.y, y: edge.x });\n axes.push(normal);\n }\n\n // Add the normals of each edge of the second rectangle\n for (let i = 0; i < cornersB.length; i++) {\n const p1 = cornersB[i];\n const p2 = cornersB[(i + 1) % cornersB.length];\n const edge = subtract(p2, p1);\n // The normal is perpendicular to the edge\n const normal = normalize({ x: -edge.y, y: edge.x });\n axes.push(normal);\n }\n\n return axes;\n}\n\n/**\n * Project a shape onto an axis\n */\nfunction projectShapeOntoAxis(\n corners: Vector2D[],\n axis: Vector2D,\n): { min: number; max: number } {\n let min = dot(corners[0], axis);\n let max = min;\n\n for (let i = 1; i < corners.length; i++) {\n const projection = dot(corners[i], axis);\n if (projection < min) min = projection;\n if (projection > max) max = projection;\n }\n\n return { min, max };\n}\n\n/**\n * Collision detection for rotated rectangles using Separating Axis Theorem (SAT)\n */\nfunction satRectRectCollision(\n rectA: Rectangle,\n rectB: Rectangle,\n): CollisionResult {\n // Get corners of both rectangles\n const cornersA = getRectangleCorners(rectA);\n const cornersB = getRectangleCorners(rectB);\n\n // Get axes to test\n const axes = getAxes(cornersA, cornersB);\n\n // Test each axis\n for (const axis of axes) {\n const projectionA = projectShapeOntoAxis(cornersA, axis);\n const projectionB = projectShapeOntoAxis(cornersB, axis);\n\n // Check for separation\n if (\n projectionA.max < projectionB.min ||\n projectionB.max < projectionA.min\n ) {\n // Shapes are separated along this axis\n return { colliding: false };\n }\n }\n\n // If we get here, the shapes are colliding\n return { colliding: true };\n}\n","import { Circle, Point, Rectangle, Shape } from \"../../types\";\nimport { circleCircleCollision } from \"./circleCircle\";\nimport { circlePointCollision } from \"./circlePoint\";\nimport { circleRectCollision } from \"./circleRect\";\nimport { rectPointCollision } from \"./rectPoint\";\nimport { rectRectCollision } from \"./rectRect\";\n\n/**\n * Check if two entities are colliding\n * @param shapeA First shape\n * @param shapeB Second shape\n * @returns True if the shapes are colliding\n */\nexport function checkShapeCollision(shapeA: Shape, shapeB: Shape): boolean {\n const shapeAType = shapeA.type;\n const shapeBType = shapeB.type;\n\n // Circle vs Circle\n if (shapeAType === \"circle\" && shapeBType === \"circle\") {\n return circleCircleCollision(shapeA as Circle, shapeB as Circle).colliding;\n }\n\n if (shapeAType === \"circle\" && shapeBType === \"point\") {\n return circlePointCollision(shapeA as Circle, shapeB as Point).colliding;\n }\n if (shapeAType === \"point\" && shapeBType === \"circle\") {\n return circlePointCollision(shapeB as Circle, shapeA as Point).colliding;\n }\n\n if (shapeAType === \"circle\" && shapeBType === \"rectangle\") {\n return circleRectCollision(shapeA as Circle, shapeB as Rectangle).colliding;\n }\n if (shapeAType === \"rectangle\" && shapeBType === \"circle\") {\n return circleRectCollision(shapeB as Circle, shapeA as Rectangle).colliding;\n }\n\n if (shapeAType === \"rectangle\" && shapeBType === \"rectangle\") {\n return rectRectCollision(shapeA as Rectangle, shapeB as Rectangle)\n .colliding;\n }\n\n if (shapeAType === \"rectangle\" && shapeBType === \"point\") {\n return rectPointCollision(shapeA as Rectangle, shapeB as Point).colliding;\n }\n if (shapeAType === \"point\" && shapeBType === \"rectangle\") {\n return rectPointCollision(shapeB as Rectangle, shapeA as Point).colliding;\n }\n\n return false;\n}\n","import { Entity, Shape } from \"../types\";\nimport { BaseCollisionDetector } from \"./CollisionDetector\";\nimport { checkShapeCollision } from \"./shapeCollisions/checkShapeCollision\";\n\n/**\n * Collision detector that uses a brute force approach\n * Checks every entity against the given shape\n *\n * Best used when:\n * - You have a small number of entities\n * - You only need to check collisions occasionally\n * - You want the simplest implementation\n */\nexport function BruteForceCollisionDetector({\n entities,\n}: {\n entities: Entity[];\n}) {\n return new BruteForceCollisionDetectorImpl(entities);\n}\n\nclass BruteForceCollisionDetectorImpl extends BaseCollisionDetector {\n /**\n * Get all entities that collide with the given shape\n * @param shape The shape to check collisions against\n * @returns Array of entity IDs that collide with the shape\n */\n getCollisions(shape: Shape): (string | number)[] {\n const collisions: (string | number)[] = [];\n\n // Check each entity against the given shape\n for (const entity of this.entities) {\n // Check if the shapes collide\n if (checkShapeCollision(shape, entity.shape)) {\n collisions.push(entity.id);\n }\n }\n\n return collisions;\n }\n}\n","import { AABB, Circle, Entity, Point, Rectangle, Shape } from \"../types\";\nimport { BaseCollisionDetector } from \"./CollisionDetector\";\nimport { checkShapeCollision } from \"./shapeCollisions/checkShapeCollision\";\nimport { cellToId, circleToAABB, positionToCell, rectToAABB } from \"../utils\";\n\ntype CellId = number;\n\n/**\n * Configuration options for the spatial grid collision detector\n */\nexport interface SpatialGridConfig {\n /** Size of each grid cell */\n cellSize: number;\n}\n\n/**\n * Collision detector that uses spatial partitioning for efficient collision detection\n *\n * Best used when:\n * - You have a large number of entities\n * - Entities are distributed across the space\n * - You need to check collisions frequently\n */\nexport function SpatialGridCollisionDetector({\n entities,\n cellSize = 64,\n}: {\n entities: Entity[];\n cellSize?: number;\n}) {\n return new SpatialGridCollisionDetectorImpl(entities, { cellSize });\n}\n\nclass SpatialGridCollisionDetectorImpl extends BaseCollisionDetector {\n /** The spatial hash grid for quick lookups */\n private grid: Map<CellId, Entity[]>;\n /** Configuration for the spatial grid */\n private config: SpatialGridConfig;\n\n /**\n * Create a new spatial grid collision detector\n */\n constructor(entities: Entity[], config: SpatialGridConfig) {\n super(entities);\n this.config = config;\n this.grid = new Map();\n\n // Initialize the grid with entities\n this.rebuildGrid();\n }\n\n /**\n * Get all entities that collide with the given shape\n */\n getCollisions(shape: Shape): (string | number)[] {\n // Get the AABB for the shape\n const aabb = this.getAABBForShape(shape);\n\n // Get all cells that the AABB overlaps\n const cells = this.getCellsForAABB(aabb);\n\n // Get all entities in those cells\n const potentialCollisions = new Set<Entity>();\n\n for (const cellId of cells) {\n const entitiesInCell = this.grid.get(cellId);\n if (entitiesInCell) {\n for (const entity of entitiesInCell) {\n potentialCollisions.add(entity);\n }\n }\n }\n\n // Check for actual collisions\n const collisions: (string | number)[] = [];\n\n for (const entity of potentialCollisions) {\n if (checkShapeCollision(shape, entity.shape)) {\n collisions.push(entity.id);\n }\n }\n\n return collisions;\n }\n\n /**\n * Rebuild the spatial grid with the current entities\n */\n rebuildGrid(): void {\n // Clear the grid\n this.grid.clear();\n\n // Add all entities to the grid\n for (const entity of this.entities) {\n this.insertEntityIntoGrid(entity);\n }\n }\n\n /**\n * Insert an entity into the spatial grid\n */\n private insertEntityIntoGrid(entity: Entity): void {\n // Get the AABB for the entity\n const aabb = this.getAABB(entity);\n\n // Get all cells that the AABB overlaps\n const cells = this.getCellsForAABB(aabb);\n\n // Add the entity to each cell\n for (const cellId of cells) {\n if (!this.grid.has(cellId)) {\n this.grid.set(cellId, []);\n }\n\n this.grid.get(cellId)!.push(entity);\n }\n }\n\n /**\n * Get all cells that an AABB overlaps\n */\n private getCellsForAABB(aabb: AABB): CellId[] {\n const { cellSize } = this.config;\n\n // Calculate the min and max cell coordinates\n const [minCellX, minCellY] = positionToCell(aabb.min, cellSize);\n const [maxCellX, maxCellY] = positionToCell(aabb.max, cellSize);\n\n // Get all cells in the range\n const cells: CellId[] = new Array(\n (maxCellX - minCellX + 1) * (maxCellY - minCellY + 1),\n );\n let index = 0;\n\n for (let x = minCellX; x <= maxCellX; x++) {\n for (let y = minCellY; y <= maxCellY; y++) {\n cells[index++] = cellToId(x, y);\n }\n }\n\n return cells;\n }\n\n /**\n * Get the AABB for an entity\n */\n private getAABB(entity: Entity): AABB {\n return this.getAABBForShape(entity.shape);\n }\n\n /**\n * Get the AABB for a shape\n */\n private getAABBForShape(shape: Shape): AABB {\n const shapeType = shape.type;\n\n if (shapeType === \"circle\") {\n return circleToAABB(shape as Circle);\n } else if (shapeType === \"rectangle\") {\n return rectToAABB(shape as Rectangle);\n } else if (shapeType === \"point\") {\n // For a point, create a tiny AABB\n return {\n min: { x: (shape as Point).position.x, y: (shape as Point).position.y },\n max: { x: (shape as Point).position.x, y: (shape as Point).position.y },\n };\n }\n\n throw new Error(`Unsupported shape type: ${shapeType}`);\n }\n}\n","import { Circle, Point, Rectangle, Shape } from \"../types\";\nimport { ShapeStyle, RendererOptions, RenderableShape } from \"./types\";\n\n/**\n * Apply style settings to the canvas context\n */\nexport function applyStyle(ctx: CanvasRenderingContext2D, style: ShapeStyle) {\n // Save the current context state\n ctx.save();\n\n // Apply fill and stroke styles\n if (style.fillColor) {\n ctx.fillStyle = style.fillColor;\n }\n\n if (style.strokeColor) {\n ctx.strokeStyle = style.strokeColor;\n }\n\n if (style.strokeWidth !== undefined) {\n ctx.lineWidth = style.strokeWidth;\n }\n\n if (style.alpha !== undefined) {\n ctx.globalAlpha = style.alpha;\n }\n\n // Apply shadow settings if provided\n if (style.shadowBlur !== undefined) {\n ctx.shadowBlur = style.shadowBlur;\n }\n\n if (style.shadowColor) {\n ctx.shadowColor = style.shadowColor;\n }\n\n if (style.shadowOffsetX !== undefined) {\n ctx.shadowOffsetX = style.shadowOffsetX;\n }\n\n if (style.shadowOffsetY !== undefined) {\n ctx.shadowOffsetY = style.shadowOffsetY;\n }\n}\n\n/**\n * Restore the canvas context to its previous state\n */\nexport function restoreContext(ctx: CanvasRenderingContext2D) {\n ctx.restore();\n}\n\n/**\n * Render a circle shape\n */\nexport function renderCircle(\n ctx: CanvasRenderingContext2D,\n circle: Circle,\n style: ShapeStyle,\n) {\n applyStyle(ctx, style);\n\n ctx.beginPath();\n ctx.arc(circle.center.x, circle.center.y, circle.radius, 0, Math.PI * 2);\n\n if (style.fillColor) {\n ctx.fill();\n }\n\n if (style.strokeColor && style.strokeWidth && style.strokeWidth > 0) {\n ctx.stroke();\n }\n\n restoreContext(ctx);\n}\n\n/**\n * Render a point shape\n */\nexport function renderPoint(\n ctx: CanvasRenderingContext2D,\n point: Point,\n style: ShapeStyle,\n) {\n // Points are rendered as small circles\n const pointSize = style.strokeWidth || 4;\n\n applyStyle(ctx, style);\n\n ctx.beginPath();\n ctx.arc(point.position.x, point.position.y, pointSize / 2, 0, Math.PI * 2);\n\n if (style.fillColor) {\n ctx.fill();\n }\n\n if (style.strokeColor && style.strokeWidth && style.strokeWidth > 0) {\n ctx.stroke();\n }\n\n restoreContext(ctx);\n}\n\n/**\n * Render a rectangle shape\n */\nexport function renderRectangle(\n ctx: CanvasRenderingContext2D,\n rectangle: Rectangle,\n style: ShapeStyle,\n) {\n applyStyle(ctx, style);\n\n // Save the current transformation matrix\n ctx.save();\n\n // Translate to the rectangle's position\n ctx.translate(rectangle.position.x, rectangle.position.y);\n\n // Rotate if needed\n if (rectangle.rotationDeg !== 0) {\n const rotationRad = (rectangle.rotationDeg * Math.PI) / 180;\n ctx.rotate(rotationRad);\n }\n\n // Draw the rectangle centered at the origin\n const halfWidth = rectangle.width / 2;\n const halfHeight = rectangle.height / 2;\n\n if (style.fillColor) {\n ctx.fillRect(-halfWidth, -halfHeight, rectangle.width, rectangle.height);\n }\n\n if (style.strokeColor && style.strokeWidth && style.strokeWidth > 0) {\n ctx.strokeRect(-halfWidth, -halfHeight, rectangle.width, rectangle.height);\n }\n\n // Restore the transformation matrix\n ctx.restore();\n\n // Restore the style context\n restoreContext(ctx);\n}\n\n/**\n * Render any shape based on its type\n */\nexport function renderShape(\n ctx: CanvasRenderingContext2D,\n shape: Shape,\n style: ShapeStyle,\n) {\n switch (shape.type) {\n case \"circle\":\n renderCircle(ctx, shape, style);\n break;\n case \"rectangle\":\n renderRectangle(ctx, shape, style);\n break;\n case \"point\":\n renderPoint(ctx, shape, style);\n break;\n default:\n // This should never happen if all shape types are handled\n console.warn(\"Unknown shape type encountered\");\n break;\n }\n}\n\n/**\n * Main renderer function to render multiple shapes\n */\nexport function renderShapes(\n ctx: CanvasRenderingContext2D,\n shapes: RenderableShape[],\n options: RendererOptions,\n) {\n // Render each shape\n for (const { shape, style } of shapes) {\n // Merge with default style if provided\n const mergedStyle = {\n ...options.defaultStyle,\n ...style,\n };\n\n renderShape(ctx, shape, mergedStyle);\n }\n}\n","/**\n * pepperjs\n * A spicy, high-performance library for building 2D games in JavaScript\n *\n * @packageDocumentation\n */\n\n// ----- Collision Detection System -----\n// Export types\nexport * from \"./types\";\n\n// Export utility functions\nexport * from \"./utils\";\n\n// Export collision detection system\nexport * from \"./collision\";\n\n// Export rendering system\nexport * from \"./render\";\n\n// ----- Library Information -----\nexport const VERSION = \"0.0.1\";\n\n// ----- Future modules (placeholders) -----\n// These will be implemented in future versions\n\n/**\n * @internal\n * Rendering capabilities\n */\nexport const Renderer = {\n // Renderer is now implemented\n notImplemented: false,\n\n // Information about implementation\n info: \"Basic rendering capabilities are now available\",\n};\n\n/**\n * @internal\n * Future game loop management API\n */\nexport const GameLoop = {\n // Placeholder for future game loop module\n notImplemented: true,\n\n // Information about planned implementation\n info: \"Game loop management will be added in a future version\",\n};\n\n/**\n * @internal\n * Future input handling API\n */\nexport const Input = {\n // Placeholder for future input handling module\n notImplemented: true,\n\n // Information about planned implementation\n info: \"Input handling will be added in a future version\",\n};\n"],"mappings":"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","names":["vec2","x","y","add","a","b","subtract","scale","v","scalar","dot","cross","lengthSquared","length","normalize","len","distanceSquared","dx","dy","distance","rectToAABB","rect","circleToAABB","circle","aabbIntersect","positionToCell","position","cellSize","cellToId","BaseCollisionDetector","entities","circleCircleCollision","circleA","circleB","distSquared","distanceSquared","radiusSum","circlePointCollision","circle","point","distanceSquared","circleRectCollision","circle","rect","circleRotatedRectCollision","closestX","closestY","distanceSquared","rotationRad","cos","sin","rectCenterX","rectCenterY","dx","dy","rotatedX","rotatedY","localCircle","localRect","rectPointCollision","rect","point","rotatedRectPointCollision","rotationRad","cos","sin","rectCenterX","rectCenterY","dx","dy","rotatedX","rotatedY","localPoint","localRect","rectRectCollision","rectA","rectB","aabbRectRectCollision","satRectRectCollision","aabbIntersect","rectToAABB","getRectangleCorners","rect","position","width","height","rotationDeg","halfWidth","halfHeight","center","rotationRad","cos","sin","corner","getAxes","cornersA","cornersB","axes","i","p1","p2","edge","subtract","normal","normalize","projectShapeOntoAxis","corners","axis","min","dot","max","projection","projectionA","projectionB","checkShapeCollision","shapeA","shapeB","shapeAType","shapeBType","circleCircleCollision","circlePointCollision","circleRectCollision","rectRectCollision","rectPointCollision","BruteForceCollisionDetector","entities","BruteForceCollisionDetectorImpl","BaseCollisionDetector","shape","collisions","entity","checkShapeCollision","SpatialGridCollisionDetector","entities","cellSize","SpatialGridCollisionDetectorImpl","BaseCollisionDetector","config","shape","aabb","cells","potentialCollisions","cellId","entitiesInCell","entity","collisions","checkShapeCollision","minCellX","minCellY","positionToCell","maxCellX","maxCellY","index","x","y","cellToId","shapeType","circleToAABB","rectToAABB","applyStyle","ctx","style","restoreContext","renderCircle","circle","renderPoint","point","pointSize","renderRectangle","rectangle","rotationRad","halfWidth","halfHeight","renderShape","shape","renderShapes","shapes","options","mergedStyle","VERSION","Renderer","GameLoop","Input"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts","../src/collision/CollisionDetector.ts","../src/collision/shapeCollisions/circleCircle/index.ts","../src/collision/shapeCollisions/circlePoint/index.ts","../src/collision/shapeCollisions/circleRect/index.ts","../src/collision/shapeCollisions/rectPoint/index.ts","../src/collision/shapeCollisions/rectRect/index.ts","../src/collision/shapeCollisions/index.ts","../src/collision/BruteForceCollisionDetector.ts","../src/collision/SpatialGridCollisionDetector.ts","../src/camera/Camera.ts","../src/index.ts"],"sourcesContent":["import { Vector2D, AABB, Circle, Rectangle } from \"./types\";\n\n/**\n * Create a new vector\n */\nexport function vec2(x: number, y: number): Vector2D {\n return { x, y };\n}\n\n/**\n * Vector addition\n */\nexport function add(a: Vector2D, b: Vector2D): Vector2D {\n return { x: a.x + b.x, y: a.y + b.y };\n}\n\n/**\n * Vector subtraction\n */\nexport function subtract(a: Vector2D, b: Vector2D): Vector2D {\n return { x: a.x - b.x, y: a.y - b.y };\n}\n\n/**\n * Vector scaling\n */\nexport function scale(v: Vector2D, scalar: number): Vector2D {\n return { x: v.x * scalar, y: v.y * scalar };\n}\n\n/**\n * Dot product of two vectors\n */\nexport function dot(a: Vector2D, b: Vector2D): number {\n return a.x * b.x + a.y * b.y;\n}\n\n/**\n * Cross product magnitude of two 2D vectors\n */\nexport function cross(a: Vector2D, b: Vector2D): number {\n return a.x * b.y - a.y * b.x;\n}\n\n/**\n * Get squared length of a vector (avoids sqrt for performance)\n */\nexport function lengthSquared(v: Vector2D): number {\n return v.x * v.x + v.y * v.y;\n}\n\n/**\n * Get vector length\n */\nexport function length(v: Vector2D): number {\n return Math.sqrt(lengthSquared(v));\n}\n\n/**\n * Normalize a vector (make it unit length)\n */\nexport function normalize(v: Vector2D): Vector2D {\n const len = length(v);\n // Avoid division by zero\n if (len < 1e-10) return { x: 0, y: 0 };\n return { x: v.x / len, y: v.y / len };\n}\n\n/**\n * Distance squared between two points (avoids sqrt for performance)\n */\nexport function distanceSquared(a: Vector2D, b: Vector2D): number {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n return dx * dx + dy * dy;\n}\n\n/**\n * Distance between two points\n */\nexport function distance(a: Vector2D, b: Vector2D): number {\n return Math.sqrt(distanceSquared(a, b));\n}\n\n/**\n * Create an AABB from a rectangle\n */\nexport function rectToAABB(rect: Rectangle): AABB {\n return {\n min: { x: rect.position.x, y: rect.position.y },\n max: { x: rect.position.x + rect.width, y: rect.position.y + rect.height },\n };\n}\n\n/**\n * Create an AABB from a circle\n */\nexport function circleToAABB(circle: Circle): AABB {\n return {\n min: {\n x: circle.center.x - circle.radius,\n y: circle.center.y - circle.radius,\n },\n max: {\n x: circle.center.x + circle.radius,\n y: circle.center.y + circle.radius,\n },\n };\n}\n\n/**\n * Check if two AABBs intersect\n */\nexport function aabbIntersect(a: AABB, b: AABB): boolean {\n // Exit with no intersection if separated along an axis\n if (a.max.x < b.min.x || a.min.x > b.max.x) return false;\n if (a.max.y < b.min.y || a.min.y > b.max.y) return false;\n\n // Overlapping on all axes means AABBs are intersecting\n return true;\n}\n\n/**\n * Calculate cell indices for a position in a spatial grid\n */\nexport function positionToCell(\n position: Vector2D,\n cellSize: number,\n): [number, number] {\n return [Math.floor(position.x / cellSize), Math.floor(position.y / cellSize)];\n}\n\n/**\n * Calculate a unique cell ID from grid coordinates\n * Uses a spatial hashing function to convert 2D coordinates to 1D\n */\nexport function cellToId(x: number, y: number): number {\n // Cantor pairing function - maps two non-negative integers to a unique non-negative integer\n return ((x + y) * (x + y + 1)) / 2 + y;\n}\n","import { Entity, Shape } from \"../types\";\n\n/**\n * Base class for collision detectors that implements common functionality\n */\nexport abstract class BaseCollisionDetector {\n /**\n * The entities to check collisions against\n */\n protected entities: Entity[];\n\n /**\n * Create a new collision detector\n * @param entities The entities to check collisions against\n */\n constructor(entities: Entity[]) {\n this.entities = entities;\n }\n\n /**\n * Get all entities that collide with the given shape\n * @param shape The shape to check collisions against\n * @returns Array of entities that collide with the shape\n */\n abstract getCollisions(shape: Shape): Entity[];\n}\n","import { Circle, CollisionResult } from \"../../../types\";\nimport { distanceSquared } from \"../../../utils\";\n\n/**\n * Detects collision between two circles\n * @param circleA First circle\n * @param circleB Second circle\n * @returns Collision result with contact information\n */\nexport function circleCircleCollision(\n circleA: Circle,\n circleB: Circle,\n): CollisionResult {\n const distSquared = distanceSquared(circleA.center, circleB.center);\n\n const radiusSum = circleA.radius + circleB.radius;\n\n const colliding = distSquared <= radiusSum * radiusSum;\n\n return {\n colliding,\n };\n}\n","import { Circle, CollisionResult, Point } from \"../../../types\";\nimport { distanceSquared } from \"../../../utils\";\n\n/**\n * Detects collision between a circle and a point\n * @param circle Circle\n * @param point Point\n * @returns Collision result with contact information\n */\nexport function circlePointCollision(\n circle: Circle,\n point: Point,\n): CollisionResult {\n const distSquared = distanceSquared(circle.center, point.position);\n\n const colliding = distSquared <= circle.radius * circle.radius;\n\n return {\n colliding,\n };\n}\n","import { Circle, CollisionResult, Rectangle } from \"../../../types\";\nimport { distanceSquared } from \"../../../utils\";\n\n/**\n * Detects collision between a circle and a rectangle\n * @param circle Circle\n * @param rect Rectangle\n * @returns Collision result with contact information\n */\nexport function circleRectCollision(\n circle: Circle,\n rect: Rectangle,\n): CollisionResult {\n // Handle rotation if present\n if (rect.rotationDeg !== 0) {\n return circleRotatedRectCollision(circle, rect);\n }\n\n // Find the closest point on the rectangle to the circle center\n const closestX = Math.max(\n rect.position.x,\n Math.min(circle.center.x, rect.position.x + rect.width),\n );\n const closestY = Math.max(\n rect.position.y,\n Math.min(circle.center.y, rect.position.y + rect.height),\n );\n\n const distSquared = distanceSquared(circle.center, {\n x: closestX,\n y: closestY,\n });\n\n // Check if the circle is colliding with the rectangle\n const colliding = distSquared <= circle.radius * circle.radius;\n\n return {\n colliding,\n };\n}\n\n/**\n * Detects collision between a circle and a rotated rectangle\n * @param circle Circle\n * @param rect Rotated rectangle\n * @returns Collision result with contact information\n */\nfunction circleRotatedRectCollision(\n circle: Circle,\n rect: Rectangle,\n): CollisionResult {\n // Convert rotation from degrees to radians\n const rotationRad = (rect.rotationDeg * Math.PI) / 180;\n const cos = Math.cos(-rotationRad);\n const sin = Math.sin(-rotationRad);\n\n // Translate circle center to rectangle's local space (unrotated)\n const rectCenterX = rect.position.x + rect.width / 2;\n const rectCenterY = rect.position.y + rect.height / 2;\n\n // Vector from rectangle center to circle center\n const dx = circle.center.x - rectCenterX;\n const dy = circle.center.y - rectCenterY;\n\n // Rotate the vector to align with the rectangle's local axes\n const rotatedX = cos * dx - sin * dy;\n const rotatedY = sin * dx + cos * dy;\n\n // Create a circle in the rectangle's local space\n const localCircle: Circle = {\n type: \"circle\",\n center: {\n x: rotatedX + rectCenterX,\n y: rotatedY + rectCenterY,\n },\n radius: circle.radius,\n };\n\n // Create an unrotated rectangle\n const localRect: Rectangle = {\n type: \"rectangle\",\n position: rect.position,\n width: rect.width,\n height: rect.height,\n rotationDeg: 0,\n };\n\n // Check collision with the unrotated rectangle\n return circleRectCollision(localCircle, localRect);\n}\n","import { CollisionResult, Point, Rectangle } from \"../../../types\";\n\n/**\n * Detects collision between a rectangle and a point\n * @param rect Rectangle\n * @param point Point\n * @returns Collision result with contact information\n */\nexport function rectPointCollision(\n rect: Rectangle,\n point: Point,\n): CollisionResult {\n // Handle rotation if present\n if (rect.rotationDeg !== 0) {\n return rotatedRectPointCollision(rect, point);\n }\n\n // Check if the point is inside the rectangle\n const colliding =\n point.position.x >= rect.position.x &&\n point.position.x <= rect.position.x + rect.width &&\n point.position.y >= rect.position.y &&\n point.position.y <= rect.position.y + rect.height;\n\n return {\n colliding,\n };\n}\n\n/**\n * Detects collision between a rotated rectangle and a point\n * @param rect Rotated rectangle\n * @param point Point\n * @returns Collision result with contact information\n */\nfunction rotatedRectPointCollision(\n rect: Rectangle,\n point: Point,\n): CollisionResult {\n // Convert rotation from degrees to radians\n const rotationRad = (rect.rotationDeg * Math.PI) / 180;\n const cos = Math.cos(-rotationRad);\n const sin = Math.sin(-rotationRad);\n\n // Calculate rectangle center\n const rectCenterX = rect.position.x + rect.width / 2;\n const rectCenterY = rect.position.y + rect.height / 2;\n\n // Vector from rectangle center to point\n const dx = point.position.x - rectCenterX;\n const dy = point.position.y - rectCenterY;\n\n // Rotate the vector to align with the rectangle's local axes\n const rotatedX = cos * dx - sin * dy;\n const rotatedY = sin * dx + cos * dy;\n\n // Create a point in the rectangle's local space\n const localPoint: Point = {\n type: \"point\",\n position: {\n x: rotatedX + rectCenterX,\n y: rotatedY + rectCenterY,\n },\n };\n\n // Create an unrotated rectangle\n const localRect: Rectangle = {\n type: \"rectangle\",\n position: {\n x: rect.position.x,\n y: rect.position.y,\n },\n width: rect.width,\n height: rect.height,\n rotationDeg: 0,\n };\n\n // Check collision with the unrotated rectangle\n return rectPointCollision(localRect, localPoint);\n}\n","import { Rectangle, CollisionResult, Vector2D } from \"../../../types\";\nimport {\n subtract,\n normalize,\n dot,\n rectToAABB,\n aabbIntersect,\n} from \"../../../utils\";\n\n/**\n * Detect collision between two rectangles\n * This implementation handles rotated rectangles using the Separating Axis Theorem (SAT)\n */\nexport function rectRectCollision(\n rectA: Rectangle,\n rectB: Rectangle,\n): CollisionResult {\n // If both rectangles have zero rotation, use a simpler AABB check\n if (rectA.rotationDeg === 0 && rectB.rotationDeg === 0) {\n return aabbRectRectCollision(rectA, rectB);\n }\n\n // For rotated rectangles, use Separating Axis Theorem (SAT)\n return satRectRectCollision(rectA, rectB);\n}\n\n/**\n * Collision detection for axis-aligned (non-rotated) rectangles\n */\nfunction aabbRectRectCollision(\n rectA: Rectangle,\n rectB: Rectangle,\n): CollisionResult {\n return {\n colliding: aabbIntersect(rectToAABB(rectA), rectToAABB(rectB)),\n };\n}\n\n/**\n * Get the corners of a rotated rectangle\n */\nfunction getRectangleCorners(rect: Rectangle): Vector2D[] {\n const { position, width, height, rotationDeg } = rect;\n const halfWidth = width / 2;\n const halfHeight = height / 2;\n\n // Calculate center of the rectangle\n const center = {\n x: position.x + halfWidth,\n y: position.y + halfHeight,\n };\n\n // Convert rotation to radians\n const rotationRad = (rotationDeg * Math.PI) / 180;\n const cos = Math.cos(rotationRad);\n const sin = Math.sin(rotationRad);\n\n // Calculate corners relative to center\n const corners: Vector2D[] = [\n { x: -halfWidth, y: -halfHeight }, // Top-left\n { x: halfWidth, y: -halfHeight }, // Top-right\n { x: halfWidth, y: halfHeight }, // Bottom-right\n { x: -halfWidth, y: halfHeight }, // Bottom-left\n ];\n\n // Rotate and translate corners\n return corners.map((corner) => ({\n x: center.x + (corner.x * cos - corner.y * sin),\n y: center.y + (corner.x * sin + corner.y * cos),\n }));\n}\n\n/**\n * Get the axes to test for the SAT algorithm\n */\nfunction getAxes(cornersA: Vector2D[], cornersB: Vector2D[]): Vector2D[] {\n const axes: Vector2D[] = [];\n\n // Add the normals of each edge of the first rectangle\n for (let i = 0; i < cornersA.length; i++) {\n const p1 = cornersA[i];\n const p2 = cornersA[(i + 1) % cornersA.length];\n const edge = subtract(p2, p1);\n // The normal is perpendicular to the edge\n const normal = normalize({ x: -edge.y, y: edge.x });\n axes.push(normal);\n }\n\n // Add the normals of each edge of the second rectangle\n for (let i = 0; i < cornersB.length; i++) {\n const p1 = cornersB[i];\n const p2 = cornersB[(i + 1) % cornersB.length];\n const edge = subtract(p2, p1);\n // The normal is perpendicular to the edge\n const normal = normalize({ x: -edge.y, y: edge.x });\n axes.push(normal);\n }\n\n return axes;\n}\n\n/**\n * Project a shape onto an axis\n */\nfunction projectShapeOntoAxis(\n corners: Vector2D[],\n axis: Vector2D,\n): { min: number; max: number } {\n let min = dot(corners[0], axis);\n let max = min;\n\n for (let i = 1; i < corners.length; i++) {\n const projection = dot(corners[i], axis);\n if (projection < min) min = projection;\n if (projection > max) max = projection;\n }\n\n return { min, max };\n}\n\n/**\n * Collision detection for rotated rectangles using Separating Axis Theorem (SAT)\n */\nfunction satRectRectCollision(\n rectA: Rectangle,\n rectB: Rectangle,\n): CollisionResult {\n // Get corners of both rectangles\n const cornersA = getRectangleCorners(rectA);\n const cornersB = getRectangleCorners(rectB);\n\n // Get axes to test\n const axes = getAxes(cornersA, cornersB);\n\n // Test each axis\n for (const axis of axes) {\n const projectionA = projectShapeOntoAxis(cornersA, axis);\n const projectionB = projectShapeOntoAxis(cornersB, axis);\n\n // Check for separation\n if (\n projectionA.max < projectionB.min ||\n projectionB.max < projectionA.min\n ) {\n // Shapes are separated along this axis\n return { colliding: false };\n }\n }\n\n // If we get here, the shapes are colliding\n return { colliding: true };\n}\n","import { Circle, Point, Rectangle, Shape } from \"../../types\";\nimport { circleCircleCollision } from \"./circleCircle\";\nimport { circlePointCollision } from \"./circlePoint\";\nimport { circleRectCollision } from \"./circleRect\";\nimport { rectPointCollision } from \"./rectPoint\";\nimport { rectRectCollision } from \"./rectRect\";\n\n/**\n * Check if two entities are colliding\n * @param shapeA First shape\n * @param shapeB Second shape\n * @returns True if the shapes are colliding\n */\nexport function checkShapeCollision(shapeA: Shape, shapeB: Shape): boolean {\n const shapeAType = shapeA.type;\n const shapeBType = shapeB.type;\n\n // Circle vs Circle\n if (shapeAType === \"circle\" && shapeBType === \"circle\") {\n return circleCircleCollision(shapeA as Circle, shapeB as Circle).colliding;\n }\n\n if (shapeAType === \"circle\" && shapeBType === \"point\") {\n return circlePointCollision(shapeA as Circle, shapeB as Point).colliding;\n }\n if (shapeAType === \"point\" && shapeBType === \"circle\") {\n return circlePointCollision(shapeB as Circle, shapeA as Point).colliding;\n }\n\n if (shapeAType === \"circle\" && shapeBType === \"rectangle\") {\n return circleRectCollision(shapeA as Circle, shapeB as Rectangle).colliding;\n }\n if (shapeAType === \"rectangle\" && shapeBType === \"circle\") {\n return circleRectCollision(shapeB as Circle, shapeA as Rectangle).colliding;\n }\n\n if (shapeAType === \"rectangle\" && shapeBType === \"rectangle\") {\n return rectRectCollision(shapeA as Rectangle, shapeB as Rectangle)\n .colliding;\n }\n\n if (shapeAType === \"rectangle\" && shapeBType === \"point\") {\n return rectPointCollision(shapeA as Rectangle, shapeB as Point).colliding;\n }\n if (shapeAType === \"point\" && shapeBType === \"rectangle\") {\n return rectPointCollision(shapeB as Rectangle, shapeA as Point).colliding;\n }\n\n return false;\n}\n","import { Entity, Shape } from \"../types\";\nimport { BaseCollisionDetector } from \"./CollisionDetector\";\nimport { checkShapeCollision } from \"./shapeCollisions\";\n\n/**\n * Collision detector that uses a brute force approach\n * Checks every entity against the given shape\n *\n * Best used when:\n * - You have a small number of entities\n * - You only need to check collisions occasionally\n * - You want the simplest implementation\n */\nexport function BruteForceCollisionDetector({\n entities,\n}: {\n entities: Entity[];\n}) {\n return new BruteForceCollisionDetectorImpl(entities);\n}\n\nclass BruteForceCollisionDetectorImpl extends BaseCollisionDetector {\n /**\n * Get all entities that collide with the given shape\n * @param shape The shape to check collisions against\n * @returns Array of entities that collide with the shape\n */\n getCollisions(shape: Shape): Entity[] {\n const collisions: Entity[] = [];\n\n // Check each entity against the given shape\n for (const entity of this.entities) {\n // Check if the shapes collide\n if (checkShapeCollision(shape, entity.shape)) {\n collisions.push(entity);\n }\n }\n\n return collisions;\n }\n}\n","import { AABB, Circle, Entity, Point, Rectangle, Shape } from \"../types\";\nimport { BaseCollisionDetector } from \"./CollisionDetector\";\nimport { checkShapeCollision } from \"./shapeCollisions\";\nimport { cellToId, circleToAABB, positionToCell, rectToAABB } from \"../utils\";\n\ntype CellId = number;\n\n/**\n * Configuration options for the spatial grid collision detector\n */\nexport interface SpatialGridConfig {\n /** Size of each grid cell */\n cellSize: number;\n}\n\n/**\n * Collision detector that uses spatial partitioning for efficient collision detection\n *\n * Best used when:\n * - You have a large number of entities\n * - Entities are distributed across the space\n * - You need to check collisions frequently\n */\nexport function SpatialGridCollisionDetector({\n entities,\n cellSize = 64,\n}: {\n entities: Entity[];\n cellSize?: number;\n}) {\n return new SpatialGridCollisionDetectorImpl(entities, { cellSize });\n}\n\nclass SpatialGridCollisionDetectorImpl extends BaseCollisionDetector {\n /** The spatial hash grid for quick lookups */\n private grid: Map<CellId, Entity[]>;\n /** Configuration for the spatial grid */\n private config: SpatialGridConfig;\n\n /**\n * Create a new spatial grid collision detector\n */\n constructor(entities: Entity[], config: SpatialGridConfig) {\n super(entities);\n this.config = config;\n this.grid = new Map();\n\n // Initialize the grid with entities\n this.rebuildGrid();\n }\n\n /**\n * Get all entities that collide with the given shape\n */\n getCollisions(shape: Shape): Entity[] {\n // Get the AABB for the shape\n const aabb = this.getAABBForShape(shape);\n\n // Get all cells that the AABB overlaps\n const cells = this.getCellsForAABB(aabb);\n\n // Get all entities in those cells\n const potentialCollisions = new Set<Entity>();\n\n for (const cellId of cells) {\n const entitiesInCell = this.grid.get(cellId);\n if (entitiesInCell) {\n for (const entity of entitiesInCell) {\n potentialCollisions.add(entity);\n }\n }\n }\n\n // Check for actual collisions\n const collisions: Entity[] = [];\n\n for (const entity of potentialCollisions) {\n if (checkShapeCollision(shape, entity.shape)) {\n collisions.push(entity);\n }\n }\n\n return collisions;\n }\n\n /**\n * Rebuild the spatial grid with the current entities\n */\n rebuildGrid(): void {\n // Clear the grid\n this.grid.clear();\n\n // Add all entities to the grid\n for (const entity of this.entities) {\n this.insertEntityIntoGrid(entity);\n }\n }\n\n /**\n * Insert an entity into the spatial grid\n */\n private insertEntityIntoGrid(entity: Entity): void {\n // Get the AABB for the entity\n const aabb = this.getAABB(entity);\n\n // Get all cells that the AABB overlaps\n const cells = this.getCellsForAABB(aabb);\n\n // Add the entity to each cell\n for (const cellId of cells) {\n if (!this.grid.has(cellId)) {\n this.grid.set(cellId, []);\n }\n\n this.grid.get(cellId)!.push(entity);\n }\n }\n\n /**\n * Get all cells that an AABB overlaps\n */\n private getCellsForAABB(aabb: AABB): CellId[] {\n const { cellSize } = this.config;\n\n // Calculate the min and max cell coordinates\n const [minCellX, minCellY] = positionToCell(aabb.min, cellSize);\n const [maxCellX, maxCellY] = positionToCell(aabb.max, cellSize);\n\n // Get all cells in the range\n const cells: CellId[] = new Array(\n (maxCellX - minCellX + 1) * (maxCellY - minCellY + 1),\n );\n let index = 0;\n\n for (let x = minCellX; x <= maxCellX; x++) {\n for (let y = minCellY; y <= maxCellY; y++) {\n cells[index++] = cellToId(x, y);\n }\n }\n\n return cells;\n }\n\n /**\n * Get the AABB for an entity\n */\n private getAABB(entity: Entity): AABB {\n return this.getAABBForShape(entity.shape);\n }\n\n /**\n * Get the AABB for a shape\n */\n private getAABBForShape(shape: Shape): AABB {\n const shapeType = shape.type;\n\n if (shapeType === \"circle\") {\n return circleToAABB(shape as Circle);\n } else if (shapeType === \"rectangle\") {\n return rectToAABB(shape as Rectangle);\n } else if (shapeType === \"point\") {\n // For a point, create a tiny AABB\n return {\n min: { x: (shape as Point).position.x, y: (shape as Point).position.y },\n max: { x: (shape as Point).position.x, y: (shape as Point).position.y },\n };\n }\n\n throw new Error(`Unsupported shape type: ${shapeType}`);\n }\n}\n","import { Vector2D, AABB, Point, Circle, Rectangle } from \"../types\";\n\n/**\n * Configuration for the camera\n */\nexport type CameraConfig = {\n /** Center position of the camera in world coordinates */\n position: Vector2D;\n /** Width of the viewport/canvas in pixels */\n width: number;\n /** Height of the viewport/canvas in pixels */\n height: number;\n /** Rotation in degrees (optional, defaults to 0) */\n rotation?: number;\n};\n\n/**\n * Converts a global coordinate object into a local camera coordinate system.\n */\nexport function globalCoordinatesToCameraCoordinates(\n global: Vector2D,\n camera: CameraConfig,\n): Vector2D;\nexport function globalCoordinatesToCameraCoordinates(\n global: Point,\n camera: CameraConfig,\n): Point;\nexport function globalCoordinatesToCameraCoordinates(\n global: Circle,\n camera: CameraConfig,\n): Circle;\nexport function globalCoordinatesToCameraCoordinates(\n global: Rectangle,\n camera: CameraConfig,\n): Rectangle;\nexport function globalCoordinatesToCameraCoordinates(\n global: AABB,\n camera: CameraConfig,\n): AABB;\nexport function globalCoordinatesToCameraCoordinates(\n global: Vector2D | Point | Circle | Rectangle | AABB,\n camera: CameraConfig,\n): Vector2D | Point | Circle | Rectangle | AABB {\n // Helper to transform a single point\n const transformPoint = (p: Vector2D): Vector2D => {\n // 1. Translate relative to camera position\n // If camera is at (100,100), world point (150,150) becomes (50,50)\n let x = p.x - camera.position.x;\n let y = p.y - camera.position.y;\n\n // 2. Rotate if needed\n if (camera.rotation) {\n const rad = (camera.rotation * Math.PI) / 180;\n // We rotate by -camera.rotation to bring world into camera space\n // If camera rotates +90 (clockwise), world appears to rotate -90 (counter-clockwise)\n const invRad = -rad;\n const cos = Math.cos(invRad);\n const sin = Math.sin(invRad);\n\n const rx = x * cos - y * sin;\n const ry = x * sin + y * cos;\n x = rx;\n y = ry;\n }\n\n // 3. Offset to viewport center\n // Camera position corresponds to the center of the screen\n x += camera.width / 2;\n y += camera.height / 2;\n\n return { x, y };\n };\n\n // Determine type and transform accordingly\n\n // Check for Shapes with 'type' property\n if (\"type\" in global) {\n if (global.type === \"point\") {\n return {\n ...global,\n position: transformPoint(global.position),\n };\n }\n\n if (global.type === \"circle\") {\n return {\n ...global,\n center: transformPoint(global.center),\n };\n }\n\n if (global.type === \"rectangle\") {\n return {\n ...global,\n position: transformPoint(global.position),\n // Rotation relative to camera\n rotationDeg: global.rotationDeg - (camera.rotation ?? 0),\n };\n }\n }\n\n // Check for AABB (min/max)\n if (\"min\" in global && \"max\" in global) {\n // For AABB, we must transform all corners and find the new AABB\n // because rotation might make it not axis-aligned in the original sense,\n // but the return type must be AABB.\n\n // If there is no rotation, we can just transform min/max\n if (!camera.rotation) {\n return {\n min: transformPoint(global.min),\n max: transformPoint(global.max),\n };\n }\n\n // With rotation, we need to transform all 4 corners\n const corners = [\n { x: global.min.x, y: global.min.y },\n { x: global.max.x, y: global.min.y },\n { x: global.max.x, y: global.max.y },\n { x: global.min.x, y: global.max.y },\n ];\n\n const transformed = corners.map(transformPoint);\n\n let minX = Infinity,\n minY = Infinity;\n let maxX = -Infinity,\n maxY = -Infinity;\n\n for (const p of transformed) {\n minX = Math.min(minX, p.x);\n minY = Math.min(minY, p.y);\n maxX = Math.max(maxX, p.x);\n maxY = Math.max(maxY, p.y);\n }\n\n return {\n min: { x: minX, y: minY },\n max: { x: maxX, y: maxY },\n };\n }\n\n // Check for Vector2D (x, y)\n // We check this last or ensure the other checks are exhaustive for types that might structurally overlap\n if (\"x\" in global && \"y\" in global) {\n return transformPoint(global);\n }\n\n throw new Error(\n \"Unsupported type passed to globalCoordinatesToCameraCoordinates\",\n );\n}\n","/**\n * InfernoJS\n * A spicy, high-performance library for building 2D games in JavaScript\n *\n * @packageDocumentation\n */\n\n// ----- Collision Detection System -----\n// Export types\nexport * from \"./types\";\n\n// Export utility functions\nexport * from \"./utils\";\n\n// Export collision detection system\nexport * from \"./collision\";\n\n// Export camera system\nexport * from \"./camera\";\n\n// ----- Library Information -----\nexport const VERSION = \"0.0.1\";\n\n// ----- Future modules (placeholders) -----\n// These will be implemented in future versions\n\n/**\n * @internal\n * Future game loop management API\n */\nexport const GameLoop = {\n // Placeholder for future game loop module\n notImplemented: true,\n\n // Information about planned implementation\n info: \"Game loop management will be added in a future version\",\n};\n\n/**\n * @internal\n * Future input handling API\n */\nexport const Input = {\n // Placeholder for future input handling module\n notImplemented: true,\n\n // Information about planned implementation\n info: \"Input handling will be added in a future version\",\n};\n"],"mappings":"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","names":["vec2","x","y","add","a","b","subtract","scale","v","scalar","dot","cross","lengthSquared","length","normalize","len","distanceSquared","dx","dy","distance","rectToAABB","rect","circleToAABB","circle","aabbIntersect","positionToCell","position","cellSize","cellToId","BaseCollisionDetector","entities","circleCircleCollision","circleA","circleB","distSquared","distanceSquared","radiusSum","circlePointCollision","circle","point","distanceSquared","circleRectCollision","circle","rect","circleRotatedRectCollision","closestX","closestY","distanceSquared","rotationRad","cos","sin","rectCenterX","rectCenterY","dx","dy","rotatedX","rotatedY","localCircle","localRect","rectPointCollision","rect","point","rotatedRectPointCollision","rotationRad","cos","sin","rectCenterX","rectCenterY","dx","dy","rotatedX","rotatedY","localPoint","localRect","rectRectCollision","rectA","rectB","aabbRectRectCollision","satRectRectCollision","aabbIntersect","rectToAABB","getRectangleCorners","rect","position","width","height","rotationDeg","halfWidth","halfHeight","center","rotationRad","cos","sin","corner","getAxes","cornersA","cornersB","axes","p1","p2","edge","subtract","normal","normalize","projectShapeOntoAxis","corners","axis","min","dot","max","i","projection","projectionA","projectionB","checkShapeCollision","shapeA","shapeB","shapeAType","shapeBType","circleCircleCollision","circlePointCollision","circleRectCollision","rectRectCollision","rectPointCollision","BruteForceCollisionDetector","entities","BruteForceCollisionDetectorImpl","BaseCollisionDetector","shape","collisions","entity","checkShapeCollision","SpatialGridCollisionDetector","entities","cellSize","SpatialGridCollisionDetectorImpl","BaseCollisionDetector","config","shape","aabb","cells","potentialCollisions","cellId","entitiesInCell","entity","collisions","checkShapeCollision","minCellX","minCellY","positionToCell","maxCellX","maxCellY","index","x","y","cellToId","shapeType","circleToAABB","rectToAABB","globalCoordinatesToCameraCoordinates","global","camera","transformPoint","p","x","y","invRad","cos","sin","rx","ry","transformed","minX","minY","maxX","maxY","VERSION","GameLoop","Input"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "infernojs",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "A
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "A library for building 2D games in TypeScript",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|