What is the userData property in planck.js?

The userData property in planck.js (a 2D JavaScript physics engine based on Box2D) serves as a custom data container that allows developers to attach arbitrary application-specific information to physics bodies and fixtures. Because the physics engine only manages mathematical properties like mass, velocity, and shapes, userData acts as the vital bridge linking the physics simulation back to your game’s logic, rendering engine, or state management. This article explores how userData works, common use cases, and best practices for leveraging it in your projects.

The Problem it Solves: Decoupling Physics from Logic

In a typical game or simulation, a physics body doesn’t inherently know what it represents in the game world. It simply tracks coordinates, angles, and forces. For instance, if a collision occurs, planck.js can tell you that Fixture A hit Fixture B, but it cannot natively tell you that “Player 1’s sword” hit “Enemy 3.” By utilizing userData, you can store references to your high-level game objects directly inside the physics objects, making state updates and collision handling seamless.

Common Use Cases

Body vs. Fixture userData

It is important to understand where to attach your data, as both Body and Fixture objects support the userData property:

Code Example: Implementing userData

Setting and retrieving this data is straightforward. You can assign any JavaScript data type—a string, an object, or an instance of a class—to the property.

// Creating a body and attaching an object to userData
const playerBody = world.createBody({
  type: 'dynamic',
  position: Vec2(0, 5),
  userData: {
    type: 'player',
    name: 'Hero',
    score: 0
  }
});

// Retrieving userData during a collision contact listener
world.on('begin-contact', (contact) => {
  const fixtureA = contact.getFixtureA();
  const bodyA = fixtureA.getBody();
  const dataA = bodyA.getUserData();

  if (dataA && dataA.type === 'player') {
    console.log(`${dataA.name} has collided with something!`);
  }
});

Best Practices