SYN TIP: A Great Substitute for an "after" Timer - Will Aid BIG in Optimization
synthesis
Member Posts: 1,693
This tip is NOT 100% confirmed with regard to increased performance...but it does appear to help considerably...plus it seems to be MUCH more reliable than a timer (which seem to misfire at times).
As you probably know...Too many timers can KILL an app on performance...especially a 3G or an iPod. Did you know you have a game timer?
If you didn't...its there. The game timer is a "quiet" background clock that initiates at the launch of your GS app and continues until the app is closed. You cannot modify it or do anything to it...its just there keeping time in 100ths of seconds.
Well...you can easily use that game.time value as a delay timer (aka...an "after" timer) quite easily and it works well and appears to really help in processing overhead on actors...especially if you are using lots of timers.
To replace the timer...you will need to do 3 things.
1) create an integer attribute in the actor called "markGameTime". This will be where you store a "grab" of the game time to use as a benchmark.
2) add a "change attribute" to wherever you want to "start the timer delay". In that behavior...set the "self.markGameTime" to ceil(game.time). I usually use ceiling but you can also use floor. You do need an integer attribute though...working within 100ths of a second is way too fast otherwise. The ceiling will take the time value and round up.
3) then...wherever you want the behavior(s) to execute after the time delay (the stuff you would originally have had in the timer), create a rule and in the rule say: when self.markGameTime = floor(game.time+5) [ 5 is the seconds delay amount...it can be any number value or an attribute value ]. Place your desired "delayed" behaviors inside this rule.
This also works really well for perfectly timed sequences. Like if you want something to happen after 1 second...then 2 seconds...then 3 seconds...and so on...lots of delay timed events...WITHOUT the timer overhead!!! And the sequences perform without a hitch.
Its really cool since I was having trouble getting a 3 second audio clip to match every 1 second timer rates (for 3 seconds)...since the processor sometimes stutters on them and the results tend to be less than perfectly synced.
The only time you cannot use this technique is if the interior behaviors for your rule trigger will need more than 1 second to execute or require the "run to completion" option in the timer. But I have found, about 90% of the time...you don't need that and this method is much faster for the game engine to process currently. One alternative is using a > comparison...but this can leave the timer switch open indefinitely...which may not be a problem if the actor has a short life span or will only execute the behaviors once...or if the timer sequence is wrapped within another rule switch.
Its a bit of a "dirty" work around, but it works well and the processor savings far outweighs the hassle of the setup...at least it did for me.
You may need multiple time marker attributes in an actor if you want to do more than one (meaning different unique starting times)...but that usually isn't too big a deal to incorporate.
Also, this doesn't give you a perfect time delay since you are rounding the time mark...but if your delay length variation tolerance is within 1 second...this will work nicely. Otherwise...if you need a perfectly timed delay...use a timer.
However, once the multi-ruled delayed sequences are started...the sequenced rules seem to fire flawlessly in perfect time with the game clock.
This could also be used as a substitute for a "FOR" timer by putting a < and a > comparison hi and lo boundary in the rule definitions. I have not tested this...but it seems that it should work logically.
Hope it helps!
Synthesis
As you probably know...Too many timers can KILL an app on performance...especially a 3G or an iPod. Did you know you have a game timer?
If you didn't...its there. The game timer is a "quiet" background clock that initiates at the launch of your GS app and continues until the app is closed. You cannot modify it or do anything to it...its just there keeping time in 100ths of seconds.
Well...you can easily use that game.time value as a delay timer (aka...an "after" timer) quite easily and it works well and appears to really help in processing overhead on actors...especially if you are using lots of timers.
To replace the timer...you will need to do 3 things.
1) create an integer attribute in the actor called "markGameTime". This will be where you store a "grab" of the game time to use as a benchmark.
2) add a "change attribute" to wherever you want to "start the timer delay". In that behavior...set the "self.markGameTime" to ceil(game.time). I usually use ceiling but you can also use floor. You do need an integer attribute though...working within 100ths of a second is way too fast otherwise. The ceiling will take the time value and round up.
3) then...wherever you want the behavior(s) to execute after the time delay (the stuff you would originally have had in the timer), create a rule and in the rule say: when self.markGameTime = floor(game.time+5) [ 5 is the seconds delay amount...it can be any number value or an attribute value ]. Place your desired "delayed" behaviors inside this rule.
This also works really well for perfectly timed sequences. Like if you want something to happen after 1 second...then 2 seconds...then 3 seconds...and so on...lots of delay timed events...WITHOUT the timer overhead!!! And the sequences perform without a hitch.
Its really cool since I was having trouble getting a 3 second audio clip to match every 1 second timer rates (for 3 seconds)...since the processor sometimes stutters on them and the results tend to be less than perfectly synced.
The only time you cannot use this technique is if the interior behaviors for your rule trigger will need more than 1 second to execute or require the "run to completion" option in the timer. But I have found, about 90% of the time...you don't need that and this method is much faster for the game engine to process currently. One alternative is using a > comparison...but this can leave the timer switch open indefinitely...which may not be a problem if the actor has a short life span or will only execute the behaviors once...or if the timer sequence is wrapped within another rule switch.
Its a bit of a "dirty" work around, but it works well and the processor savings far outweighs the hassle of the setup...at least it did for me.
You may need multiple time marker attributes in an actor if you want to do more than one (meaning different unique starting times)...but that usually isn't too big a deal to incorporate.
Also, this doesn't give you a perfect time delay since you are rounding the time mark...but if your delay length variation tolerance is within 1 second...this will work nicely. Otherwise...if you need a perfectly timed delay...use a timer.
However, once the multi-ruled delayed sequences are started...the sequenced rules seem to fire flawlessly in perfect time with the game clock.
This could also be used as a substitute for a "FOR" timer by putting a < and a > comparison hi and lo boundary in the rule definitions. I have not tested this...but it seems that it should work logically.
Hope it helps!
Synthesis
Comments
You can have more than one though but it may be at the cost of some FPS so i dont know.
you have to spawn an actor and use its self time that works just like the game timer then you can destroy or re spawn to start and stop. Problem is you of course have to constrain it.
I had to do this in my newest game but i didn't notice a hit at all.
I wish there was an easy way to consolidate some of the great tips and discoveries that have come up in this forum. Maybe somebody with some ambition (and free time) can start a independent GS blog.
There was a tip a long time back where someone suggested using time to get better random behavors that I thought was really brilliant.
[ EDIT ALERT ]
The rule comparison should say...
when self.gameMarkTime = floor(game.time-5)
[ my rule above says "+" which the markTime will never compare to...sorry about that ]
This allows the rule to compare a present GAME TIME to a future MARK TIME.
The way I have above doesn't work...as I found out this morning...guess I posted when I was too tired. :0
What a difference a plus make instead of a minus.
Sucks you can't edit posts later.
"You can have more than one though but it may be at the cost of some FPS so i dont know."
The game timer is always present...The game engine puts it there.
The point of this tip was to use the game timer instead of adding NEW timers. This means NO FPS damage...instead of FPS damage with multiple timers...since you are using the same GAME clock for all your "after" timer sequences.
Hope this clarifies.
I just meant in addition each actor also has its own timer separate from adding a "timer" into it. So you can get a way with using that to change an attribute so that you can have a rule without having to add a timer inside of it it. . Handy for actors that have to spawn and do something one time right away. Just dont know if it changes much but, i too am always looking for a way to avoid a few behaviors. Thats all i meant
Right...but it appears in initial testing that the self.timer or game.timer is present regardless at part of their game engine overhead...and using them should save FPS no matter how many times you tap into them. You shouldn't need to use constrained behaviors to utilize them...since they are already constrains in a sense and are running in real time.
Just grab them or borrow them as necessary and use a timeMark attribute and a rule to set up a "seudo-timer". This practice...if used regularly instead of incorporating the bloated timers...should make your game much quicker and more responsive...as well as more reliable.
You can also use this method to create a fake Every timer. Here's the math do do something every 2 seconds:
When game.time = self.marktime+(Floor((game.time-self.marktime)/2))*2
Here's an example of an Every 5 seconds do behavior For 1 seconds timer:
When all conditions
game.time < (self.marktime+(Floor((game.time-self.marktime)/5))*5)+1
game.time > self.marktime+(Floor((game.time-self.marktime)/5))*5
If the developers at GS were really smart, they would all just do this automatically. Timers wouldn't actually be timers, just static variable comparisons.
>> (and free time) can start a independent
>> GS blog.
>> design219
Are people really interested in that? Why go to a blog when you can just go here? I started a Game Development section at my website and I posted a few articles about GameSalad...
http://photics.com/tag/gamesalad
...but I hesitate to make it a regular thing. I ran a Guild Wars fansite for about six years. I'm a bit burned out from that, so I'm not sure I'd want to get involved in something like this... but I have been considering it.
>> This tip is $$$$$$$$$$
>> $$$$$$$$$$$$$$$$$$
>> $$$$$$$$$$$$$$$$$$
>> $$$$.
Is it really? I don't see any FPS comparisons.
Note: I'm not trying to be negative. This tip and a GameSalad blog could be awesome.
(now that they lifted my temporary ban because of yesterday's thread...I will try to post more when I have them
@Wombat...
I can't speak for how smart the developers at GS are...but it sure seems like there would be lots of ways to optimize the game engine better...you solution being one of them.
You must have missed what I was saying, I was talking about a consolidation/indexing of tips. There is a lot here, but damn if you try to find it. Most tips don't have good titles to threads like this one, they ususally just come up in the middle of a thread. And try searching for something... if this thread was 3 months out of date, what search term would you use?
We've got something in the works along what you are saying...we'll keep you posted. Right now we are focused on our BDX game wrap up.
By the way...
I switched to using a <= comparison (without the floor) sometimes rather than = to floor...
This allows it to be more accurate in its triggering and functions more like a "run to completion" timer. You just have to make sure its in a switch wrapper and the behavior that are executed are not going to cause problems if they are left "exposed" after the suedo-timer is run.
I've pretty much all but quit using the timer behavior because it is WAY TOO damaging to the processor with the game engine in its current state (hence my recent frustrations).
Isn't puting a timer behaviur the same as puting "when" behaviur?!
After all- a timer tells the CPU to do something every period of time.
And a "when" behaviur tells the CPU to check if the process inside "when"
should run---and the checking process hapens every period of time.
Do I make any sense ?!
You are Correct in your statement...
The tip above however is a substitute for the timer behavior because timers (if used too often) will bog down your game processing and use excessive RAM/FPS. The solution above is a "workaround" which will allow you to have many more "suedo-timers" than normal timers and use less processor.
Timers in general are very heavy to process...but if you are only using a few...this workaround may be more trouble than its worth...but the above tip...is MUCH lighter on the game engine to process...since you are borrowing the game timer which is already running in your game...rather than adding a new clock to process each time you add a unique timer behavior.
in short...
5 rule timers = 1 clock (using the game clock = 0 additional processing...since the game clock is already running)
5 timer behaviors = 6 clocks (1 game clock + 5 timer clocks = 6x the processing demand)
The the same project with Syn's method implemented. That would reveal a pretty good test of how many more FPS you may be able to eek out of this method.
I can't believe it would be too many more since the implementation of their timers internally in the engine is probably similar. There may be some overhead on interpreting which type of timer of the three it is but there may be some behind the scene optimization going on that groups similar timers together and such.
Hopefully there is some benefit but it would be good to have proof! ;-)
i will just add that timers, when used, should be thought of as spawning a new thread and all the overhead that goes with that. that's why they are expensive. but also, they can be really useful because they continue executing even after the branch that triggered them has exited.
Unless I'm not understanding what your saying (always a possibility