Collision response - intersection via Box3.intersectsBox

I have one BoxGeom mesh that moves, another that is static.

When they intersect/collide, I need the moving box to move back such that it no longer intersects.

I’ve done similar things before where I:

  • test for collision, if so
  • get collision normal and intersection depth
  • move the colliding object back along collision normal by intersection depth
  • now it no longer intersects

Another common approach for this is to:

  • move the object
  • if it intersects,
  • move it back to where it was (so it never moves)
    But that falls down when the object moves far in one step (for fast moving objects).

Box3.intersectsBox is a cheap way of testing the collision/intersection and is accurate enough for my needs, however it doesn’t tell me the collision normal or intersection depth.

How might I get that information to resolve the collsion? Or is there a neater/cheaper way to approach this?

I’m essentially trying to implement simple physics - I don’t want to use a lib for this. My cube that moves is a character that should jump, adhere to gravity in falling off ledges and returning to the ground after jumping.

Here’s my test cube class, which falls with gravity and jumps while still in the air but is no longer able to jump when it hits the ground because it doesn’t move out of the intersection range.

export class TestCube {
  public cube: THREE.Mesh;
  public dy = 0;
  public gravity = 0.1;
  public onGround = false;

  constructor(private keyboardListener: KeyboardListener) {
    // Make cube
    const geom = new THREE.BoxGeometry(1, 1, 1);
    const mat = new THREE.MeshBasicMaterial({ color: 'red' });
    this.cube = new THREE.Mesh(geom, mat);

    // Controls
    keyboardListener.on('keyj', this.jump);
  }

  public moveTo(pos: THREE.Vector3) {
    this.cube.position.set(pos.x, pos.y, pos.z);
  }

  public update(deltaTime: number, props: Prop[]) {
    // Apply gravity
    this.dy -= this.gravity;

    // Test for collisions with props
    this.onGround = false;
    for (const prop of props) {
      // Test intersection with ground
      const propBox = new THREE.Box3().setFromObject(prop.model);
      const cubeBox = new THREE.Box3().setFromObject(this.cube);
      if (cubeBox.intersectsBox(propBox)) {
        console.log('intersects ground');
        // Move out of intersection range
        // -----> How?
        // Clear y movement
        this.dy = 0;
        // On ground
        this.onGround = true;
      }
    }

    // Move
    this.cube.position.y += this.dy * deltaTime;
  }

  private jump = () => {
    this.dy = 5;
  };
}

Any pointers much appreciated, thanks!

Update, I’m now doing this, and it works - but only because I know that in this case i’m testing the bottom of the cube with the top of the floor. What about hitting the cube’s head against lower bounds of some other box?

  public update(deltaTime: number, props: Prop[]) {
    // Apply gravity
    this.dy -= this.gravity;

    // Save current position
    const lastPos = this.cube.position.clone();

    // Move to new positionw
    this.cube.position.y += this.dy * deltaTime;


    // Test for intersections
    for (const prop of props) {
      const propBox = new THREE.Box3().setFromObject(prop.model);
      const cubeBox = new THREE.Box3().setFromObject(this.cube);
      if (cubeBox.intersectsBox(propBox)) {
        // Intersects with prop; move backwards. Get reverse of travelled direction
        const backwards = lastPos.sub(this.cube.position).normalize(); 
        // Get amount intersected
        const intersectDepth = propBox.max.y - cubeBox.min.y;
        // Move backwards by depth
        const moveStep = backwards.multiplyScalar(intersectDepth);
        this.cube.position.add(moveStep);
        this.dy = 0;
        break;
      }
    }
  }