Simple Physics Library written in Haxe

collisions, physics, 2d-physics-engine, gamedev, haxe, haxelib
haxelib install echo 2.1.0



A 2D Physics library written in Haxe.

Build Status

Echo focuses on maintaining a simple API that is easy to integrate into any engine/framework (Heaps, OpenFL, Kha, etc). All Echo needs is an update loop and its ready to go!

Try the Samples 🎮!

Check out the API 📖!


  • Semi-implicit euler integration physics
  • SAT-powered collision detection
  • Quadtree for broadphase collision querying
  • Collision listeners to provide collision callbacks
  • Physics State History Management with Built-in Undo/Redo functionality
  • Extendable debug drawing

Getting Started

Echo requires Haxe 4 to run.

Install the library from haxelib:

haxelib install echo

Alternatively the dev version of the library can be installed from github:

haxelib git echo

Then include the library in your project's .hxml:

-lib echo

For OpenFL users, add this into your Project.xml:

<haxelib name="echo" />

For Kha users (who don't use haxelib), clone echo and hxmath to Libraries folder in your project root, and then add the following to your khafile.js:





The Echo Class holds helpful utility methods to help streamline the creation and management of Physics Simulations.


A World is an Object representing the state of a Physics simulation and it configurations.


A Body is an Object representing a Physical Body in a World. A Body has a position, velocity, mass, optional collider shapes, and many other properties that are used in a World simulation.


A Body's collider is represented by different Shapes. Without a Shape to define it's form, a Body can be thought of a just a point in the World that cant collide with anything.

Available Shapes:

  • Rectangle
  • Circle
  • Polygon (Convex Only)

When a Shape is added to a Body, it's transform (x, y, rotation) becomes relative to its parent Body. In this case, a Shape's local transform can still be accessed through shape.local_x, shape.local_y, and shape.local_rotation.

It's important to note that all Shapes (including Rectangles) have their origins centered.


Use Lines to perform Linecasts against other Lines, Bodies, and Shapes.


Listeners keep track of collisions between Bodies - enacting callbacks and physics responses depending on their configurations. Once you add a Listener to a World, it will automatically update itself as the World is stepped forward.


Echo has a couple of ways to help integrate itself into codebases through the Body class.

First, the Body class has two public fields named on_move and on_rotate. If these are set on a body, they'll be called any time the body moves or rotates:

var body = new echo.Body();
body.on_move = (x,y) -> entity.position.set(x,y);
body.on_rotate = (rotation) -> entity.rotation = rotation;

Second, a build macro is available to add custom fields to the Body class, such as an Entity class:

in build.hxml:

--macro echo.Macros.add_data("entity", "some.package.Entity")

in Main.hx

var body = new echo.Body();
body.entity = new some.package.Entity();


Engine/Framework Examples

For an example of integrating echo with the Heaps engine, check out this sample.

Basic Example

import echo.Echo;

class Main {
  static function main() {
    // Create a World to hold all the Physics Bodies
    // Worlds, Bodies, and Listeners are all created with optional configuration objects.
    // This makes it easy to construct object configurations, reuse them, and even easily load them from JSON!
    var world = Echo.start({
      width: 64, // Affects the bounds for collision checks.
      height: 64, // Affects the bounds for collision checks.
      gravity_y: 20, // Force of Gravity on the Y axis. Also available for the X axis.
      iterations: 2 // Sets the number of Physics iterations that will occur each time the World steps.

    // Create a Body with a Circle Collider and add it to the World
    var a = world.make({
      elasticity: 0.2,
      shape: {
        type: CIRCLE,
        radius: 16,

    // Create a Body with a Rectangle collider and add it to the World
    // This Body will have a Mass of zero, rendering it as unmovable
    // This is useful for things like platforms or walls.
    var b = world.make({
      mass: 0, // Setting this to zero makes the body unmovable by forces and collisions
      y: 48, // Set the object's Y position below the Circle, so that gravity makes them collide
      elasticity: 0.2,
      shape: {
        type: RECT,
        width: 10,
        height: 10

    // Create a listener and attach it to the World.
    // This listener will react to collisions between Body "a" and Body "b", based on the configuration options passed in
    world.listen(a, b, {
      separate: true, // Setting this to true will cause the Bodies to separate on Collision. This defaults to true
      enter: (a, b, c) -> trace("Collision Entered"), // This callback is called on the first frame that a collision starts
      stay: (a, b, c) -> trace("Collision Stayed"), // This callback is called on frames when the two Bodies are continuing to collide
      exit: (a, b) -> trace("Collision Exited"), // This callback is called when a collision between the two Bodies ends

    // Set up a Timer to act as an update loop (at 60fps)
    new haxe.Timer(16).run = () -> {
      // Step the World's Physics Simulation forward (at 60fps)
      world.step(16 / 1000);
      // Log the World State in the Console



  • Linecast updates
    • Endless length Line support
    • Allow querying World's Quadtree when Linecasting
  • Allow parenting of Body transforms


  • Allow Concave Polygons (through Convex Decomposition)
  • Sleeping Body optimations
  • Constraints
  • Compiler Flag to turn off a majority of inlined functions (worse performance, but MUCH smaller filesize)