These timers do not exhibit run to completion behavior. You can trick the engine into giving you similar functionality, or work around it. In some cases you may have to use run to completion timers, but avoid this whenever possible.
You can use a separate rule and an extra attribute to do this. Essentially you create a timer with a Boolean toggle rather than the actual code you want run, then place the code in a simpler rule toggled by the Boolean. Once the code you want run is completed (you may need to track this with another rule) you can toggle the Boolean off. As the Boolean cycles, your events are fired and are not limited by the cycling of the math timers themselves, which can in turn give your events enough time to run properly.
Hey...this is great tip, i replaced all my timers on my new game, i had everywhere timers because needed, and now i see great difference on performance and speed. THANKS!!!
This is a great tutorial. I have an addition that I picked up a while back on the forums (I'm not claiming this as my idea or creation, just stumbled across it).
The following will allow you to loop extremely fast while also waiting for your instructions within the loop to complete:
If you don't want the loop to fire on actor start and want to start it with an action, change the loop condition to >=
example: Self.Time >= time.Stamp
Then, throw this in some other outside action:
Change attribute timeStamp = Self.Time + 0.005
Note:
I always use .005 as it seems fast enough, but it appears to work all the way down .00001.
tatiangMember, Sous Chef, PRO, Senior Sous-ChefPosts: 11,949
@eezing. This is awesome! I've been trying to figure out a faster loop method because I'm using it to build and search tables so often. In a quick test (see attached), it's twice as fast as my current method. Thanks for posting that.
Since I'm replacing many many timers, won't all the extra self attributes reduce performance too? Or do self attributes make that little of a difference to the performance?
The addition of attributes does have a performance overhead, but it is significantly less than what a native timer takes. The difference is that the attributes use physical memory to store, whereas timers use processing power. From experience, I can say that processing power is more often our limiting factor on performance than physical memory.
The memory used by a single attribute is fairly small, especially compared to game assets such as graphics or sounds. In practice, the memory overhead of these timers is nearly negligible.
Hey @domenius Electric brain wave to delve so deep into the core architecture of this baby and gettin us a refined way of speeding up our games man really. I am having one problem, the alternate mod way for creating the every timer works great when you use real numbers but when i try to fetch a number for timing using the rand function, the timer goes haywire and just does not time correctly.
For example, i am looking to spawn a character after a random duration of say 5-10 seconds. I have my mod1 set up to 0.05 sec. When i create a when mod1=self.time%rand(5,10) rule, several characters are spawned 1-2 seconds after the other. This is peachy if you use a static number which is say 5 seconds in place of the random function.
@adilsulaiman. If you are using longer iteration times, such as in your example, the easiest fix is to create a new mod value. If you simply set mod to a larger value, for your example I would try 1, it should work just fine.
The problem you are encoutering is caused by floating-point accuracy issues. Since you are feeding rand an integer value, it outputs an integer value. When we compare the integer to a very small number (this case, 0.05) the equation is never given a chance to flip between its on and off state. You might be able to fix this by simply stating rand(1.0,5.0), though I've had mixed results in practice. The best solution is modifying the mod value; as stated above.
@Socks , now my spawning engine purrs happily, thank you!
@domenius That did not do it no, instead i saw three actors instead of just the two spawning at 1 second intervals between each other. Although i understand the anomaly and i would think that playing around with the mod would ultimately fix this irregularity but the @Socks way is quicker albeit at the expense of another native variable!
This seems to work for almost everything. However, I tried the For Timer Workaround for an animation and the animation no longer animates. It works perfectly in the Timer Behavior, but not with this. I wasn't sure why and it works for everything but animations. Anyone have a solution for this or should I just go back to the For Timer Behavior?
I'm not positive, but I'm guessing when you used the For timer behavior, "Run to completion" was active? If so, I think (-I think-) that this workaround only does this without the "run to completion active," in which case your animation will stop after a certain point.
Ok sorry if this has been asked/stated in this thread already but I've been using something like
if mod1 > self.time%.1
change attribute self.size.width to 100-( self.Position.Y /9)
so that the actor gets smaller as it moves up the screen. I did this because I read that constrain is performance heavy like timers. My question is, is this way any better than using a constrain instead?
@tatiang not sure why but your zip always shows up as an image and not downloadable on safari or Firefox for me. On iPad I can click it and the text shows as a link that I then mail to myself to get it to download but not sure why it never works on regular browsers.(or its just mine?)
The 'time stamp' method seems like the way to go if you want very fast iterations, I noticed that changing the interval time from 0.005 to 0.00001 made it no faster, I'm guessing somewhere around 0.005 is this method's limit ?
The 'time stamp' method does seem to be the fastest looping method. The interval threshold seems to be at about .01. Anything higher (for example .02) will almost double the time it takes to complete 500 iterations. But anything lower (for example .005) does not appreciably increase the speed. Anything under .01 continues to fluctuate around 9-10 seconds to complete 500 iterations (including as low as 0.0).
Just tested this, you are pretty spot on, the limit seems to be about 0.01 - I tested 0.015 against 0.01 (running at the same time) and it takes around 2,000 iterations before you see 0.01 pull very slightly ahead - so 0.01 seems to be number.
I wonder is there is any advantage/disadvantage to using 0.01 as opposed to 0.0001 as they both loop at the same speed, would 0.01 give the loop more time to execute its function/contents ?
tatiangMember, Sous Chef, PRO, Senior Sous-ChefPosts: 11,949
@SingleSparq I haven't heard that from other people, but if you ever need the .zip file just let me know and I can send it to you directly. I've been able to download the .zip after I post it using Firefox.
@SingleSparq I found that I needed to log in to the forums for the ZIP to be recognised as a downloadable file rather than a picture in Safari on my mac!
tatiangMember, Sous Chef, PRO, Senior Sous-ChefPosts: 11,949
I found that I needed to log in to the forums for the ZIP to be recognised as a downloadable file rather than a picture in Safari on my mac!
Once again, cheers for uploading your 'A Study of Loops v0.2 2' file, I've now managed to use parts of it in a project I am working on and it's made an enormous difference.
>-
tatiangMember, Sous Chef, PRO, Senior Sous-ChefPosts: 11,949
@Socks, you're welcome. As I wrote in the project file, I can't take credit for any of it, but I did decide to compile it in one place.
I wonder is there is any advantage/disadvantage to using 0.01 as opposed to 0.0001 as they both loop at the same speed, would 0.01 give the loop more time to execute its function/contents ?
You reach the theoretical limit of GameSalad at .015. (That's about 60 frames a second.) Anything less isn't going to speed up a processor that is set to fire at around 60 frames a second.
About the fastest loop GameSalad can achieve (using the method @ericzingler describes above) would be something like this:
When self.Time > self.oldTime --(Do your thing. Whatever it may be.) --Change Attribute: resetOldTime To: true
When resetOldTime is true -- Change Attribute: self.oldTime To: self.time -- Change Attribute: resetOldTime To: false
You reach the theoretical limit of the GameSalad at .015. (That's about 60 frames a second.) Anything less isn't going to speed up a processor that is set to fire at around 60 frames a second.
Got it ! So even though an iPad (for instance) can run a lot faster than 60 fps - GameSalad is set up to run at a maximum frame rate of 60fps ?
About the fastest loop GameSalad can achieve . . .
Yep, your example is pretty much what @tatiang had in his example. By the way, the limit of loop speed seems to sit somewhere around 0.013.
In the time it takes 0.008 to reach 10,000 iterations . . .
0.008 gets to 10,000 0.010 gets to 10,000 0.012 gets to 10,000 0.013 gets to 10,000 0.0135 gets to 9998 0.01355 gets to 9996 0.014 gets to 9994 0.015 gets to 9976.
Hey guys I've been trying to used this new timer method to replace my timed animation. I usually use two GS timer to do the animation. "EVERY" timer for generating random animation time, and "FOR" timer nested in it and run to completion checked to play the animation. I've been using this new method of timer to replace GS standard EVERY timer and nested the the new FOR method in it but its not working.
When I used the new EVERY timer alone the animation would stop prematurely (i'm using 6 images with 10fps/sec), this is also happened when i'm using GS EVERY timer, thats why i put another GS FOR timer to run the animation for a given time. Now i know that this new EVERY timer method doesn't support random formula directly and you must created another rules with attributes to store the random number, so i takeout the random number and use static number instead to no avail.
So how can that kind of nesting method of timers can be replaced with the NEW and improved timer? How can I select the frame rate of animation using this new timer method?
Comments
You can use a separate rule and an extra attribute to do this. Essentially you create a timer with a Boolean toggle rather than the actual code you want run, then place the code in a simpler rule toggled by the Boolean. Once the code you want run is completed (you may need to track this with another rule) you can toggle the Boolean off. As the Boolean cycles, your events are fired and are not limited by the cycling of the math timers themselves, which can in turn give your events enough time to run properly.
The following will allow you to loop extremely fast while also waiting for your instructions within the loop to complete:
2 Attributes:
1. timeStamp (real) = 0
2. loopSwitch (boolean) = false
2 Rules, + activator (optional):
1. Loop Rule:
If Self.Time > timeStamp
[Your instructions]...
@end of loop
Change attribute loopSwitch = 1
2. Loop Switch Rule:
If loopSwitch = true
Change attribute timeStamp = Self.Time + 0.005
Change attribute loopSwitch = 0
Activator:
If you don't want the loop to fire on actor start and want to start it with an action, change the loop condition to >=
example: Self.Time >= time.Stamp
Then, throw this in some other outside action:
Change attribute timeStamp = Self.Time + 0.005
Note:
I always use .005 as it seems fast enough, but it appears to work all the way down .00001.
New to GameSalad? (FAQs) | Tutorials | Templates | Greenleaf Games | Educator & Certified GameSalad User
The memory used by a single attribute is fairly small, especially compared to game assets such as graphics or sounds. In practice, the memory overhead of these timers is nearly negligible.
A pleasure to bringing this kind of quality to the community - Keep it up!
Electric brain wave to delve so deep into the core architecture of this baby and gettin us a refined way of speeding up our games man really. I am having one problem, the alternate mod way for creating the every timer works great when you use real numbers but when i try to fetch a number for timing using the rand function, the timer goes haywire and just does not time correctly.
For example, i am looking to spawn a character after a random duration of say 5-10 seconds. I have my mod1 set up to 0.05 sec. When i create a when mod1=self.time%rand(5,10) rule, several characters are spawned 1-2 seconds after the other. This is peachy if you use a static number which is say 5 seconds in place of the random function.
Try generating the random number outside of the rule.
So . . . Change attribute 'MyRandomNumber' to random (5,10)
Then . . . If mod1=self.time%MyRandomNumber . . .
The problem you are encoutering is caused by floating-point accuracy issues. Since you are feeding rand an integer value, it outputs an integer value. When we compare the integer to a very small number (this case, 0.05) the equation is never given a chance to flip between its on and off state. You might be able to fix this by simply stating rand(1.0,5.0), though I've had mixed results in practice. The best solution is modifying the mod value; as stated above.
Let me know if it works!
Domenius
@domenius That did not do it no, instead i saw three actors instead of just the two spawning at 1 second intervals between each other. Although i understand the anomaly and i would think that playing around with the mod would ultimately fix this irregularity but the @Socks way is quicker albeit at the expense of another native variable!
Thank you guys!
Adil
However, I tried the For Timer Workaround for an animation and the animation no longer animates. It works perfectly in the Timer Behavior, but not with this.
I wasn't sure why and it works for everything but animations.
Anyone have a solution for this or should I just go back to the For Timer Behavior?
But I'm not sure of this. Can anyone confirm?
if mod1 > self.time%.1
change attribute
self.size.width to 100-( self.Position.Y /9)
so that the actor gets smaller as it moves up the screen. I did this because I read that constrain is performance heavy like timers. My question is, is this way any better than using a constrain instead?
Yep, using this technique as a drop-in replacement for constrains is very efficient, and advised wherever possible!
New to GameSalad? (FAQs) | Tutorials | Templates | Greenleaf Games | Educator & Certified GameSalad User
@tatiang
Great stuff tatiang, really interesting stuff.
The 'time stamp' method seems like the way to go if you want very fast iterations, I noticed that changing the interval time from 0.005 to 0.00001 made it no faster, I'm guessing somewhere around 0.005 is this method's limit ?
Interesting stuff!
Just tested this, you are pretty spot on, the limit seems to be about 0.01 - I tested 0.015 against 0.01 (running at the same time) and it takes around 2,000 iterations before you see 0.01 pull very slightly ahead - so 0.01 seems to be number.
I wonder is there is any advantage/disadvantage to using 0.01 as opposed to 0.0001 as they both loop at the same speed, would 0.01 give the loop more time to execute its function/contents ?
New to GameSalad? (FAQs) | Tutorials | Templates | Greenleaf Games | Educator & Certified GameSalad User
New to GameSalad? (FAQs) | Tutorials | Templates | Greenleaf Games | Educator & Certified GameSalad User
Once again, cheers for uploading your 'A Study of Loops v0.2 2' file, I've now managed to use parts of it in a project I am working on and it's made an enormous difference.
>-
New to GameSalad? (FAQs) | Tutorials | Templates | Greenleaf Games | Educator & Certified GameSalad User
About the fastest loop GameSalad can achieve (using the method @ericzingler describes above) would be something like this:
When self.Time > self.oldTime
--(Do your thing. Whatever it may be.)
--Change Attribute: resetOldTime To: true
When resetOldTime is true
-- Change Attribute: self.oldTime To: self.time
-- Change Attribute: resetOldTime To: false
Cheers for the response. Got it ! So even though an iPad (for instance) can run a lot faster than 60 fps - GameSalad is set up to run at a maximum frame rate of 60fps ? Yep, your example is pretty much what @tatiang had in his example.
By the way, the limit of loop speed seems to sit somewhere around 0.013.
In the time it takes 0.008 to reach 10,000 iterations . . .
0.008 gets to 10,000
0.010 gets to 10,000
0.012 gets to 10,000
0.013 gets to 10,000
0.0135 gets to 9998
0.01355 gets to 9996
0.014 gets to 9994
0.015 gets to 9976.
When I used the new EVERY timer alone the animation would stop prematurely (i'm using 6 images with 10fps/sec), this is also happened when i'm using GS EVERY timer, thats why i put another GS FOR timer to run the animation for a given time. Now i know that this new EVERY timer method doesn't support random formula directly and you must created another rules with attributes to store the random number, so i takeout the random number and use static number instead to no avail.
So how can that kind of nesting method of timers can be replaced with the NEW and improved timer? How can I select the frame rate of animation using this new timer method?
Cheers! ;P