Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Inaccuracy of the physics engine?

edited June 2013 in General Posts: 1,595

Hey guys check this video out :
Its two runs of my latest game with exactly the same track, fps and physics body moving but the outcomes are slightly different which is making my game a bit unplayable as in its not really possible to make a full length track that works exactly the same every time.

«1

Comments

  • edited May 2013 Posts: 580

    @Luatee: can you try something for me? Turn off interpolation on your physics bodies and see if that fixes your issue. I have a theory but I want to see if this works before I explain it.

  • Posts: 1,595

    I set interpolation of the physics body (now a 60x30 square polygon) to false and the track doesnt have interpolation on but its still happening and im not quite sure how to solve it

  • edited May 2013 Posts: 580

    Hmm, that blows my theory out of the water. In my experience with Box2D outside of Codea it's behavior is deterministic, so my only thought is that it's something specific to either a) Codea, or b) your code, but I doubt it's Box2D. Most likely it's b)

  • edited May 2013 Posts: 580

    Actually, I take that back, my theory might still hold water, but with some modification (it doesn't have to do with interpolation).

    I think what's going on has to do with the way the physics time stepping is implemented in Codea (which is what allow interpolation for smooth motion, regardless of framerate). Most likely they implemented it this way: http://gafferongames.com/game-physics/fix-your-timestep/

    What this can mean is that, although the physics engine is being updated with a fixed timestep, the iterative nature of the solver can produce unexpected results depending on the elapsed time from one Codea frame update to the next. For example, if one game loop step takes longer than the fixed timestep, on the next frame update Codea will actually end up stepping the physics engine twice, potentially leading to a slightly different result from one run to the next (since due to environment-wide variability like garbage collection, OS-level operations, etc, you aren't guaranteed that from one run to the next your updates will always use the same time deltas). This is just a theory, but it makes some sense to me. Maybe someone smarter than me can lend some credence to or debunk this theory.

    EDIT: nope, I take this back. I just read the article again (it's been awhile), and had forgotten that the algorithm ensures that the results are deterministic. If indeed the time step is implemented this way in Codea than I doubt that's the problem. I'm back to thinking that either Codea doesn't implement their time step this way (though if memory serves correctly since the last time I've looked at the runtime they do), or you have some issue in your code itself. What are the inputs? Can you influence the simulation at all (for example with the accelerometer or with touch), or is it strictly "hit the play button and watch what happens"?

  • dave1707dave1707 Mod
    Posts: 7,613

    I think it's caused by the precision of Codeas' calculations. I created a program with 2 circles that bounced off the edges and each other. I addled code to restart the positions and velocity anytime I touched the screen. I had one of the circles leave a trail of it's path and each time I touched the screen, the one circles' path would overlay the previous ones, but eventually it would start to deviate from the trail. That's probably what's happening to your program. Even though you start out the same, the small errors start adding up and the calculations start to deviate. The longer the program runs, the more things are going to differ.

  • edited May 2013 Posts: 580

    @dave1707: Nope. If you are running your physics simulation with a fixed time step, the results will be the same run after run, regardless of how long the program has been running, if the input is identical (again, I've had a lot of experience with Box2D outside of Codea, and this is definitely the case). Sure, there may be tiny rounding errors due to using floating point math, but again, if the time step is constant, and the input is identical, those errors will be consistent fom run to run. So, either a) Codea's physics time step is not truly constant, b) something else that Codea is doing is causing the inconsistency, or c) the simulation's input is not identical from run to run.

  • dave1707dave1707 Mod
    Posts: 7,613

    . @toadkick I start the simulation each time with the same x,y values and the same linearVelocity for both objects. Sometimes the trails overlap, sometimes it starts to vary a little. If I keep restarting the simulation, the new trail will follow one of the trails, either the original or one of the varied ones. Something changes, but it's repeatable from one run to the next.

  • edited May 2013 Posts: 580

    @dave1707: when you say "restart", do you mean "terminate and restart the program" or do you mean a "warm" restart, where you reset the simulation state within the program itself, without terminating the program? There is a subtle difference, and I might have another hypothesis depending on your answer.

    If it works when terminating/restarting, but not with "warm" restarting, then this is definitely an issue with Codea's implementation. If it's inconsistent both ways...then I have no idea what the specific cause might be.

    @Luatee is correct about this: if the results of the simulation are not deterministic, it is impossible to provide physics-based gameplay that feels fair and predictable.

  • dave1707dave1707 Mod
    edited May 2013 Posts: 7,613

    . @toadkick I just do a warm restart so that the trail from each run remains on the screen. Each restart starts with the same values for the 2 objects.

  • edited May 2013 Posts: 580

    @dave1707: I'd recommend reconfiguring your test so that you can terminate/restart the program and test the consistency. Since you only have a two simulated objects on screen, you can save out their orientation/motion information every frame (using one of the save*Data functions), and compare the numbers across two runs.

    This is my hypothesis: "warm" starting does not re-initialize Box2D, thus the input to your simulation is not identical in each run (in other words, the physics engine's state will not be the same when you warm restart your program as it was when you cold started the program).

  • edited May 2013 Posts: 1,595

    Well I'm still a bit peeved that this is the case, as my game will not be a good runner if the outcomes vary each time the ball starts again. The thing is I don't even do a restart, I just recreate the physics bodies but obviously being maths the lines will not change as the points surrounding it do not change. I'm not experienced in java/c++ so I couldn't run a test in box2d itself, that might be a good idea though?

  • JohnJohn Admin Mod
    Posts: 573

    @Luatee Codea uses a fixed timestep for physics calculations so it should be deterministic. Does the bike in your demo have any forces acting on it besides gravity? Do you use DeltaTime for any calculations in your game?

  • Posts: 1,595

    There is only gravity acting on the body, so I'm not sure whats going on. I only use DeltaTime for a fps watcher such as text("FPS: "..1/DeltaTime,x,y)

  • dave1707dave1707 Mod
    Posts: 7,613

    .@toadkick I altered my program to save 470 plots to local data. Each time I hard restart the program, I read the 470 plots back in and plot the original trail. I then start the 2 balls bouncing around and the ball that does the plot followed it's path 10 out of 10 times. When I did soft restarts, the ball followed it's path about 7 out of 10 times. So what path the ball takes depends on the timing of the soft restart. If that's the case, you can't guarantee the same path unless you hard restart the program each time which probably isn't an option in a normal game.

  • edited May 2013 Posts: 580

    @dave1707: Thanks for confirming. I think a possible solution would be for Codea to provide a way for us to manually reset Box2D from within our programs (not sure how easy/hard that would be to do). I think this would solve @Luatee's issue too.

    Another thing that might provide consistency is to make sure you've manually destroyed all of your physics objects when you do a warm restart, but I am not holding out much hope for this method.

  • Posts: 1,595

    Well seeming as I haven't put in a way to save tracks yet it isn't going to work that well for me to test this. I did notice when I was doing my testing the track was completed about 6 times out of 10, it seemed every other running of the simulation worked fine, this was with about 6 different runs of deleting the physics bodies then recreating them (without restarting the app at all) so it is going to be a lot harder for me to fix this situation from what I can see, feel free to correct me if Im wrong

  • edited May 2013 Posts: 580

    @Luatee: I am about 99% sure that being able to reset the entire physics engine from within your program would solve your issue (assuming of course that you've saved your tracks, so that they can be recreated after the reset).

  • Posts: 1,595

    well if it was just a physics engine reset then thats alright as I can store all the values before doing so then restoring them after, I hope that this will be seen and heard by the developers of codea anyway otherwise I'll have to go back to my other game

  • dave1707dave1707 Mod
    Posts: 7,613

    I altered my program to destroy all the physics objects and recreate them each time I do a soft restart. I did 20 soft restarts and all 20 times the plotting ball followed the original path. So destroying and recreating the objects look like it will work.

  • Posts: 580

    @dave1707: ahh nice!

  • JohnJohn Admin Mod
    Posts: 573

    @Luatee I suspect whats been happening is that nilling objects and restarting your game will not destroy physics bodies immediately, you need to do myBody:destroy() before you nil your physics bodies otherwise you could create a new body in the same position before the garbage collection takes effect and the 'ghost' bodies might interact with objects in the new game causing different starting conditions resulting in what appears to be non-deterministic behavior.

  • Posts: 1,595

    Well I was destroy all the line bodies but not the bike body which I dont know if that would have an effect on it but I've set that to be destroyed each time the simulation ends aswell and I'll get back to you in a bit with the outcome.

  • Posts: 1,595

    @John Ive tested that and Im still ending up with different results still, Im not sure what to do now though

  • Posts: 372

    I don't know how you've done the programming @Luatee, here's how I did it and I get the same results every time I reset the ball. But there are two catchs one is that though the angle rotated, ball.x, ball.y are the Same the time taken is accurate to the first decimal place in seconds. Since I've calculated time taken using DeltaTime I think that's pretty accurate. Second i didnt move the screen so at most you could draw five to six lines if too many lines is making a problem then this code maybe won't solve it. Here's the code if you want to have a look. https://gist.github.com/Saurabh96jun/5655889

  • Posts: 1,595

    No I'm not sure that will help as the only way I get these errors are with a full length track

  • edited May 2013 Posts: 372

    While making the track how do you keep the cycles position always in the middle of the screen. Cause if the cycle is a physics body and has a velocity then shouldn't it at some point move out of the screen. Maybe the way you keep in cycle in the middle might be making the difference. I am not sure about it though just a guess.

  • Posts: 1,595

    Nah its not that, you can do it by translating the screen to the balls position and adding Width/2 and Height/2 that should follow the ball

  • Posts: 1,595

    I have narrowed it down to this -
    The bike takes two separate paths and it changes between them each time the bike is added and the simulation run

  • dave1707dave1707 Mod
    Posts: 7,613

    That's what I was finding in the physics simulation I did. There were 2 paths that the ball took. But after I changed the program to destroy and recreate all the physics objects each warm restart, it took only one path. I'm thinking that if I would have let it run for longer times, the single path would have started to deviate again after several more collisions. It's called Chaos theory. Unless everything is calculated to infinity, things are going to change. Maybe even at infinity too.

  • Posts: 1,595

    Well according to john it doesn't include random occurrences or chaos theory as you say, it should only follow one path

  • dave1707dave1707 Mod
    Posts: 7,613

    Codeas' math has only 6-7 digits of precision which sucks when it comes to physics objects or anything else that does continuous calculations. Rounding errors start to occur fast and keep growing. If you do simple calculations on one object, you probably will come out with the same results. But the more objects you add, the more the calculations will differ. The tracks are made up of multiple physics edges, so the bicycle would have to hit every one exactly the same each time. I doubt that will happen with the limited math precision. And that's what Chaos theory is, the accumulation of small errors that add up to cause a difference from one run to another.

  • Posts: 36

    I quite like the iOS game Bubble Ball which is a free physics game. But I have noticed that adding an irrelevant object to the scene can make the physics of the ball change ever so slightly.

  • edited May 2013 Posts: 580

    @inoddy: You are correct, even the presence of an additional body can alter the outcome, because of certain details of how Box2D is implemented.

    But again: Box2D's behavior is deterministic. If the input is the same, it doesn't matter how long you let the simulation run, it will always be identical (after all, reproducibility is necessary in software. Nobody would use a physics engine that couldn't be debugged!)

  • Posts: 36

    But @toadkick surely if I have a ball running down a ramp on the right side of the screen and add a box to the left side and the box never touches the ball then the ball should always follow the exact same path? Unless the box has a gravity field.

  • Posts: 372

    Why is it then that if I play the game line rider online the result is always the same even if I make I long track and even have some extreme cases where the cart just lands on the line? Do they use more accurate physics engines or is there some method to do so??

  • Posts: 580

    @inoddy: It might be ever so slightly different. You would only notice the tiny difference if you did one run without the irrelevant box, and then another run with it. There are a few reasons for this, but largely it has to do with the fact that adding that extra body changes the internal state of Box2D (for example, the bodies might be processed in a different order, depending on the order that you add the bodies to the world).

    @Saurabh: I believe line rider uses a custom physics engine, tailored specifically to the game. Line rider's engine is not a full-featured engine, and is quite a bit simpler than Box2D.

  • Posts: 1,595

    Line riders engine seems to be doing better than our favoured box2d atm, I'm just stuck I doubt this games gonna move anywhere

  • dave1707dave1707 Mod
    Posts: 7,613

    .@Luatee I've been playing around with my program that was giving me 2 different paths for the bouncing balls when I would do soft restarts. I added physics.iterations(1,1) in setup() and that gave me 1 path with the soft restarts. Not sure if that will make a difference for you or not.

  • edited May 2013 Posts: 372

    @dave1707 I didn't understand why you set the iteration to 1,1. I read the inbuilt help and saw that higher the number more stable the physics is and the default is 10,8 then shouldn't you actually set it higher than 10,8?@Inoddy even if the mass of the body affects the motion of the ball. In this case the edges don't have mass and also the results are different for the same case I.e. without making any changes

  • Posts: 1,595

    @dave1707 thanks I had a little play and it seems to have improved the accuracy of it but not by setting it to 1,1. I'm at 10,50 atm which is giving good results, except there are still 2 defined paths, they just follow each other a bit more closely. Thanks for that though I've always missed tht function in the reference

  • dave1707dave1707 Mod
    edited May 2013 Posts: 7,613

    .@Saurabh I knew that the default was 10,8. I tried various values going as high as 100,100 but none of them seemed to matter. I would still get the same 2 paths. I then tried going lower and when I reached 1,1 I got one path each time I did the soft restart. The path wasn't the same as either of the 2 paths when it was set to the 10,8 default. So I'm not sure what's happening.

  • Posts: 1,595

    Well the iterations change the path each time you change each one, I tried doing 1,1 but no luck so I'm not sure if its to do with that

  • dave1707dave1707 Mod
    Posts: 7,613

    .@Luatee I modified my collision program to let me compare 1,500 x,y collision points and I was still getting 2 different paths that alternated on soft restarts. That's also what I saw in my previous experiments. What I then did in the latest program was when I would destroy all the physics objects and recreate them during a soft restart, I would do another soft restart destroying the objects and recreating them again. So basically I was skipping the conditions of the second path and recreating the conditions for the first path again. I compared the 1,500 points and they were the same. So maybe you could determine how many different paths you take and skip the paths that you have to so you get just one path. A hard restart seems to recreate the same conditions each time, but a soft restart seems to vary, in my case creating 2 paths.

  • edited May 2013 Posts: 1,595

    Solved, thanks a lot dave and everyone else, @dave1707 you confirmed my theory of the two alternating paths, I got it to create destroy and then create again. This made the ball only follow the one

  • dave1707dave1707 Mod
    edited May 2013 Posts: 7,613

    .@Luatee Glad that helped. I was playing with my program again and I had 7 balls bouncing around the screen. Every 20 collision, I added the 7 current x,y positions up and saved that value in a table for 50 entries. So that was 1000 collisions. Even with 7 objects, the 1st, 3rd, 5th, and 7th loops were the same. The 2nd, 4th, 6th, and 8th loops were the same. So I would say that kind of confirms that there are 2 different physics starting conditions on soft restarts.

    EDIT: I don't think there's anything wrong with the accuracy, just the starting condition.

  • Posts: 1,595

    I think you're spot on with that as I always ended up with it having 2 paths, the difference in the physics body at each start? Who knows? I know that something must be defining its path but none of the physics.body attributes cover that so I'm not sure, I don't think it's the accuracy of the engine although I've noticed a few hiccups and trip ups that can occur with the engine but then again I think they'll probably occur every time if it isn't changed so that makes it more accurate i guess..

  • Posts: 372

    So what I understood is that we should destroy the physics bodies twice every time and recreate them if we want the same result every time. That should solve the problem. Correct me if I'm wrong.

  • dave1707dave1707 Mod
    Posts: 7,613

    From what I've seen with my collision program, everything I tried so far points to 2 different paths on soft restarts. As @Luatee said, there doesn't seem to be any attributes that prevents this. So the only solution is to do a destroy and define twice to skip over one of the paths.

  • Posts: 36

    It would be interesting to program a double pendulum (http://en.wikipedia.org/wiki/Double_pendulum) in Codea. It's the classic example of chaotic motion (or the butterfly effect).

    Perhaps someone could post some code here (perhaps starting from Test 2 in the physics lab).

  • dave1707dave1707 Mod
    edited May 2013 Posts: 7,613

    .@inoddy Here's something I wrote a long time ago.


    supportedOrientations(PORTRAIT) displayMode(FULLSCREEN) function setup()     c1 = physics.body(CIRCLE,0)     c1.x = 400     c1.y = 900     c1.restitution = 1     c1.type = STATIC          c2 = physics.body(CIRCLE,25)     c2.x = 300     c2.y = 600     c2.restitution = 1            c3 = physics.body(CIRCLE, 25)     c3.x = 300     c3.y = 800     c3.restitution = 1            c4 = physics.body(CIRCLE, 25)     c4.x = 100     c4.y = 700     c4.restitution = 1           p1=physics.body(POLYGON,vec2(-10,25),vec2(-10,-25),vec2(10,-25),vec2(10,25))      p1.x=200     p1.y=700                  joint1 = physics.joint(REVOLUTE,c1,c2,c1.position)     joint2 = physics.joint(REVOLUTE, c2, c3,vec2(c2.x,c2.y))        joint3 = physics.joint(REVOLUTE, c3, c4,vec2(c3.x,c3.y))      joint4 = physics.joint(REVOLUTE, c4, p1,vec2(c4.x,c4.y))            end function draw()     background(40, 40, 50)          noFill()          stroke(255)     strokeWidth(2)     line(c1.x,c1.y,c2.x,c2.y)     line(c2.x,c2.y,c3.x,c3.y)      line(c3.x,c3.y,c4.x,c4.y)      line(c4.x,c4.y,p1.x,p1.y)                 strokeWidth(1)     ellipse(c1.x,c1.y,4)             ellipse(c2.x,c2.y,c2.radius*2)          ellipse(c3.x,c3.y,c3.radius*2)         ellipse(c4.x,c4.y,c4.radius*2)         strokeWidth(3)         translate(p1.x,p1.y)     rotate(p1.angle)     local points = p1.points     for j = 1,#points do         a = points[j]         b = points[(j % #points)+1]         line(a.x, a.y, b.x, b.y)         end end
Sign In or Register to comment.