Timers are for chumps - GS optimization tips

12346»

Comments

  • SnapFireStudiosSnapFireStudios Member Posts: 1,603
    @RThruman - Yeah! That changes... everything...
    Sorry, how is that helpful? :P
    - Thomas
  • RThurmanRThurman Member, Sous Chef, PRO Posts: 2,879
    @SnapFireStudios -- perhaps I got a little excited and overstated things a bit. But it is helpful to know that Boolean logic is available at the expression level. Its an extra capability that comes in handy. And besides, I like learning something new about this amazingly easy, yet incredibly versatile tool called GameSalad.

    I will probably delete this and the previous three comments in a while. (I didn't mean to hijack the thread.)
  • tatiangtatiang Member, Sous Chef, PRO, Senior Sous-Chef Posts: 11,949
    Wowsers! @ORBZ, I didn't realize that the expression editor could read Boolean operators. This is really cool! (I didn't make it to the yellow actors yet. I was floored with "not( game.Increment )" in the controller actor).

    Boolean logic at the expression editor level changes everything!
    What?! Example, please...

    New to GameSalad? (FAQs)   |   Tutorials   |   Templates   |   Greenleaf Games   |   Educator & Certified GameSalad User

  • ORBZORBZ Member Posts: 1,304
    I moved this post to the fast for loop. That's where I meant to post it originally. I updated the example to be faster than the original post I made here.

    However, the new example doesn't use a controller so it's no longer needed to do a flip flop with the bool.

    Moved to: http://forums.gamesalad.com/discussion/55050/fast-for-loop-a-collection-from-the-community-merged-into-a-single-really-really-fast-loop#latest
  • ORBZORBZ Member Posts: 1,304
    Oh, and if you were wondering:

    Not() is an undocumented function that you can use to negate a bool. ONLY a bool. Doesn't work on other data types.
  • tatiangtatiang Member, Sous Chef, PRO, Senior Sous-Chef Posts: 11,949
    Oh, and if you were wondering:

    Not() is an undocumented function that you can use to negate a bool. ONLY a bool. Doesn't work on other data types.
    Okay, thanks for the explanation.

    New to GameSalad? (FAQs)   |   Tutorials   |   Templates   |   Greenleaf Games   |   Educator & Certified GameSalad User

  • WbokoWboko Tennessee, USAMember, PRO Posts: 621
    After reading this it make a huge difference in a game idea I had left alone because of the amount of timers need to make it work...I feel a game of the month coming up!!!...LOL

    Thanks @domenius!!!
  • SnapFireStudiosSnapFireStudios Member Posts: 1,603
    Oh, and if you were wondering:

    Not() is an undocumented function that you can use to negate a bool. ONLY a bool. Doesn't work on other data types.
    Sorry, what do you mean by "negating" a bool? I know what both words mean, but are you just saying that it changes the bool to false or something? :-/
    - Thomas
  • MantoManto Member Posts: 796
    edited May 2013
    @SnapFireStudios Negating a boolean means changing its value to the opposite one.

    If the boolean is true, negating will make it false.

    If the boolean is false, negating will make it true.


    Here's also the wikipedia page about negation http://en.m.wikipedia.org/wiki/Negation

    I hope that helps.
  • SnapFireStudiosSnapFireStudios Member Posts: 1,603
    edited May 2013
    @Manto1 - Got it, that really could be useful..
    - Thomas
  • mataruamatarua Auckland, New ZealandMember Posts: 854
    Late to this gold mine. Thanks for all the hard work!
  • The_Gamesalad_GuruThe_Gamesalad_Guru Member Posts: 9,922
    Hmmm so especially using not() in an expression one might be able to build an array using a rule.
  • HymloeHymloe Member Posts: 1,653
    Have looked at it a bit already. There are some clear issues that need to be resolved. Have noted the issue for more work soon.
    Is there any chance that we might one day see the performance of the Timer rule reaching the same sort of performance level of using the game.timer and self.timer approach instead?

  • pHghostpHghost London, UKMember Posts: 2,342
    edited November 2013
    @domenius

    Thanks for this! Great advice, especially breaking it down, so it is actually possible to understand what is going on there.

    I actually built my own every "timer," based on the theory. It goes like this --

    First off, set up two actor attributes: cycle_length and cycle_counter.

    Then create a rule:

    when self.Time = self.cycle_counter
    [do what you want to do]
    change self.cycle_counter to: self.cycle_counter+self.cycle_length

    Set cycle_length for the duration of "every" and cycle_counter for the initial time offset, if you want (especially great for spawners, so they wait a bit before starting to work).

    Looking at this approach, do you think it is as efficient as yours, or should I dump it? This came as an idea when reading your post, but I'm not sure whether the calculations happening under the surface are simpler or not.
  • lpalmierilpalmieri Member, PRO Posts: 5
    Thanks for the tip. It works great, I'm never using timers ever again :)
  • KovaKova Member Posts: 5
    edited October 2014

    Hello, thanks for amazing tips (in fact tutorial), but I don't understand how to do this " In fact, I recommend using these sorts of timers for animation instead of the standard animate function, it seems to play smoother and being able to adjust the animation parameters at runtime can be particularily useful for complex actors."

    How to make animation with self timers, etc, how to replace GS Animation? (lets say you have 50 images for animation), thanks in advance.

  • LoadedLoaded Member Posts: 240

    Website » Twitter » Facebook » Loaded Arts - Fun for thumbs.

    Developer Blog » 08/01/2015 - Week 72 – Apple, the great dictator…

  • domeniusdomenius Member Posts: 108
    edited October 2014
    Hey all (specifically @Kova), the question of how to use this method of fast looping for animation has been one of the most common questions I have received since I first made this post, and until now I have not fully diverged the secret of how I do it. At first, I purposely left it vague as this is a topic I discuss in my book, GameSalad Master Class, and I didn't want to give ALL of my secrets away :). However, I feel that it is time to clarify exactly what I meant in the original post and give you all a full glimpse in on my technique for performing animation at optimal framerates using this method of looping. The following tutorial is a direct excerpt from my book (it may reference images and content from the original book that is not fully present here, but all the information you need to take advantage of this method is present) and should help to clarify the exact means that I use in my own projects to achieve ultra smooth animations that are capable of reaching a full 60fps. Of course, this full chapter of information adorned with graphics is available in my book (among many other advanced GS tips and techniques), which can be purchased from the following link: https://gumroad.com/l/gsmclass

    Before we jump in, I just want to explicitly state just how bad the default GS animation behaviour is. Not only is it highly limited in its capabilities to provide robust support for advanced animation, it is highly prone to inconsistency among frame playback speed even when you are working within the 30fps limit of the default animate behaviour. This is one area where the GS team has made zero effort to improve GameSalad since as long as I've been using it; and given its poor capabilities I would have expected someone to have done some sort of overhaul on it by now. Anyways, without further adieu, here is everything you need to know about using pseudo-loops to create robust, accurate, and extremely fast animation with vastly improved performance over the default GS functions.



    11.8 Animation Using Timers

    For the creation of animated actors, GameSalad includes a behavior called Animate. This behavior allows you to specify a series of frames to be played in sequence at a specified speed, in FPS. The Animate behavior included in GameSalad is very glitchy, for lack of a better term, and does not lend well to high-quality animation. It tends to skip and stutter oddly, reducing the quality of your animated assets despite your best efforts to use the pre-built functions as they are intended to be used. Luckily, there is a way we can create our very own animate behavior which performs better, looks better, and allows a higher maximum FPS than 30 (which is the maximum of the included behavior).

    To emulate animation as efficiently as possible, we make use of a rule-based "every" type timer, as described in the previous section. For this example, we will set our mod attribute to 0.05 and our modulus value to 0.1. The equation in our timer rule looks like so: when mod1>self.time%0.1. In addition to this, we create a new integer attribute called frame. We use the frame attribute to keep track of what frame of animation to show to the user. Inside the timer rule, we place two change attribute commands, one which increments our frame attribute (self.frame = self.frame+1) and one to apply the proper frame to our actor.

    Applying the proper frame makes use of careful asset naming, combined with string concatenation. As previously mentioned, to make use of this optimization all the frames of an animation must have the same name and be sequentially numbered. Because of this correlation, we can simply force GameSalad to apply a new image with each tick of our timer using the following Change Attribute: self.image to [imagename] .. self.frame .. ".png". When we use concatenation to force GameSalad to apply an image, we must add the .png extension manually as demonstrated. Now, we wrap this rule in a second rule, which stops playing the animation when our final frame is reached. To do so, simply state when self.frame =/= [maximum frame].

    The example above would play a new frame every 0.1 seconds, effectively creating animation at 10 FPS. To adjust the FPS, the value after the modulus operator (%) may be adjusted. In practice, if you need to play animation any faster than 10FPS it is better to duplicate your two Change Attribute behaviors into the otherwise section of your timer rule. This effectively doubles the FPS by switching the image during both the on and off state of the timer. When doing so, make sure your mod attribute value is exactly half of the value placed after the modulus in your equation, or the animation will play unevenly. This optimization can also be used with looping animations. To do so, simply add a Change Attribute in the otherwise section of the rule stating when self.frame =/= [maximum frame] resetting self.frame to 0, creating a looping behavior.

    Depending on your needs, feel free to manipulate the frame number as you see fit. Through advanced modification of your self.frame variable, various types of animated content can be made with relative ease. For example, the animated character illustrated to the left has 24 total frames, grouped into sets of 6 frames for each cardinal direction per row. Knowing this, we can set the animation start frame for each cardinal direction at the appropriate spot, often called a keyframe, and play the next 6 frames looping in sequence. Create an integer value, I've called it keyframe, to hold this information. Modify our containing rule (self.frame =/= [maximum frame]) to state: when self.frame =/= self.keyframe+6. Next, modify the Change Attribute in the otherwise section of this rule to state: self.frame = self.keyframe. In this example, when the player moves right, we would set the self.keyframe to 18 and effectively play frames 18,19,20,21,22,23; then loop back to 18, repeating until the player is no longer moving right. The same concept applies for the other three directions. All that needs to be changed is the self.keyframe value to pick a different set of animations. In this example, the keyframes are: 0, 6, 12, and 18.



    Hopefully this information should help to set you on the right path :).

    Domenius


  • I_AM_BENJII_AM_BENJI USAMember Posts: 40

    so i have a attribute and i have i in a timer right now. so to fix that would i simply do
    mod1>self.time%(attribute)

  • IodineIodine Member, PRO Posts: 3

    This saved me so hard. I cannot tell you how much I appreciate this. Thank-you, thank-you, thank-you, thank-you. I will pay it forward.

  • phamtasticphamtastic Member, PRO Posts: 354

    OMG!!! I think you just save my project as it's very heavy timer based and hitting performance issues with medium and low end devices. Can't wait to try this ASAP. Thank you so much!!!

  • domeniusdomenius Member Posts: 108

    @Iodine @phamtastic Always glad to hear success stories; Nice to know that even now this post is still helping people :)

    @I_AM_BENJI This reply is a bit late but yes, you have the right idea.

    Domenius

  • phamtasticphamtastic Member, PRO Posts: 354

    @domenius - Is this timer technique still valid for optimization from when you originally posted it? Did GS make any crucial updates on timer func since the original post from back in 2012?

    Phamtastic

  • colandercolander Member Posts: 1,610
    edited February 2015

    @CodeWizard said:
    Have looked at it a bit already. There are some clear issues that need to be resolved. Have noted the issue for more work soon.

    Yes I agree with @phamtastic would be nice to have an update even though there have been improvements and @CodeWizard post is nearly two years old :).

  • domeniusdomenius Member Posts: 108

    @ phamtastic As far as I know, the GS team has still failed to update the timer code to operate faster than the "trick" I have outlined in the original post. That said, GS itself has become faster than it was back when I originally posted this code. Even so, I still use this technique whenever possible to optimize advanced projects with complex code. You can get away with having a few "classic" timers in your code with minimal impact, but this technique is still very relevant to anyone trying to create advanced code or a project which requires a vast number of time events. For example, AI code can often benefit hugely from this technique since you are usually dealing with many actors that are making many decisions based on constantly repeating procedures. Even with the advances made by the GS team in recent times, this technique is still relevant in many cases.

  • phamtasticphamtastic Member, PRO Posts: 354

    @domenius - thanks for clarifying. I am making a huge project over 600 actors and with 40% of them using some sort of timer. Wish I read this post early :)

  • winged_boxwinged_box Member Posts: 52
    edited March 2015

    Please help, I want my splash image to change forth and back every 1 second.

    I set the below rules and the first 2 seconds it changed back and forth properly but after that it is like turbo changing in 0.1 second.

    Page 1:
    image

    Page 2:
    image

  • tatiangtatiang Member, Sous Chef, PRO, Senior Sous-Chef Posts: 11,949
    edited February 2015

    I'm kind of a proponent for using built-in systems unless they don't work for me. This thread was started three years ago when the codebase for GameSalad was considerably different. Yes, you can optimize your code by swapping out Timer behaviors but unless they seem to be causing problems, why not just use them?

    Timer every 1 second
    .....Change attribute self.counter to self.counter+1
    .....Change attribute self.Image to "Title2."..self.Counter

    That will cycle through images named Title2.1, Title 2.2, Title 2.3, etc.

    If you just want to cycle between two images, use the mod() function:

    .....Change attribute self.Image to "Title2."..mod(self.Counter,2)+1

    New to GameSalad? (FAQs)   |   Tutorials   |   Templates   |   Greenleaf Games   |   Educator & Certified GameSalad User

  • winged_boxwinged_box Member Posts: 52

    @tatiang said:
    I'm kind of a proponent for using built-in systems unless they don't work for me. This thread was started three years ago when the codebase for GameSalad was considerably different. Yes, you can optimize your code by swapping out Timer behaviors but unless they seem to be causing problems, why not just use them?

    Timer every 1 second
    .....Change attribute self.counter to self.counter+1
    .....Change attribute self.Image to "Title2."..self.Counter

    That will cycle through images named Title2.1, Title 2.2, Title 2.3, etc.

    I just want to try out the method since it will help to enhance the performance.

  • tatiangtatiang Member, Sous Chef, PRO, Senior Sous-Chef Posts: 11,949

    An even simpler method than a Timer is to use an Animate behavior with two frames and Loop set to true. I'm a bit confused by the way you have your custom timer set up. If it's helpful, you might want to check out my Study of Loops demo that shows various ways for creating fast loops (although they could slowed down for every 1 second type timers):

    http://forums.gamesalad.com/discussion/comment/381275/#Comment_381275

    New to GameSalad? (FAQs)   |   Tutorials   |   Templates   |   Greenleaf Games   |   Educator & Certified GameSalad User

Sign In or Register to comment.