C++ Timer, Call Function every seconds

If the timer is replicated properly and reliably then it will be synchronized. Although replication isn’t always 100% reliable and it would need abit of testing but nonetheless you’re likely better off using timers with conditions to fit your needs.

Wolfsblut,

Yes, that is right. Doing slow things inside of a tick will slow down the game. However, doing slow things in timer delegates will also slow down your game. Try to avoid doing slow things anywhere in the main thread.

Thanks for spreading some knowledge Fred K,

I have been starting to use timers more often now, but now I have a few questions about timers and replication.

Can and should timers be replicated?
How often will this be sent across?
How would one would go about doing such thing? Will replicating the FTimerHandle suffice?
For client verification checks and HUD updating (like a progress-bar), will it be better to just start a timer on the client as well instead of constantly replicating it?

As an example, lets say I have a bomb that once triggered starts a 15 second timer, after which it explodes. This could be done simply by having a timer on the server and only notify the client about the explosion. However I want the player HUD to have a progress-bar that shows countdown progress, which means the client needs to know the constant progress.

Should I be constantly replicating the timer, or just create a local timer as well to “emulate” the server timer. The “emulation” should be fairly accurate (minus the latency).

So i’m a bit of a c++ noob, there is probably a way cleaner way of doing it, but with regards to the very first post of this thread (i’ll be honest i didn’t read the rest), could you do this? Note that i’m asking purely to see if there’s an easier way (so i can learn).



//member variables
bool bTimerActive = false;
float mTimer = 0.f;
float mTimerEnd = 0.f;

//tick function
void MyClass::Tick()
{
   Super::Tick(DeltaSeconds);

   //check whether timer is active
   if(bTimerActive)
   {
      //check if timer is 1 second along, but less than the 5 second timer
      float Timer = mTimer + 1.f;
      if(mTimer == Timer && mTimer < mTimerEnd)
      {
         //run function
         Function()
         //set timer again so this function will re-run in another second.
         mTimer = GetWorld->GetTimeSeconds();

         //turn off the activator if time goes beyond 5 seconds.
         if(mTimer > mTimerEnd)
         {
            bTimerActive = false;
         }
      }
   }
}

//Timer event, let's say it's activated by a button push for sake of argument
void MyClass::Event()
{
   //set timer 
   mTimer = GetWorld()->GetTimeSeconds();
   //set time end
   mTimerEnd = GetWorld()->GetTimeSeconds() + 5.f;
   //enable ticker
   bTimerActive = true;
}


There are a few problem I can see in that code:

  • first your MyClass::Tick() function takes float as an argument, which I assume its the DeltaSeconds variable
  • since “Timer = mTimer + 1”, it will never pass the condition “mTimer == Timer”, so it will never go inside the “if”
  • mTimer is never actually updated
  • you appear to be under the assumption that Tick is called once per second. Tick is called once per frame, so if you 30 fps its called 30 times in that one second.

If you want to use the tick function instead of a Timer (this was discussed, but you didn’t read it), you could do something like this:


//member variables
float ElapsedTimeMini;
float ElapsedTimeFull;
float Period;	
float TimerEnd;

//class constructor
MyClass::MyClass(){
   //Assuming you are not doing something else on tick, you can just disable tick instead of having a variable
   PrimaryActorTick.bCanEverTick = true;
   PrimaryActorTick.bStartWithTickEnabled = false;

   ElapsedTimeMini = 0.f;
   ElapsedTimeFull = 0.f
   Period = 1.f;	
   TimerEnd = 5.f;
}

//tick function
void MyClass::Tick(DeltaSeconds){
   Super::Tick(DeltaSeconds);

   ElapsedTimeMini += DeltaSeconds;
   ElapsedTimeFull += DeltaSeconds;
   if (ElapsedTimeMini >= Period){
      FunctionYouWantToCallEveryPeriod();
      //we subtract the Period, instead of setting it to zero so it is more accurate
      //example if ElapsedTimeMini is 1.2, setting it to zero would make us lose 0.2 seconds
      ElapsedTimeMini -= Period;		
   }
		
   if (ElapsedTimeFull >= TimerEnd){
      //disable and reset variables
      SetActorTickEnabled(false);
      ElapsedTimeMini = 0.f;
      ElapsedTimeFull = 0.f;
   }
}

//Timer event, let's say it's activated by a button push for sake of argument
void MyClass::Event(){
   //enable tick on the actor
   SetActorTickEnabled(true);
}

I do this by starting a timer on the server which updates a replicated variable (the time left on my countdown). I don’t replicate a timer, just the variable the timer updates. Then I just bind this variable in a UMG widget, so all the clients can display it in their UI.

I’d avoid replicating timers. If you look at how we’re currently generating timer handles you can see that they’re unique per machine so you’ll run the risk of having multiple timers with the same handle if you try this. For your bomb example you could start separate timers on both the client and server. The client timer could have no delegate but still be queryable via the handle for UI. You could also use the same code for both timers but have the delegate contain a check so that it will only do the real work if it’s on the server. Syntaks suggestion will also work but running timers on each machine will reduce the network traffic.

Almighty_gir,

I haven’t had a chance to look at your code closely but I’d suggest you use the timer system instead of ticking your class for this. There are some explanations for why you should do this in the rest of this thread.

Timers tick independently of one another, they aren’t synced over the network and doing it would likely throttle your connection. You want to look at ‘Lockstep’ programming, not using Timers. Starcraft uses a Lockstep system.

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