Clock Class and Player Boost


September 26th, 2024

Hello! Today, I'll be covering my Clock class. This class will help me perform "over-time" effects. 

This class will allow a function to be called every tick for a duration, which I'll call Tick functions. I'll also support calling a function once after a duration, which I'll call Delayed functions. 

Supporting Structs

TimerData

TimerFunction

This is the signature for functions the clock will accept. 

EntityDelay/Tick

The finalTickFunction will be called right before the timer is deleted. This is added because it isn't guaranteed that the tickFunction will be called right at the end of the timer's duration. An example will be in the Demonstration section. 

Tick/DelayVector

The clock will keep two separate maps of these "vectors". We make vectors of these in case an object wants to set multiple function timers. Admittedly, these aren't great type aliases, but I couldn't think of anything better. 

Clock

Here are the members:

Like the KeyboardController, we'll use the EntityID as the Key here. If an Entity is deleted and it has a timer associated with it, the Clock will remove that timer. The IDCounter is used when a timer does not want to associate with an entity. We start with -1 because Entities have IDs that are always greater than or equal to 0. 

Onto the functions. Most importantly, we need to get the time. We can do this by calling SDL_GetTicks64(): 

This function returns the milliseconds by default, so we need to divide by 1000 to get the seconds. 

Here are my functions for setting timers.

The parameters are pretty self-explanatory, so I'll only explain a few. The tickNow variable is only relevant if an interval is specified. If tickNow is true, we'll call the function on the 1st update. There are only some cases where we'd want a finalTickFunction, so I created an overload for it. These will insert a value into their respective maps. 

The implementation is straightforward, we fill out the value at the correct key. 

If an object isn't specified, we'll use one of the negative IDs. 

Now for calling the functions, we'll call HandleTickFuncs every frame. I have a version called HandleDelayedFuncs as well, but the implementation is similar, so I won't cover it. This is a long function so I'll walk through it piece by piece: 

Here, we loop through every object's vector of timers. If the startTime was set to 0, we'll start it right now. If the startTime is in the future, we can ignore it. 

We check if the timer has ended. If it has, we'll call the finalTickFunction if it's valid, and erase the entry from the container. 

The tickNow variable comes into play if an interval is specified. We store the time in lastInterval so we call the function at the correct rate.

And finally, outside of the nested for loop, we'll see if the current Entity has any other Tick functions. If not, we'll remove it from the list. 

Demonstration

Now let's see it in action. A primary mechanic in my game will be dodging enemies. If you dodge an enemy at the right time, you'll gain a burst of speed and not take damage while touching them. I want that speed boost to decrease over time until the player is back at base speed. I'll also change the player's color to visualize the boost.

I'll add these member variables to my Player: 

The mSpeedIncreaseDuration is how long the player will stay at max speed. mSpeedDecrease is how long it takes the player to return to base speed. The color mod is a shade of blue, which will get mixed into the player's texture for a visual effect. 

I'll set up all the boost functionality in a function called TryPerformBoost. After confirming the player can boost, the actual boost begins. 

I want the burst of speed to be instant, so I'll directly override the player's speed.

Now I'll create a lambda for slowing down over time: 

Ah, the Lerp function. A game programmer's best friend. By using lerp, we can smoothly move from our max speed back to base speed over "mSpeedDecreaseDuration" seconds, which is 1 second in this case.

We'll also create a function for when the boost has ended: 

Here, we reset to the base speed, just in case the tick function didn't completely reset the speed already (same with the color mod). 

Now we just need to set the timer:

 

Since we want the speed boost to last for a bit, we delay the start time by mSpeedIncreaseDuration seconds.

Here's the boosting in action. I've set it up so that when the player collides with the white box (the enemy's collider) and presses a button, that's when a boost can happen. 

 

Conclusion

Now that the Clock class is set up, I can start doing some more gameplay-specific stuff. The player boost was only the beginning. I'm not sure what I'll be working on next, but I'll be sure to keep updating!

Thanks for reading,

Jamari

Leave a comment

Log in with itch.io to leave a comment.