2d-physics-engine
Version:
A lightweight, flexible 2D physics engine with ECS architecture, built with TypeScript
249 lines (177 loc) • 6.28 kB
Markdown
# 2D Physics Engine
A lightweight, flexible 2D physics engine built with TypeScript, featuring an Entity-Component-System (ECS) architecture. Perfect for building 2D games, simulations, and interactive applications.
## Features
- 🎮 **ECS Architecture** - Clean separation of concerns with Entity-Component-System pattern
- 🚀 **Rigidbody Physics** - Mass, velocity, forces, friction, and restitution
- 💥 **Collision Detection** - Circle-to-circle collision detection with penetration resolution
- 🎨 **Rendering System** - Built-in canvas-based rendering with custom drawers
- 🎯 **Input Management** - Keyboard and mouse input handling
- 📐 **Math Utilities** - Vector2, AABB, and QuadTree for spatial operations
- 🔧 **TypeScript** - Fully typed for better development experience
- ⚡ **Fixed Timestep** - Stable physics simulation with configurable timestep
> **⚠️ Note:** This project is **not production-ready**. It is still under active development and primarily built for **educational purposes**, experimentation, and learning how 2D physics engines and ECS architectures work. Use it as a learning tool or prototype, but it may contain bugs, incomplete features, and performance limitations.
## Installation
```bash
npm install 2d-physics-engine
# or
yarn add 2d-physics-engine
# or
pnpm add 2d-physics-engine
```
## Quick Start
```typescript
import { Iterator, Scene, Entity, Transform, Rigidbody, CircleCollider, Vector2, InputManager } from '2d-physics-engine';
// Setup canvas
const canvas = document.getElementById('canvas') as HTMLCanvasElement;
const ctx = canvas.getContext('2d')!;
const inputManager = new InputManager();
// Create engine
const engine = new Iterator(inputManager, canvas, ctx);
// Create scene
const scene = new Scene();
// Create an entity with physics
const ball = new Entity('Ball');
ball.addComponent(new Transform(new Vector2(100, 100)));
ball.addComponent(new Rigidbody({ mass: 1, restitution: 0.8, friction: 0.1 }));
ball.addComponent(new CircleCollider(25));
scene.addEntity(ball);
// Start the engine
engine.setScene(scene);
engine.start();
```
## Core Concepts
### Entity-Component-System
- **Entity**: Container for components (e.g., a ball, player, wall)
- **Component**: Data container (Transform, Rigidbody, Collider)
- **System**: Logic that operates on entities with specific components
### Components
#### Transform
Handles position, rotation, and scale of entities.
```typescript
const transform = new Transform(
new Vector2(100, 100), // position
0, // rotation (radians)
new Vector2(1, 1), // scale
);
```
#### Rigidbody
Adds physics properties to an entity.
```typescript
const rigidbody = new Rigidbody({
mass: 1, // mass in kg
restitution: 0.8, // bounciness (0-1)
friction: 0.1, // friction coefficient
});
```
#### Colliders
Define collision shapes for entities.
```typescript
const collider = new CircleCollider(25); // radius
```
### Math Utilities
#### Vector2
2D vector operations for position, velocity, forces, etc.
```typescript
import { Vector2 } from '2d-physics-engine';
const v1 = new Vector2(10, 20);
const v2 = new Vector2(5, 5);
// Operations (all return new vectors, immutable)
const sum = v1.add(v2);
const diff = v1.subtract(v2);
const scaled = v1.scale(2);
const normalized = v1.getNormal();
const magnitude = v1.getMagnitude();
```
#### AABB
Axis-Aligned Bounding Box for spatial queries.
```typescript
import { AABB, Vector2 } from '2d-physics-engine';
const box = new AABB(
new Vector2(0, 0), // min corner
new Vector2(100, 100), // max corner
);
// Or use factory methods
const box2 = AABB.fromCenter(new Vector2(50, 50), new Vector2(25, 25));
```
## API Reference
### Core Classes
- `Entity` - Container for components
- `Scene` - Manages collections of entities
- `Iterator` - Main game loop and system manager
- `InputManager` - Handles keyboard and mouse input
### Components
- `Transform` - Position, rotation, scale
- `Rigidbody` - Physics properties
- `Collider` (abstract) - Collision shape base class
- `CircleCollider` - Circular collision shape
- `Controller` - WASD/Arrow key movement controller
- `Drawer` (abstract) - Rendering base class
- `CircleDrawer` - Renders circles
### Systems
- `Physics` - Handles physics simulation
- `Rendering` - Renders entities with drawer components
- `CollisionDetector` - Detects collisions between entities
- `CollisionResolver` - Resolves collisions
### Math
- `Vector2` - 2D vector class
- `AABB` - Axis-Aligned Bounding Box
- `QuadTree` - Spatial partitioning structure
## Examples
### Adding Forces
```typescript
const rigidbody = entity.getComponent(Rigidbody);
if (rigidbody) {
rigidbody.addForce(new Vector2(100, 0)); // Apply force to the right
}
```
### Custom Drawer
```typescript
import { Drawer, Transform } from '2d-physics-engine';
class MyDrawer extends Drawer {
draw(ctx: CanvasRenderingContext2D, transform: Transform): void {
// Your custom rendering code
}
}
```
### Custom Collider
```typescript
import { Collider, AABB, Transform } from '2d-physics-engine';
class BoxCollider extends Collider {
static readonly COLLIDER_ID = Symbol('BoxCollider');
readonly colliderId = BoxCollider.COLLIDER_ID;
constructor(
private width: number,
private height: number,
) {
super();
}
getAABB(transform: Transform): AABB {
// Return AABB based on transform
}
calculateInertia(mass: number): number {
// Calculate moment of inertia
}
}
```
## Development
```bash
# Install dependencies
npm install
# Run development server
npm run dev
# Build library
npm run build:lib
# Run tests
npm test
# Format code
npm run format
```
## License
MIT
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## Resources
- [Dot Product](https://www.mathsisfun.com/algebra/vectors-dot-product.html)
- [Cross Product](https://www.mathsisfun.com/algebra/vectors-cross-product.html)
- [2D Collisions](https://www.vobarian.com/collisions/2dcollisions2.pdf)
- [Coefficient of Restitution](https://en.wikipedia.org/wiki/Coefficient_of_restitution)