cocos2d / cocos2d-objc

Cocos2d for iOS and OS X, built using Objective-C
http://www.cocos2d-objc.org
Other
4.07k stars 1.16k forks source link

Scheduled callbacks doesn't return time elapsed since last call. #1145

Open Birkemose opened 9 years ago

Birkemose commented 9 years ago

Scheduling a call like this:

[self schedule:@selector(test:) interval:1];

results in test:getting called with a value of 1.00000, while ex. the update: method gets called with the actual time interval. I guess this should be consistent?

Panajev commented 9 years ago

Is this a regression or has it always been like this? I think API consistency is only second to the zero bugs hopeful goal in terms of priorities, unless we drag performance waaaay down to achieve it. It would be nice to have it fixed yes :).

[web [iPhone msg]]

On 31/dic/2014, at 13:03, Birkemose notifications@github.com wrote:

Scheduling a call like this:

[self schedule:@selector(test:) interval:1];

results in test:getting called with a value of 1.00000, while ex. the update: method gets called with the actual time interval. I guess this should be consistent?

\ Reply to this email directly or view it on GitHub.

Birkemose commented 9 years ago

In 2.x the time was the actual time since last call, but I do not think it was correct over time. If you scheduled a callback each 0.1 second, you would not get 100 callbacks in 10 seconds, but less, depending on cpu load, fps and stuff. In 3.x, this is fixed, but the provided interval does not seem correct.

On 31 Dec 2014, at 13:56, Panajev notifications@github.com wrote:

Is this a regression or has it always been like this? I think API consistency is only second to the zero bugs hopeful goal in terms of priorities, unless we drag performance waaaay down to achieve it. It would be nice to have it fixed yes :).

[web [iPhone msg]]

On 31/dic/2014, at 13:03, Birkemose notifications@github.com wrote:

Scheduling a call like this:

[self schedule:@selector(test:) interval:1];

results in test:getting called with a value of 1.00000, while ex. the update: method gets called with the actual time interval. I guess this should be consistent?

\ Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHub https://github.com/cocos2d/cocos2d-swift/issues/1145#issuecomment-68440308.

andykorth commented 9 years ago

I think the current behavior is correct. It operates more like the fixedUpdate loop, which guarantees that it will be called with exact delta time numbers, regardless of wall-clock time. Since update should be used for things like setting positions of something that is going to be drawn, we want the actual wall-clock time to be used for that position to ensure motion is smooth even if the frame times are inconsistent or unsteady.

I believe scheduled stuff should occur on this fixed schedule because it's the only way we can reliably ensure an event scheduled with an interval of 0.1 and 100 repeats will occur that many times in 10 seconds and be evenly spaced. If we're reporting wallclock time deltas instead, when you add up all the deltas, they probably won't total exactly 10 seconds.

And perhaps more importantly, you might end up with intervals (deltaTimes) of zero if you were using wallclock time. Imagine running a scheduled task 100 times a second for 1 second. If you end up with a 0.2 second long frame somewhere in the middle of that scheduled task (maybe you loaded an image), the scheduler would call your method 20 times, the last 19 of which would have a interval of zero.

A detailed example log with fixed updates listed: (showing a few calls out of 100, scheduled every 0.1 seconds) https://gist.github.com/andykorth/510c01f9e1fad12d3779 Code used in test: https://gist.github.com/andykorth/0d415a17424a1cd48678

slembcke commented 9 years ago

Yeah. This was something that changed with the rewrite of the scheduler in 3.0 to support the fixed update loop for the physics. I could try and find the GitHub issue for it from last year if you'd like.

Kinda repeating what Andy said, but 2.x timers had a lot of problems that made them unusable with a fixed time step:

The new scheduler steps time forward along the actual timeline using a priority queue. The timers get called in the right order, with the exact interval that was requested. If you keep a reference to the CCTimer object, you can get the interval since the last fixed or variable update loop that was called.

The update: methods are the only thing that receive the frame delta times since their purpose was to handle variable frame intervals.

Make sense?

edit: A shorter way of putting it. Say you have a 100 hz timer and 1 second of time passes. In 2.x, you would get at most 60 invocations, though the delta time values would add up to 1. In 3.x you will get exactly 100 invocations, and all of the delta time values will be 1/100.

Birkemose commented 9 years ago

I guess for me, it is just a little weird to provide a param which is a constant. Would confuse me, and I would expect it to hold the actually delay since last call. Either that, or the callback should have no param at all. Anyways, I will rest my case.

On 31 Dec 2014, at 21:16, Scott Lembcke notifications@github.com wrote:

Yeah. This was something that changed with the rewrite of the scheduler in 3.0 to support the fixed update loop for the physics. I could try and find the GitHub issue for it from last year if you'd like.

Kinda repeating what Andy said, but 2.x timers had a lot of problems that made them unusable with a fixed time step:

You couldn't have a repeating timer with a duration shorter than a frame. If the framerate stuttered, it would affect timers. All timers were grouped together at the frame intervals and were called in a random(ish) order. There was no way to tell when the timer was supposed to be called. The new scheduler steps time forward along the actual timeline using a priority queue. The timers get called in the right order, with the exact interval that was requested. If you keep a reference to the CCTimer object, you can get the interval since the last fixed or variable update loop that was called.

The update: methods are the only thing that receive the frame delta times since their purpose was to handle variable frame intervals.

Make sense?

— Reply to this email directly or view it on GitHub https://github.com/cocos2d/cocos2d-swift/issues/1145#issuecomment-68466687.