Mathematical error in the physics restitution formula

I admit it. I am a mathematical idiot. Should I try to do this at home? Probably not without serious injury. Anyway. Anyone who has a little experience in games and physics who can view this code and make it clear why there is a built-in “loss” of speed in the prototype will be greatly admired.

concept: an actor falls from the sky, at some point crosses the border (trampoline.y), after which gravity (in this example, a value of 1.6) stops working and the restitution coefficient (in this case, the value is 6).

right now I'm trying to create a situation with a zero amount in which you get the same speed as exiting the trampoline "bounce" (hero.y> = trampoline.y), as you did. as the tracks show.

I tried five different approaches, and this is the last, given the understanding that with any given tick of my game timer (33 ms) we could go over the trampoline boundary, and thus, the acceleration rules will be changed. I really thought I had it, but the results show a decrease in speed after each bounce, which I did not expect.

I pass the following code to your reviewed review:

var newV:Number; if (hero.y < trampoline.y) { newV = hero.velocityY + gravityAccelerationInPixels } else { newV = hero.velocityY + TrampolineActor.SPRING_ACCELERATION } var newY:Number = hero.y + newV; trace("Coming in: y=" + hero.y + " oldVelocity=" + hero.velocityY + " newVelocity=" + newV + " Change in V: " + (newV - hero.velocityY) + ". Testing for newY=" + newY); if ((hero.y < trampoline.y && newY < trampoline.y) || (hero.y >= trampoline.y && newY >= trampoline.y)) { hero.y = newY; hero.velocityY = newV; } else { trace("SPLIT"); var percent:Number = (trampoline.y - hero.y) / newV; trace("Percent: " + percent); var newVV:Number; if (hero.y < trampoline.y) { // going down! newVV = hero.velocityY + percent * gravityAccelerationInPixels; trace("New velocity before split: " + hero.velocityY + " Change in V: " + (newVV - hero.velocityY)); newVV += (1 - percent) * TrampolineActor.SPRING_ACCELERATION; trace("Percent after split: " + (1 - percent) + " Change in V: " + (newVV - hero.velocityY)); } else { // movin on up! newVV = hero.velocityY + percent * TrampolineActor.SPRING_ACCELERATION; trace("New velocity before split: " + hero.velocityY + " Change in V: " + (newVV - hero.velocityY)); newVV += (1 - percent) * gravityAccelerationInPixels; trace("Percent after split: " + (1 - percent) + " Change in V: " + (newVV - hero.velocityY)); } trace("New velocity: " + newVV + " Change in V: " + (newVV - hero.velocityY)); hero.velocityY = newVV; hero.y += hero.velocityY; } 

Additional info: The origin of the screen is top left, so y-- = higher up Currently my tick is set to 33 ms gravityAccelerationInPixels currently 1.62 (fairly random) SPRING_ACCELERATION is arbitrary 6, but I hope to set this number to control. how far below the trampoline the character can go during the deceleration / absorption cycle.

Currently, I hope to get a solution in which the speed at tic after the character contacts the trampoline will be the same (but negative) from the speed immediately before the entrance. I even tried to keep both getting the position and entry speed, but it looks like a hiccup.

+4
source share
1 answer

Here are some debugging methods for this type of simulation:

  • First: make sure you know what units each of your variables and constants is in. For example, if hero.y is the distance in pixels, then since it is set to hero.y + newV , it should in case newV also in pixels; except that it is assumed to be speed (distance at a time), so it should be pixels per frame (where the time interval is implicit because you do it once per frame).

    For the next debugging steps, it is better to make sure that all your values ​​are expressed in seconds, and not in every frame; to do this, enter a value equal to your time, in seconds per frame. Then you have hero.y + newV * timestep and similarly newV = hero.velocityY + gravityAccelerationInPixelsPerSecondSquared * timestep .

    OK to calculate gravityAccelerationInPixelsPerSecondSquared * timestep as a constant by itself, but make sure all your hardcoded values ​​are independent of your time, so you can easily:

  • Try reducing your time interval by some factor k. If this reduces your error, your problem is that your discrete time calculations do not match the ideal integral query. If this does not reduce your error, then your simulation will be consistent, but in a sense “non-physical”.

  • Try to calculate the total energy of your system. That is, the amount

    • kinetic energy of any moving bodies, 1/2 · m · v² (m = mass, v = speed)
    • potential energy of any incident bodies, m · g · h (g = constant of gravitational acceleration, h = height above an arbitrary control point)
    • potential energy of any springs, 1/2 · k · d² (k = spring constant, I hope, equal to your "restitution coefficient" (but positive), d = distance offset from the relaxed state)

    If you give h = hero.y - trampoline.y , then for your specific system you

    E = 1/2 · m · v² + m · g · max (h, 0) + 1/2 · k · (min ( h , 0)) ²

    (From my reading of your code, gravity does not apply when the character is on a trampoline, and if so, change max (h, 0) only to h.)

    Make sure you do this in consistent sizes (you cannot add pixels per second to pixels) and units (you cannot add pixels per second in pixels per frame or inches per second). Remember that a square also blocks units.

    According to your stated goal - a character bouncing at the same speed - you have a system without friction, and therefore the energy of the system should be identical before, during and after the rebound. If the energy changes, then pay attention when it changes. For instance:

    • If it changes when the symbol falls, then your simulation of this case, constant acceleration, is incorrect. A common mistake (it looks like you did in your code) is to forget the third formula term for a position with constant acceleration : newPos = pos + velocity * timestep + 1/2 * acceleration * timestep^2 , where acceleration is gravity. (It’s also important to update the position before updating the speed so that you don’t use tomorrow’s speed with yesterday’s position in calculating the position.) Try simulating a rebound on a hard surface instead of a trampoline to simplify the situation.

    • If it changes exactly when the character touches or leaves the trampoline, your calculation of percent does not reach its goal.

+14
source

All Articles