Phaser Box2D

repository·main·Indexed 41 days ago

https://github.com/phaserjs/phaser-box2d

A high-performance 2D physics engine based on Box2D v3, designed to work as a standalone library on client or server with seamless integration helpers for the Phaser game framework. It provides a direct JavaScript conversion of original C functions, utilizing MKS (meters-kilograms-seconds) units. Version 1.1.0 includes high-level wrappers for creating worlds, bodies, and shapes, as well as debug drawing tools for both vanilla HTML5 Canvas and Phaser Graphics objects.

Tokens
23.4K
Snippets
80
Records
89
Agent score
50%

What's inside Phaser Box2D

  1. Understand the Box2D JavaScript conversion

    main

    This library is a direct JavaScript conversion of the original C functions. While most documentation from box2d.org applies, the primary difference is that C typedef structs (like b2Vec2) are implemented as JavaScript classes. You must instantiate these using the new keyword.

    Example: Instead of C-style initialization: bodyDef.position = (b2Vec2){0.0f, 4.0f};

    You must use: bodyDef.position = new b2Vec2(0.0, 4.0);

  2. Managing Sprite and Body movement

    main

    When using the Sprite-to-Body pairing, follow these movement principles:

    • Move via the Body: To move an object, apply forces or impulses to the Box2D Body. Do not move the Sprite directly, as UpdateWorldSprites will overwrite the sprite's position with the body's position.
    • Unlocking the pairing: If you need to move a Sprite independently (e.g., via a Phaser Tween), use RemoveSpriteFromWorld to break the link. Note that the Box2D body will continue to simulate and remain active in the world even if the sprite is unlinked. You can re-link them later using AddSpriteToWorld.
  3. Create bodies and shapes

    main

    Bodies are the simulated objects within a world. They require shapes (polygons, circles, etc.) to define their physical properties like density and friction.

    Workflow:

    1. Create a bodyDef using b2DefaultBodyDef().
    2. Create the body using b2CreateBody(worldId, bodyDef).
    3. Create a shape definition using b2DefaultShapeDef().
    4. Create the specific shape (e.g., via b2MakeBox) and attach it to the body using b2CreatePolygonShape().
    // create a definition for a body using the default values
    let bodyDef = b2DefaultBodyDef();
    bodyDef.type = b2BodyType.b2_dynamicBody;
    bodyDef.position = new b2Vec2(0, 4);
    
    // create the body
    let bodyId = b2CreateBody(worldId, bodyDef);
    
    // create a definition for a shape using the default values
    let shapeDef = b2DefaultShapeDef();
    shapeDef.density = 1.0;
    shapeDef.friction = 0.3;
    
    // create a polygon shape using a helper function (parameters are half-width and half-height)
    let box = b2MakeBox(1.0, 1.0);
    
    // attach the polygon to the body
    b2CreatePolygonShape(bodyId, shapeDef, box);
  4. Run the Phaser Box2D API Docs

    main

    To view the local API documentation server, follow these steps:

    1. Run npm install in the root directory.
    2. Run npm run docs to launch the documentation server.
    3. Open your browser to the provided URL (typically http://localhost:8000).
    npm install
    npm run docs
  5. Use the Phaser Box2D Vite Template

    main

    The repository includes a Vite template for quickly setting up a project with Vite, Phaser, and Phaser Box2D. Follow these steps to use it:

    1. Copy PhaserBox2D.js, PhaserBox2D-Debug.js, and PhaserBox2D-Debug.js.map into the vite-template/src folder.
    2. Navigate to the vite-template folder and run npm install to install Vite and Phaser.
    3. Use the following commands to manage your project:
      • npm run dev: Runs Vite in dev/watcher mode and opens your browser.
      • npm run build: Creates a production build in the dist folder.
      • npm run preview: Tests the dist build locally.

    Switching to Debug Mode: By default, the template uses the Release version (PhaserBox2D.js). To use the Debug Draw renderer, edit the import statement in src/main.js to import PhaserBox2D-Debug.js instead. Remember to revert this before your production build.

    # Inside the vite-template folder
    npm install
    npm run dev
  6. Learn how to use Phaser Box2D

    main

    To master Phaser Box2D, utilize the following four resources:

    1. Examples: A wide range of code samples provided in the repository. They demonstrate both direct Box2D usage and usage via Phaser helper functions. Refer to the repository README to run these.
    2. API Documentation: Custom documentation for all core Box2D functions (prefixed with b2). Use this to cross-reference parameters and classes while looking at examples.
    3. Official Box2D Documentation: The official site is highly recommended. Crucial: Pay close attention to the Core Concepts and Units sections. Physics engines operate in meters and kilograms; failing to account for this will result in impractical simulations.
    4. Box2D Tutorials: A comprehensive list of tutorials hosted on the Phaser website covering everything from basic bodies and world settings to advanced topics like buoyancy and explosions.
  7. Step and Render the Box2D World

    main

    To progress the simulation and visualize it, you must perform two steps in your update loop:

    1. Step the simulation: Call WorldStep({ worldId, deltaTime }) to advance the physics. deltaTime is the time elapsed since the last frame (typically 1/60).
    2. Draw the world: Call b2World_Draw(worldId, renderer) to render the bodies and joints using a debug renderer.

    For a vanilla JS implementation, you can use CreateDebugDraw(canvas, ctx, scale) to create a renderer and RAF(update) to manage the animation loop.

    // Inside an update loop
    function update (deltaTime)
    {
        WorldStep({ worldId: world.worldId, deltaTime: deltaTime });
    
        ctx.clearRect(0, 0, canvas.width, canvas.height);
    
        b2World_Draw(world.worldId, m_draw);
    }
  8. Setup Debug Drawing with Canvas

    main

    To visualize the physics simulation, use the provided debug drawing system. This requires a HTML <canvas> element and a 2D context.

    // 1. Set the scale for drawing
    const m_drawScale = 7.0;
    
    // 2. Get canvas and context
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');
    
    // 3. Create the debug drawing system
    const m_draw = CreateDebugDraw(canvas, ctx, m_drawScale);
    
    // 4. Inside your animation loop, clear and redraw
    function update() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        b2World_Draw(worldId, m_draw);
    }
  9. Download and choose a Phaser Box2D build

    main

    Phaser Box2D is available in the dist folder of the GitHub repository. You should choose between the Debug and Release builds based on your current development stage:

    Debug Build

    Files: PhaserBox2D-Debug.js and PhaserBox2D-Debug.js.map

    • Use for: Development and troubleshooting physics issues.
    • Features: Includes console.asset statements and a built-in Canvas debug renderer.
    • Warning: Do not use this for production. The assertion statements significantly impact performance.

    Release Build

    Files: PhaserBox2D.js and PhaserBox2D.min.js

    • Use for: Production games.
    • Features: All assertions, debug calls, and the debug renderer have been stripped to optimize performance and file size.
    • Note: You can use this during development, but you may need to swap to the Debug version if you need to trace physics-related issues.
  10. Use high-level wrappers for object creation

    main

    The library provides wrapper functions in physics.js to simplify the multi-step creation process of worlds, bodies, and shapes into single calls using configuration objects.

    import { CreateWorld, CreateBoxPolygon } from 'physics.js';
    
    let world = CreateWorld({ worldDef: b2DefaultWorldDef() });
    
    let box = CreateBoxPolygon({
        worldId: world.worldId,
        bodyDef: b2DefaultBodyDef(),
        type: b2BodyType.b2_dynamicBody,
        position: new b2Vec2(0, 4),
        size: 1,
        density: 1.0,
        friction: 0.3
    });
  11. Integrate Phaser Box2D with Phaser

    main

    When using Phaser, you can leverage helper functions to bridge the gap between Phaser's pixel-based coordinate system and Box2D's meter-based system.

    Workflow:

    1. Set World Scale: Use SetWorldScale(pixelsPerMeter) to define the conversion ratio.
    2. Pixel-to-Meter Conversion: Use pxmVec2(x, y) to convert pixel coordinates into b2Vec2 objects required by Box2D.
    3. Rotation Helpers: Use RotFromRad(radians) to create rotation objects easily.
    4. Phaser Debug Draw: Use new PhaserDebugDraw(graphicsObject, width, height, scale) to render the physics world onto a Phaser Graphics object.

    Example Integration:

    // In Phaser Scene create()
    SetWorldScale(40);
    const debug = this.add.graphics();
    const world = CreateWorld({ worldDef: b2DefaultWorldDef() });
    const worldId = world.worldId;
    
    // Create a body using pixel coordinates
    CreateBoxPolygon({
        worldId,
        type: DYNAMIC,
        position: pxmVec2(630, 64),
        size: 1,
        density: 1.0,
        friction: 0.2,
        color: b2HexColor.b2_colorGold
    });
    
    this.worldDraw = new PhaserDebugDraw(debug, 1280, 720, GetWorldScale());
    
    // In Phaser Scene update()
    update (time, delta)
    {
        WorldStep({ worldId, deltaTime: delta });
        this.debug.clear();
        b2World_Draw(worldId, this.worldDraw);
    }