Craft applyForce is erratic

Attached file includes detailed comments and code showing

  1. applyForce fails after a while, then recovers, then fails again.
  2. applyForce works less well if called during scene:update than if called during draw.

What you should see: Run the program. The ball bounces up and down, reversed by the reverse function every two seconds. After a while (7 or 8 seconds on my iPads) the whack will miss and the ball will continue on. The program continues to try to reverse it every two seconds. Usually, after a further while, it’ll succeed and the ball will bounce up and down wherever it now is. (Usually off screen.)

Failure comes sooner and more frequently when doing the reverse during update rather than draw per the toggle.

ONE MORE THING: I recommend setting the parameter to false, not true, to begin. I’ll put the proper zip file below.

Further explication available of course.

I think most of this behavior is consistent with the object sometimes falling asleep and waking up, but of course there could be many other causes.

Zip File Here. Also, a movie of it failing is in this article.

@RonJeffries Ran your zip program. I ran 100 draw whacks with no problem then I switched to scene whacks. When I reached about 170 whacks, I noticed that the force was now 720 which means it missed 2 reverse forces. I ran it again, this time with 200 draw whacks and 100 scene whacks with no errors.

I wonder if the draw cycle is executing with a certain cycle rate and the physics engine is executing with a certain rate. But there’s a problem when the 2 execute at exactly the same time and the result of the physics applyforce gets missed. I think you mentioned at one time your device ran at 120 fps. I wonder if the fps varies, you hit the sweet spot more often and miss the applyforce more.

interesting. i would not think it could accelerate beyond the starting speed: it calcs the force as 2x the negative of current velocity.

it’s weird, obv machine dependent. i hope @John can explain, and fix.

I’ll have to see if i can figure out how it can possibly accelerate. seems impossible.

thanks!

@RonJeffries When I was out of wack, I had a force of 720 going back and forth. I was also going back and forth higher up on the screen. So somewhere I missed 2 reverse forces and ended up higher on the screen.

@RonJeffries I’ll look into this because it’s probably due to a few different things. Bullet3D and physics engines in general make use of numerical integration, which is subject to accumulation of errors over time. This means that precise forces applied over multiple frames are not precise enough, leading to unexpected behaviour as compared to analytic solutions from Newtonian equations

That said, I need to look into exactly what timestep is being used by Craft, and use your example to experiment with it as well as make sure the fixedUpdated(dt) method is working which would provide you with precise delta time values used by the physics engine

@RonJeffries @John Here’s a really whacked up run. Look at the last 2 outputs. Here’s how/why it happened. I paused the program 2 times for about a second each time. Even though the draw function was paused and the ball wasn’t moving, the physics engine was still running. I’m not sure what it was calculating, but that’s the results. I didn’t pause the program that I mentioned above with the 720, but it might be something similar but on a shorter time scale.

ah. yes. I’d bet the engine uses wall clock time, so that a pause can get some weird answers … pausing is surely gonna confuse it. now i have to the that for fun!

@RonJeffries The physics engine doesn’t stop unless you do a physics.pause(). There’s other things that still run even though the program is paused. The touched function is one of them. Those functions run normally, they just don’t communicate with the normal code until it starts running again. Once the code is started, it gets updated with wherever those functions were doing.

@RonJeffries it doesn’t use wall clock time exactly. What happens is each frame the delta time is accumulated into a buffer. When that buffer reaches 1/60th of a second (physics fixed delta time) it does an update (and more than one if there’s more multiples of 1/60 in the buffer). This ensures that all physics updates are always using the same timestep, while keeping up or slowing down based on varying framerates

What I suspect is happening, since fixedUpdate is not working you get this:

-- Frame 1
scene:update(dt)
-- physics update is triggered, force is applied from last time, rigidbody velocity is updated
applyForce(-vel)

-- Frame 2
scene:update(dt)
-- physics update skipped this frame due to slight differences in DeltaTime and buffer hasn't filled yet
applyForce(-vel) -- velocity is not up to date and calculation is wrong

-- Frame 3
scene:update(dt)
-- physics updates twice but velocity is already wrong

etc...

Once I get fixedUpdate() working properly we’ll see what happens.

Could also have something like scene.onFixedUpdate = function(dt) end for hooking into the scene fixed update directly?

@John thanks … I’ll have to think on that a bit. I am not surprised that physics time needs to be constant, and glad that it is. It’s the only way a momentum calc could even be close.

What we see happening in my program, though, doesn’t seem quite explained. The velocity in my case is always 2. I set it to 2 at the beginning, and you can see from the output numbers and the force always being 240 that it’s always read as 2 when I apply the force.

(240 is the force you need to exactly reverse a mass 1 object traveling at speed 2 in 1 60th of a second.)

I specifically coded the program so that if it works, velocity will always be 2 or -2 and since we see the velocity display always being 2 or -2 and the whack always 240 or -240, I don’t think we have a problem that can be explained by a missing update due to a minor delta time difference. Next time around vel will still be 2 and the required force still 240.

What we see after a while is that vel stays at, say -2, and we hit it again and again with 240 and it doesn’t slow down or reverse, it just keeps going. Then, after a while, it does reverse and things start to work.

I suspect it’s something about activation and sleeping, not a near-miss timing issue. See what I’m at?

The scene.onFixedUpdate and object:fixedUpdate, it seems to me, need to happen at the very beginning of the physics cycle so that they’ll be taken into account if they do something like applyForce.

One way or another, you want to be sure that the impulse is always transferring momentum equivalent to the force for 1/60th. Yes?

@dave1707 that’s fascinating, that pause just pauses the draw cycle. I never knew that. I’m not sure how that explains the weird velocity of the ball, though, since we won’t even do a scene:update, since we don’t even do a draw.

What am I missing?

@RonJeffries After playing around some more with this, it appears the Craft physics is paused when the code is paused. I’m not sure how many cycles it runs before it gets paused. The regular physics doesn’t get paused.

odd. I wonder why they don’t pause everything. anyway good to know.

I’ve pushed a new beta build that has some physics system changes/fixes. Let me know if it helps.

how can i get the beta, please

@RonJeffries send me your apple id email and I’ll add you to TestFlight

ronjeffries@acm.org