Wednesday, January 29, 2020

Collision response for 2D racing game


The title is fairly self-explanatory. I have a 2D racing game that utilizes per-pixel collision detection (the track is essentially two bitmaps, one for the graphics, one for collision data). The problem I'm running into is that I can't figure out how to implement the collision response. I can figure this out for situations where I have a box colliding with another box, but the fact that my objects can essentially be any shape has me stumped.


The one approach that I've had some success with is to just sample a couple of pixels near the pixels that collide, build vectors out of those and then take the cross product of that, but it fails in many scenarios. Plus, it just seems like overengineering. In fact, I'm about 103% sure that I'm just overthinking the whole problem.


Has anyone tackled this problem?




Answer



When you have a collision you should try to understand where the collision occurred, the involved forces, the consequences of the involved forces.


Simplest case (I can tink of):



  • The impact occurs in the frame the collision is detected (no compenetration)

  • The colliding objects are perfectly elastic (no energy loss due deformation)

  • The colliding object are disks (to be removed as soon as possible)


Under those circumstances there is conservation of total momentum and kinetic energy.


When a collision occours, there is a contact surface between the colliding bodies: they can exchange energy only through this surface; in other words the impact forces are always perpendicular to this surface.



The main conseguence to this is that you can decompone the kinetic energy vector in a radial component (perpendicular to the contact surface) and a tangential component (parallel to the contact surface) seeing that the tangential one stays the same.


Knowing the value for a component, we can consider the collision be monodimensional, restricted to the radial direction.


If we consider the second body to be still, we have some formulas for the velocity after the collision:


V1 after impact vs V1 before impact


V2 after impact vs V1 before impact


It is possible to compute the velocity after impact knowing the velocity before the impact for the radial coponent we needed. (the kinetic energy is ½·m·v²).


You can resolve the case where the second body is moving, by superimpose the collision effects (first-moving-second-still + first-still-second-moving) or by change the inertial reference to be linked to the second body before the impact; it is the same.




We can spice up the simulation by removing the geometric simplification.


First you need to compute the contact surface and to find the contat point. (I left the problem to you but you can consider to simplify the contat mode to colliding boxes)



With your contact surface you can compute the resulting kinetic energy vector - as explained before - but then? We have to "allocate" this energy because a rigid body can move and rotate and some energy is required to change linear or angular velocity.


To know around what point our body will rotate, we need to know the position for the center of mass: this can be precomputed since depends just by the object shape and mass distribution.


If you have a collision bitmap you can consider to sum up the position for each "on" pixel then divide for how many "on" pixel there are: this implies that the object has the same density in each point.


If you like you can use a graymap to store the density for each point: black for 0 density (body absence) and white for maximum density; by multiplying the position by the density, you can compute a weighted average: your center of mass


When you know the center of mass you need to know the moment of inertia: multiply the density of each point by the square of the distance from the center of mass and sum up.


Knowing the center of mass and the collision point, you can decompose the kinetic energy vector in a radial component (starting from collision point and pointing toward the center of mass) and a tangential component.


The radial component tells us how many impact enercy becomes kinetic energy, while the tangential component tells us how many impact enercy becomes rotational energy.


As well as the velocity is bounded to the kinetic energy so Et = ½mV², also the angular velocity is bounded to the rotational energy so Er = ½Iω², where I is the moment of inertia and ω the rotational velocity in radians per second.


Using those two formulas you can compute the velocity vector and the angular velocity to add to your body.


The last triky part is how to know if ω has to be clock/counterclok wise, since you will ever get a positive value.



Let I be the impact point and M the center of mass point, compute d = C - I;


Let Er be the tangential component for the impact kinetic energy, compute cross product in 2D, this will give you a right-handed perpendicular vector.


Now compute d·E if positive the rotation is CW else CCW


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...