Every X Milliseconds problem

For questions about using Classic.

Post » Sat May 29, 2010 11:09 am

http://dl.dropbox.com/u/6660860/timer.cap

This is most likely me being an idiot, but could anyone explain to me why the "bad timer" counts the milliseconds so slowly? You will notice i am increasing the Millisecond variable by 1 every 1 millisecond and then resetting it to 0 when it reaches 1000 (1 second) and then increasing the Seconds variable by 1, but it takes FOREVER to reach 1000.

If you look at the "good timer" however, if i simply increase the seconds by 1 every 1000ms it works just fine.

I hope i made sense here.

Thanks
B
7
S
2
G
4
Posts: 164
Reputation: 2,418

Post » Sat May 29, 2010 2:46 pm

That's just because you ignored what you can read if you open the wizard for the "every x milliseconds"-parameters. It says:

"This is only accurate to a resolution of ~10 milliseconds."

Well, you use a resolution of 1ms...

Set it to a value higher than 10 and it will work.
Image
B
23
S
8
G
10
Posts: 1,820
Reputation: 8,242

Post » Sat May 29, 2010 4:45 pm

There are a couple of other things I can add about this.

As tulamide mentioned, Construct warns about the resolution of the every x milliseconds condition. However, it's generally not even good to 10ms resolution under the default settings. Under the application settings, "Framerate Mode" is set by default to "V-Synced", which effectively limits the resolution to 1/60 (or 16.667 ms) on my computer. It lags on mine until I set the increment to 17 or more.

It's actually close to keeping up with the 1ms increment if I change the framerate mode to "Unlimited", where I get a framerate of around 2800. In practice, I've never felt the need to go below 50ms for any such condition, myself.

Also, I've found it to be a good practice to not rely on exact equality checks for counters such as what you use here. You would notice that it breaks if 1000 is not a multiple of the increment value (as with 17.) I would usually use:

+ System: Is global variable 'MillisecondsB' Greater or equal 1000

.
B
3
S
2
G
2
Posts: 187
Reputation: 1,449

Post » Sat May 29, 2010 6:31 pm

@Citnarf
If you simply want to have the time from the start of the application you could use the system expression "Timer", which gives the total elapsed milliseconds. Then to split it up into minutes, seconds and milliseconds, use the following formulas:
[code:rjzpz98p]minutes: floor(Timer / 1000 / 60)
seconds: Timer / 1000 % 60
milliseconds: Timer % 1000[/code:rjzpz98p]
B
79
S
24
G
54
Posts: 4,747
Reputation: 40,757

Post » Sun May 30, 2010 12:03 am

Ahh thanks a ton guys, your right i didn't read the text in the wizard at all :oops:.

R0J0hound, i will definitely give your timer idea a shot, thanks!
B
7
S
2
G
4
Posts: 164
Reputation: 2,418

Post » Sun May 30, 2010 12:41 am

Two threads that deepen R0J0hound's code snippet and could be of further help:

viewtopic.php?f=3&t=4938&p=40127#p40127

viewtopic.php?f=3&t=6238
Image
B
23
S
8
G
10
Posts: 1,820
Reputation: 8,242

Post » Mon May 31, 2010 1:12 pm

This is actually an interesting problem because the Every event can only trigger at most once per tick (like Always). So if you're running at 10fps, the Every event will only trigger at most every 100ms. This is kind of awkward because it can make things framerate dependent again, even in well-designed, framerate-independent games.

