How to Create a Ground Pound in Matter.js

This guide explains how to implement a fast, responsive ground pound mechanic in a Matter.js 2D physics environment. You will learn how to trigger the action mid-air, override default gravity with high downward velocity or force, restrict horizontal drift, and detect the ground impact to reset the player's state.

1. Track Player States

To prevent infinite ground pounds and ensure proper input handling, maintain a simple state object for the player body:

const playerState = {
  isGrounded: false,
  isGroundPounding: false
};

Update isGrounded by listening to collision events between your player sensor/body and the terrain.

2. Trigger the Downward Drive

When the player triggers the ground pound input while mid-air, cancel any existing horizontal velocity and immediately direct the body downward. While you can use Matter.Body.applyForce(), directly manipulating velocity via Matter.Body.setVelocity() often yields a more snappy, predictable arcade feel:

function executeGroundPound(playerBody) {
  if (playerState.isGrounded || playerState.isGroundPounding) return;

  playerState.isGroundPounding = true;

  // Kill horizontal momentum and set a strong downward velocity
  Matter.Body.setVelocity(playerBody, {
    x: 0,
    y: 25 // Adjust based on the scale of your physics world
  });
}

3. Maintain Downward Momentum in the Game Loop

Matter.js applies air friction and standard gravity every tick. To ensure the character drives downward rapidly without slowing down or drifting sideways before landing, enforce constraints inside an Engine or Render update hook:

Matter.Events.on(engine, 'beforeUpdate', () => {
  if (playerState.isGroundPounding) {
    // Lock horizontal movement and maintain high terminal velocity
    Matter.Body.setVelocity(player, {
      x: 0,
      y: Math.max(player.velocity.y, 25)
    });

    // Optional: Alternatively apply continuous downward force
    // Matter.Body.applyForce(player, player.position, { x: 0, y: 0.05 });
  }
});

4. Detect Ground Impact and Reset State

Listen for the collisionStart event to detect when the pound finishes. Reset the player's state and trigger any gameplay feedback, such as camera shake or area-of-effect forces:

Matter.Events.on(engine, 'collisionStart', (event) => {
  const pairs = event.pairs;

  for (let i = 0; i < pairs.length; i++) {
    const { bodyA, bodyB } = pairs[i];

    // Check if the player collided with a ground-tagged object
    const isPlayerInvolved = bodyA === player || bodyB === player;
    const isFloorInvolved = bodyA.label === 'ground' || bodyB.label === 'ground';

    if (isPlayerInvolved && isFloorInvolved) {
      playerState.isGrounded = true;

      if (playerState.isGroundPounding) {
        playerState.isGroundPounding = false;
        onGroundPoundLand(player.position);
      }
    }
  }
});

function onGroundPoundLand(position) {
  // Add impact mechanics here (e.g., spawn shockwaves, damage enemies)
  console.log('Ground pound landed at:', position);
}