Control Wheels in Matter.js Car Composite

Controlling the wheels of a vehicle generated by Matter.Composites.car involves accessing the individual wheel bodies from the composite and applying forces, torque, or angular velocity to them during the engine's update cycle. This guide covers how to locate the wheel instances inside the composite, apply rotational movement for acceleration and braking, and hook these controls into user inputs.

Accessing the Wheel Bodies

When you create a vehicle using Matter.Composites.car(xx, yy, width, height, wheelSize), Matter.js returns a Composite object containing bodies and constraints. By default, the composite contains three bodies in its bodies array:

You can extract and assign references to these wheels immediately after creation:

const car = Matter.Composites.car(150, 100, 150, 30, 30);
Matter.Composite.add(world, car);

const wheelA = car.bodies[1];
const wheelB = car.bodies[2];

Methods for Controlling the Wheels

There are two primary ways to make the wheels rotate: modifying angular velocity directly or applying torque.

1. Setting Angular Velocity (Direct Speed Control)

Setting the angular velocity is the simplest method and provides immediate, arcade-like responsiveness. It overrides current rotation speed directly.

// Rotate forward (clockwise)
Matter.Body.setAngularVelocity(wheelA, 0.15);
Matter.Body.setAngularVelocity(wheelB, 0.15);

// Rotate backward (counter-clockwise)
Matter.Body.setAngularVelocity(wheelA, -0.15);
Matter.Body.setAngularVelocity(wheelB, -0.15);

2. Applying Torque (Physics-Based Acceleration)

Applying torque simulates a realistic motor by applying rotational force over time, which allows for gradual acceleration and natural tire spin:

// Apply torque inside your update loop
wheelA.torque = 0.05;
wheelB.torque = 0.05;

Complete Implementation with User Input

To implement smooth and responsive vehicle controls, track key states and apply forces within the beforeUpdate event of the Matter.js engine.

const { Engine, Render, Runner, Composite, Composites, Events, Body } = Matter;

const engine = Engine.create();
const world = engine.world;

// Create the car
const car = Composites.car(200, 100, 120, 25, 25);
Composite.add(world, car);

const wheelA = car.bodies[1];
const wheelB = car.bodies[2];

// Track keyboard inputs
const keys = {
  ArrowRight: false,
  ArrowLeft: false
};

window.addEventListener('keydown', (e) => {
  if (keys.hasOwnProperty(e.key)) keys[e.key] = true;
});

window.addEventListener('keyup', (e) => {
  if (keys.hasOwnProperty(e.key)) keys[e.key] = false;
});

// Update wheel forces before each physics step
Events.on(engine, 'beforeUpdate', () => {
  const motorSpeed = 0.15;

  if (keys.ArrowRight) {
    // Drive Forward
    Body.setAngularVelocity(wheelA, motorSpeed);
    Body.setAngularVelocity(wheelB, motorSpeed);
  } else if (keys.ArrowLeft) {
    // Drive Reverse
    Body.setAngularVelocity(wheelA, -motorSpeed);
    Body.setAngularVelocity(wheelB, -motorSpeed);
  }
});

Tuning Wheel Friction and Handling

If the wheels spin without propelling the vehicle forward, increase the friction property on both the wheels and the driving surfaces:

wheelA.friction = 0.9;
wheelB.friction = 0.9;

For high-traction scenarios, also consider setting frictionStatic to a higher value (such as 1.0 or higher) to avoid slipping during initial acceleration.