2d-physics-engine
v1.4.2
Published
A lightweight, flexible 2D physics engine with ECS architecture, built with TypeScript
Maintainers
Readme
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
npm install 2d-physics-engine
# or
yarn add 2d-physics-engine
# or
pnpm add 2d-physics-engineQuick Start
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.
const transform = new Transform(
new Vector2(100, 100), // position
0, // rotation (radians)
new Vector2(1, 1), // scale
);Rigidbody
Adds physics properties to an entity.
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.
const collider = new CircleCollider(25); // radiusMath Utilities
Vector2
2D vector operations for position, velocity, forces, etc.
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.
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 componentsScene- Manages collections of entitiesIterator- Main game loop and system managerInputManager- Handles keyboard and mouse input
Components
Transform- Position, rotation, scaleRigidbody- Physics propertiesCollider(abstract) - Collision shape base classCircleCollider- Circular collision shapeController- WASD/Arrow key movement controllerDrawer(abstract) - Rendering base classCircleDrawer- Renders circles
Systems
Physics- Handles physics simulationRendering- Renders entities with drawer componentsCollisionDetector- Detects collisions between entitiesCollisionResolver- Resolves collisions
Math
Vector2- 2D vector classAABB- Axis-Aligned Bounding BoxQuadTree- Spatial partitioning structure
Examples
Adding Forces
const rigidbody = entity.getComponent(Rigidbody);
if (rigidbody) {
rigidbody.addForce(new Vector2(100, 0)); // Apply force to the right
}Custom Drawer
import { Drawer, Transform } from '2d-physics-engine';
class MyDrawer extends Drawer {
draw(ctx: CanvasRenderingContext2D, transform: Transform): void {
// Your custom rendering code
}
}Custom Collider
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
# Install dependencies
npm install
# Run development server
npm run dev
# Build library
npm run build:lib
# Run tests
npm test
# Format code
npm run formatLicense
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
