/** * PhysicsWorld - singleton that manages Matter.js engine * * Why singleton: * - Only one physics simulation per game * - Global gravity, timestep settings * - Central collision event dispatcher * * Common use case: platformer needs gravity, space game doesn't */ export class PhysicsWorld { constructor(options?: {}); engine: any; world: any; gravity: any; timeScale: number; fixedDelta: any; accumulator: number; maxSubSteps: any; bodies: Map; /** * Setup Matter.js collision callbacks * * Matter fires events: collisionStart, collisionActive, collisionEnd * We translate these to our node callbacks */ setupCollisionEvents(): void; /** * Step physics with fixed timestep * * Why fixed timestep: * - Game runs at variable FPS (30-144fps) * - Physics needs consistent delta (16.66ms for 60fps) * - Accumulate real delta, consume in fixed chunks * * Example: Frame takes 33ms (30fps) * - accumulator += 0.033 * - Step 1: 0.033 - 0.0166 = 0.0166 remaining * - Step 2: 0.0166 - 0.0166 = 0 remaining * - Result: physics stepped twice, stays stable */ step(delta: any): void; /** * Add body to world */ addBody(matterBody: any, rigidBodyNode: any): void; /** * Remove body from world */ removeBody(matterBody: any): void; /** * Query physics world (useful for raycasts, area queries) */ queryPoint(x: any, y: any): any; queryRegion(bounds: any): any; } /** * RigidBody2D - node that syncs with Matter.js body * * Body types: * - dynamic: Physics controls it (gravity, forces apply) * - kinematic: You control it, physics detects collisions * - static: Never moves (walls, floors) * * Authority rules: * - Dynamic: Physics -> Scene graph (read Matter position) * - Kinematic: Scene graph -> Physics (write to Matter position) * - Static: Set once, never sync */ export class RigidBody2D extends Node { /** * Creates an instance of the physics object. * * @param {string} name - The name of the physics object. * @param {Object} [options={}] - The options for the physics object. * @param {string} [options.type='dynamic'] - The type of the physics object (dynamic, kinematic, static). * @param {number} [options.mass=1.0] - The mass of the physics object. * @param {number} [options.friction=0.1] - The friction coefficient of the physics object. * @param {number} [options.restitution=0.0] - The bounciness of the physics object. * @param {number} [options.linearDamping=0.01] - The linear damping (air resistance) of the physics object. * @param {number} [options.angularDamping=0.01] - The angular damping of the physics object. * @param {number} [options.collisionLayer=0x0001] - The collision layer of the physics object. * @param {number} [options.collisionMask=0xFFFF] - The collision mask of the physics object, which determines what it can collide with. */ constructor(name: string, options?: { type?: string; mass?: number; friction?: number; restitution?: number; linearDamping?: number; angularDamping?: number; collisionLayer?: number; collisionMask?: number; }); type: string; mass: number; friction: number; restitution: number; linearDamping: number; angularDamping: number; pivot: any; sprite: any; body: any; onCollisionEnter: any; onCollisionStay: any; onCollisionExit: any; collisionLayer: number; collisionMask: number; anchorOffset: { x: number; y: any; } | { x: any; y: number; }; /** * Add collision box with automatic anchor matching pivot * * Common use: player.addCollisionBox(24, 40) * → Creates box anchored at body's pivot point * * @param {number} width - Box width * @param {number} height - Box height * @param {Object} options - Additional options (friction, etc.) */ addCollisionBox(width: number, height: number, options?: any): CollisionShape2D; /** * Add collision circle with automatic anchor matching pivot */ addCollisionCircle(radius: any, options?: {}): CollisionShape2D; /** * Set sprite and auto-configure offset to match pivot * * This is the magic: sprite offset calculated from pivot + sprite size * * @param {Sprite} sprite - Sprite instance to attach */ setSprite(sprite: Sprite): void; /** * Calculate sprite offset from pivot point * * The sprite's offset determines where its top-left corner * is drawn relative to the parent position. * * Example: pivot = 'bottom-center', sprite = 16x40 * - We want sprite bottom-center at parent position * - Sprite draws from top-left * - So offset = (-8, -40) to shift it into place */ updateSpriteOffset(): void; /** * Get offset from pivot point to top-left corner * * This converts our pivot-based system to sprite's top-left based system * * @param {number} width - Sprite/shape width * @param {number} height - Sprite/shape height * @returns {{x: number, y: number}} - Offset to top-left */ getPivotToTopLeftOffset(width: number, height: number): { x: number; y: number; }; /** * Create Matter.js body from collision shapes * * This is called when first CollisionShape2D child is added */ createBody(): void; /** * Apply force (for dynamic bodies) */ applyForce(forceX: any, forceY: any, worldX?: any, worldY?: any): void; /** * Set velocity directly (impulse) */ setVelocity(vx: any, vy: any): void; getVelocity(): { x: any; y: any; }; /** * Cleanup when removed from scene */ destroy(): void; } /** * CollisionShape2D - defines physical shape for RigidBody2D * * Why separate from RigidBody2D: * - One body can have multiple shapes (compound collision) * - Shapes can be offset from body center * - Easier to visualize/debug * * Shape types: box, circle, polygon */ export class CollisionShape2D extends Node { constructor(shapeType: any, options?: {}); shapeType: any; options: {}; anchor: any; anchorOffset: { x: number; y: any; } | { x: any; y: number; }; /** * Calculate offset from anchor point to geometric center * * This tells Matter.js where to position the body center * so the anchor point ends up at the parent position */ calculateAnchorOffset(): { x: number; y: any; } | { x: any; y: number; }; /** * Get anchor offset for box shapes * * @param {number} width - Box width * @param {number} height - Box height * @returns {{x: number, y: number}} - Offset from anchor to center */ getBoxAnchorOffset(width: number, height: number): { x: number; y: number; }; /** * Get anchor offset for circle shapes * * Circles support: center, top, bottom, left, right * (diagonal anchors don't make much sense for circles) */ getCircleAnchorOffset(radius: any): { x: number; y: any; } | { x: any; y: number; }; /** * Create Matter.js body with anchor offset applied * * Key change: Add anchorOffset to position so Matter's center * ends up correctly relative to parent's anchor point */ createMatterBody(): any; } /** * Utility: Create common physics bodies quickly */ export class PhysicsFactory { /** * Create box body with anchor support * * @param {string} name - Body name * @param {number} x - X position (at anchor point) * @param {number} y - Y position (at anchor point) * @param {number} width - Box width * @param {number} height - Box height * @param {string} type - 'dynamic', 'kinematic', 'static' * @param {string} anchor - Anchor point (default: 'center') */ static createBox(name: string, x: number, y: number, width: number, height: number, type?: string, anchor?: string): RigidBody2D; /** * Create circle body with anchor support */ static createCircle(name: any, x: any, y: any, radius: any, type?: string, anchor?: string): RigidBody2D; /** * Create static ground with bottom-center anchor * * Common use: Tilemap collision bodies * The (x, y) you pass is the top-center of the ground surface */ static createGround(name: any, x: any, y: any, width: any, height: any): RigidBody2D; /** * Create platformer character body * * Common pattern: Collision box bottom-center at feet position * * @param {string} name - Character name * @param {number} x - X position (feet X) * @param {number} y - Y position (feet Y - ground level) * @param {number} width - Collision width * @param {number} height - Collision height */ static createPlatformerCharacter(name: string, x: number, y: number, width: number, height: number): RigidBody2D; } import { Node } from './core.js';