schteppe / cannon.js

A lightweight 3D physics engine written in JavaScript.
http://schteppe.github.com/cannon.js
MIT License
4.72k stars 711 forks source link

Collision with fast bodies. #202

Open fjguerrero opened 9 years ago

fjguerrero commented 9 years ago

Hello!

I'm developing a free kick game, where the player has to shoot a ball and smash a target.

I have a problem with the collisions when the ball is too fast. I uploaded this video showing the problem. You can see, for example in the last shot [1:28], how the ball cross the wall, the target and the net without problems. https://www.youtube.com/watch?v=qd8A39i_YbQ

I know that this is a common problem in physics engines, but I'm trying to find the best possible configuration to make the game more playable, because a force of 20 is not too much. And here are my questions:

Thank you very much for creating and supporting this library! :smile: :+1:

ghost commented 8 years ago

@fjguerrero in cannon.js, there is no real support (from what I've seen in the source code) for Continous Collision Detection, or CCD. As you might already know, it basically prevents these kinds of situations from happening, where an object is moving too fast and "tunnels" through objects between simulation steps. Since the physics engine does not support it just yet, the only other way of minimizing the tunneling effects without too much hassle would be to increase the .maxSubSteps property of your world, but that leads to slower simulations (which I'm sure you don't want).

An alternative would be to implement CCD yourself. Fortunatly, since this is only 1 fast-moving ball, the code requirements are very small. All you need is a little raycasting knowledge:

var raycaster = new THREE.Raycaster();

// Must predict next position and check if the ray trajectory if it intersects anything!
function limitSphere(ball, objs){
  var arr;
  raycaster.set(ball.position.clone(), ball.velocity.clone().unit());
  raycaster.far = ball.velocity.length();
  arr = raycaster.intersectObjects(objs);

  if(arr.length){
    ball.position.copy(arr[0].point);
  }
}

This function will only work properly if the velocity already has a direction (it should not be [0,0,0]).