Announcement

Collapse
No announcement yet.

Tick vs. Timers

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Tick vs. Timers

    I've noticed that the general consensus on ticks is to never use them unless you can't get around it, and to use timers instead. However, my main concern with timers is when you have to constantly start and stop them. I'm guessing that using tick is better than timers in these cases as there may be some performance cost in starting and stopping them.

    An example scenario: I want to update the rotation of a character's mesh to face its velocity. Sometimes the velocity will not change, so the rotation will not change.
    Assuming that calculations are semi-expensive and do not just set the mesh's rotation to the direction of the character's velocity, would it be better to:

    1) Throw all logic into tick
    2) Throw all logic into tick, but add a check to only perform updates when mesh rotation does not equal the direction of velocity
    3) Start a timer with interval 0.1f whenever the direction of velocity changes, and end the timer when the mesh's rotation matches velocity

    #2
    In fact when you register a new Timer, some new UObject is created behind the scenes;
    However, you can reuse that Timer again and again, instead of spawning a new one every time...

    Tick will run forever (as long owner is still alive), but it's a better option if owner has short lifespan and the calculations inside Tick aren't outrageous.

    Never do #3.
    | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

    Comment


      #3
      • Tick() only runs if you enable it.
      • Setting off a Timer and starting/stopping Tick() is functionally equivalent.
      • The deciding factor is which code is more readable/maintainable.

      Comment


        #4
        So my understanding is that timers should be used for burst-based functions that don't need to always run, such as updating a projectile's position for a few seconds, while tick should be used for constant actions like updating a player's mesh to velocity direction. Based on this, I'm assuming using a timer that runs ~1/10 the amount of tick would be a better idea for a constant action where it isn't imperative that it's run every tick, such as a map that plots player positions.

        Thanks for the input

        Comment


          #5
          It's worth mentioning that you can change the tick rate of an actor. This is especially useful in classes like gamemode where you most likely won't be updating things every frame or so.

          Comment


            #6
            Question, Cannot find an answer for this any where!

            Which of the following would be more efficient on say an escalator moving? In this Epic training video to create an excalator he uses tick: https://www.youtube.com/watch?v=aqRUe7pm4Ok
            I have watched a few training Videos from Epic that say to never use tick because it is so inefficient. In the comments of one of the videos I asked what you are supposed to use for a line trace if you cannot use tick, but no one responded. I ended up changing my line trace to use Event Timer set to loop at second = .01, would it be better to use an Tick instead of the Event Timer? I changed the Event Timer to .1 but it was too sluggish and had to change it back to .01.

            1) Tick
            2) Event Timer set to loop at second = 1
            3) Event Timer set to loop at second = .1
            4) Event Timer set to loop at second = .01

            Comment


              #7
              Tick and event timers work more or less the same and should have the same efficiency. Tick and Timers are not particular inefficient by themselves but it is what you do with them that matters. You should think of ways to avoid constantly doing line traces or make the line trace as efficient as possible (limit the length, don't use multi-line, limit the trace channel object count etc.).

              Functions that are very demanding should be moved to C++ if they don't perform well enough in Blueprint or you could try to nativize the Blueprint.

              Comment


                #8
                Originally posted by BrUnO XaVIeR View Post
                In fact when you register a new Timer, some new UObject is created behind the scenes;

                What? This is completely wrong.

                Comment


                  #9
                  Originally posted by Zeblote View Post


                  What? This is completely wrong.
                  Code:
                  FTimerHandle  MyTimerHandle;
                  //  UStruct(BlueprintType) * Parent Class:  UScriptStruct -> UStruct -> UField -> UObject -> UObjectBaseUtility -> UObjectBase
                  
                  
                  const FTimerDelegate TimerDelegate = FTimerDelegate::CreateUObject(this,&UMyClass::MyFunction);
                  World->GetTimerManager().SetTimer(MyTimerHandle,TimerDelegate,TickRate,true);
                  Please, explain why "this is completely wrong".
                  | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

                  Comment


                    #10
                    FTimerHandle is a blueprint struct, so yeah, there's going to be a UScriptStruct to represent its reflection data - only a single one is ever created at startup.

                    CreateUObject method on delegates is used to bind a function on another UObject - so that it won't crash if this object is deleted. It doesn't create an object.

                    Comment


                      #11
                      Originally posted by Zeblote View Post
                      FTimerHandle is a blueprint struct, so yeah, there's going to be a UScriptStruct to represent its reflection data - only a single one is ever created at startup.

                      CreateUObject method on delegates is used to bind a function on another UObject - so that it won't crash if this object is deleted. It doesn't create an object.
                      Sure... the "another UObject" is some magic object that doesn't exist and is never created; I got it!
                      | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

                      Comment


                        #12
                        It's used if you want to bind a timer to a function on a UObject you already have, yeah? You can also bind timers to static methods if you want to.

                        Comment


                          #13
                          One important thing that should sometimes be considered is that the timer manager is updated each frame, likely *before* the object you've set the timer on has ticked. Can be important for finding syncronisation issues at times.

                          Comment


                            #14
                            Originally posted by BrUnO XaVIeR View Post

                            Code:
                            FTimerHandle MyTimerHandle;
                            // UStruct(BlueprintType) * Parent Class: UScriptStruct -> UStruct -> UField -> UObject -> UObjectBaseUtility -> UObjectBase
                            
                            
                            const FTimerDelegate TimerDelegate = FTimerDelegate::CreateUObject(this,&UMyClass::MyFunction);
                            World->GetTimerManager().SetTimer(MyTimerHandle,TimerDelegate,TickRate,true);
                            Please, explain why "this is completely wrong".
                            This function creates a delegate bound to a UObject, which is just a struct. It's so the delegate is garbage collecter aware.

                            Comment


                              #15
                              Hi All,

                              I've recently been trying out a workflow where I've avoided placing things in tick by running simulated ticks for certain mechanic states.

                              The workflow for each mechanic works as follows:

                              StartMechanic (called from input if criteria such as state is all good)
                              MechanicSimulatedTick (called once on end of Start Mechanic function, and then calls to self for next frame via SetTimerForNextTick) (once the mechanic is over, it just stops running).


                              I've found that there is a large behaviour difference between the logic when run via tick and run via SetTimerForNextTick.


                              For instance, my MechanicSimulatedTick sets the actor location each "simulatedTick". It's super choppy (despite delta seconds etc being correct).
                              If I then remove the call to it from start mechanic, and it's call to self (setTimerForNextTick) and call it from Tick instead (based on state system) - the SetActorLocation runs smoothly, no problems.


                              Why might this be the case? Surely they're both being run on tick. Is it a tick group error for the actor? I know timers are invoked before most of the updates, and by default an actor is ticked PrePhysics.

                              UPDATE: Looks like the issue might be that timers are invoked between PostPhysics and PostUpdateWork. This would mean that all my movement of the character during that invoked function is running after physics has already run

                              Seems like there should really be an option to specify when a SetTimer is run (choosing a tick group)
                              Last edited by AgentMilkshake1; 04-25-2019, 01:13 PM.

                              Comment

                              Working...
                              X