I thought about making 'Every X milliseconds' play catch-up - as in, in the above case at 10fps, if you have 'every 50ms', the condition will realise it should have triggered twice since the last tick, so then fires itself twice. This could create other subtle problems in events though. For example, the current time will be the same for both triggers (since it's actually running twice at the same time), and if it's important that other events run after the Every event, then that could break if the framerate drops and the Every starts re-triggering repeatedly to play catch-up. (One example is if you're firing a gun on Every, you start getting multiple bullets spawned at the same time.) But, on the other hand, logically you'd expect 'Every 10ms' to mean '100 times a second'!

It's a tricky area... what do you think should happen? Do you think the current system (capped at once per tick) is OK?
Scirra Founder
B
359
S
214
G
72
Posts: 22,952
Reputation: 178,600

Post » Mon May 31, 2010 2:39 pm

[quote="Ashley":1s9m5dmh]This is actually an interesting problem because the Every event can only trigger at most once per tick (like Always). So if you're running at 10fps, the Every event will only trigger at most every 100ms. This is kind of awkward because it can make things framerate dependent again, even in well-designed, framerate-independent games.

I thought about making 'Every X milliseconds' play catch-up - as in, in the above case at 10fps, if you have 'every 50ms', the condition will realise it should have triggered twice since the last tick, so then fires itself twice. This could create other subtle problems in events though. For example, the current time will be the same for both triggers (since it's actually running twice at the same time), and if it's important that other events run after the Every event, then that could break if the framerate drops and the Every starts re-triggering repeatedly to play catch-up. (One example is if you're firing a gun on Every, you start getting multiple bullets spawned at the same time.) But, on the other hand, logically you'd expect 'Every 10ms' to mean '100 times a second'!

It's a tricky area... what do you think should happen? Do you think the current system (capped at once per tick) is OK?[/quote:1s9m5dmh]

Yeah for v-sync you just about have to do that.
Would it be possible to have a an expression, or perhaps a plug that isn't frame rate dependent?
Image Image
B
161
S
48
G
90
Posts: 7,356
Reputation: 66,767

Post » Mon May 31, 2010 2:41 pm

[quote="Ashley":2fydhhpj]It's a tricky area... what do you think should happen? Do you think the current system (capped at once per tick) is OK?[/quote:2fydhhpj]
Given that everyone is aware of the implementation I would prefer the current system. Nearly every end user time system uses ...minutes:seconds.somekindofframes (instead of milliseconds, e.g. video editors use the video's framerate, games most often 10th of a second, music uses sample frames, etc.) anyway. And I can't think of a useful implementation for triggering events every 3 ms. The low framerate problem could be compensated by constantly checking the framerate thus getting the lowest possible resolution for "every ..."
Image
B
23
S
8
G
10
Posts: 1,820
Reputation: 8,242

Post » Tue Jun 01, 2010 12:59 am

[quote="Ashley":ypm3073b]It's a tricky area... what do you think should happen? Do you think the current system (capped at once per tick) is OK?[/quote:ypm3073b]

I can't really think of any good way for Construct to try and handle such a situation, other than how it does now. Since it really depends upon what one is doing at each interval, I don't think that there can be a catch-all solution.

I would implement a variation of TimeDelta, as a function, which would report the time elapsed since the last call. Like so:

[code:ypm3073b]+ Function: On function "TimePeriodDelta"
+ System: Is global variable 'previousTime' Different to 0
-> System: Set global variable 'currentTime' to Timer
-> Function: Set return value to (global('currentTime') - global('previousTime')) / Function.Param(1)
-> System: Set global variable 'previousTime' to global('currentTime')
+ System: Else
-> System: Set global variable 'previousTime' to Timer
-> Function: Set return value to 0[/code:ypm3073b]

This uses two globals, though it would also be good enough without 'currentTime', and accessing the Timer twice instead of once. Anyway, the first time it's called, it returns zero and starts counting time, then every call after will return the difference since last call. It takes one parameter, which the difference in milliseconds is divided by. Pass it the value 1 and it will return milliseconds, or pass it the same interval as your 'every ... milliseconds' condition, and the desired result would be one.

For instance, for a '5 damage per 50ms' event, I pass the function 50, using it in expression form as a multiplier for the desired damage. Much like the TimeDelta.

[code:ypm3073b]+ System: Every 50 milliseconds
-> System: Subtract 5 * Function.TimePeriodDelta(50) from global variable 'Health'[/code:ypm3073b]

I think a built-in such as this could be useful, but it's not difficult to implement anyway.

I made a simple .cap to test this, which simply appends each result into an EditBox. I did get some odd intervals with low fixed frame rates.

v0.99.84: [url:ypm3073b]http://dl.dropbox.com/u/5868916/TimePeriodDelta.cap[/url:ypm3073b]
B
3
S
2
G
2
Posts: 187
Reputation: 1,449

Next

Return to Help & Support using Construct Classic

Who is online

Users browsing this forum: No registered users and 2 guests