Spherical collision is actually very easy to do yourself: just use the distance formula. And yes, it works in 3D:
public static function distanceBetween(p1:Vector3D, p2:Vector3D):Float {
var x:Float = p2.x - p1.x;
var y:Float = p2.y - p1.y;
var z:Float = p2.z - p1.z;
return Math.sqrt(x * x + y * y + z * z);
}
Now imagine two spheres in a 3D environment. You know where each sphere is, and you know each sphere’s radius. This is enough information to tell whether the two spheres are overlapping:
public static function spheresColliding(p1:Vector3D, r1:Float, p2:Vector3D, r2:Float):Bool {
return distanceBetween(p1, p2) <= r1 + r2;
}
If their centers are close enough, they’re touching. Simple as that! Rotation doesn’t matter because rotating a sphere doesn’t change its collision. The direction from one to the other doesn’t matter because, again, they’re spheres.
Only their radii matter. Large spheres collide sooner, and small spheres collide later.
Aside: Math.sqrt()
is relatively slow. If you square both sides of the equation, you can skip it entirely:
public static function spheresColliding(p1:Vector3D, r1:Float, p2:Vector3D, r2:Float):Bool {
var x:Float = p2.x - p1.x;
var y:Float = p2.y - p1.y;
var z:Float = p2.z - p1.z;
var r:Float = r1 + r2;
return x * x + y * y + z * z <= r * r;
}
Again, your code will work either way. This is just for performance.
Ok, back to the main topic. It’s all well and good to tell whether two spheres are overlapping, but you asked about keeping one sphere inside another.
One solution is the one you suggested: !spheresColliding()
. But the thing about that is, your ball will pass 99% of the way through the wall, only stopping the moment before it gets completely outside.
So you’ll need to modify your function a bit. Instead of testing the ring sphere as-is, pretend that the ring is smaller, so that the ball will stop sooner. That is, you want to subtract the ball’s diameter from the ring sphere’s radius: !spheresColliding(p1, r1 - 2 * r2, p2, r2)
.
Basically, you’re drawing an invisible sphere that’s just a bit smaller than the ring. Your ball must always touch this invisible sphere (even if it’s only touching at a single point).