Your bouncing is caused by calculus imprecision, mixed with the time integration component.
This kind of things happen with involvement of these components:
- contacts detection
- response impulses
- integration
Point 1 we don't know who does it in your code. I guess some framework feature, the result of the contact information is given to you in the intersection
object so it seems. The Height
component has an imprecision you need to aknowledge, and therefore you can't trust it to be a good corrector.
Point 2, you do it on this line enemy.YLocation -= intersection.Height;
this is an exact simplified impulse. You correct the position without going through a force integration step (impulse method) but it is the same thing.
This point too is imperfect, and you can't perfect it, don't strive for it, collision handling in games is not an exact science. But you can make it fault tolerant by introducing softness a bit everywhere. In the form of deltas, epsilons, gradients, spring forces, multi-iteration penetration solving, fixed step simulation, auto freeze, etc etc... lots of little bits of technique there and there that makes your whole collision handling smooth.
Your "gravity" integration yLocation += 3
, I guess "freefall" simulation, is also sensitive to the fact that you need to rely on a NoFloor()
method that is probably too strict (too correct numerically) which is yet another factor in your bouncing problem.
The final point is the integration, in the code snippets you give us, there is notion of delta time watsoever. You skip framerate issues, or physics simulation rate issues altogether. Maybe this is for snippet purity sake on stackexchange, maybe not. Anyway it matters, and introducing it will have you think about precision even more. Because here it almost seems like you're doing integer calculus, but I think the vector you manipulate must come from xna and therefore be floats ? double
precision usually is not needed in absolute, BUT can help in these kind of domains, to increase smoothness.
Determinism, also helps in smoothness, when you fix your simulation timestep. see this link.
To talk a bit more about integration, when you will have introduced your "dt" (stuff that you multiply every unit to integrate into the next unit. Acceleration integrates into speed, and speed integrates into position). You use "dt" to multiply. If you do a simple multiply based on current values, this is called "Euler integration". If you use half of the current value, and half of the previous frame's value, this is called "Verlet integration".
Using Verlet will ALSO buy you smoothness and stability.
But really in your particular case, you need to focus on your "NoFloor()" resolution, this is the main culprit.
You have a feedback loop, because of numerical imprecision, you can't determine that for sure your character is "on the floor" after you corrected a penetration with your -= intersection.Height
subtraction. So what you need to do, is cut some lack to your "NoFloor" function so that it says a little bit more often that the character is actually on the floor.
Next step, is to try to correct penetration by progressive and smooth forces integrated over time rather than a super hard direction position correction. Use dampers and spring forces which are evaluated in term of the "distance to ground". And let a few frames fix the position, it will get rid of your bouncing totally. Just make your spring "hardness" (usually noted k
, or newton constant, in physics) very high to simulate the fact that you bump against a hard ground, and not some soft trampoline. But With any physics simulation, making so that every collision is solved in terms of soft interactions is always much more stable than truely hard interactions.
As a final point, I made a platformer demo that implements some of the ideas above, and the ground walking is perfectly smooth. You can check the code here.