The “Do After” Dilemma : Building Your Own Time Tracking Mechanic

What’s wrong with this logic?

Timer 1

Looks simple enough, doesn’t it? Imagine a hypothetical situation where you have some sort of player actor who can do something like curl up into a spiked ball and attack. Accordingly, we want the actor to display a “Spin Attack” animation for that particular move and then go back to normal (the other details such as movement are not important to us right now).

But let’s timeline some scenarios here. The numbers listed out below will reflect seconds that have passed and the actions occuring at those points. Let’s say when we “attack”, that is when the animation change occurs.

Scenario A : Attack

0s -> Push button; animation changes to “Spin Attack”
1s ->
2s ->
3s -> Animation changes to “Normal”

Scenario B : Attack and then five seconds later attack again

0s -> Push button; animation changes to “Spin Attack”
1s ->
2s ->
3s -> Animation changes to “Normal”
4s ->
5s -> Push button; animation changes to “Spin Attack”
6s ->
7s ->
8s -> Animation changes to “Normal”

* * * * *

So far, so good. But now let’s say you want the player to be able mash the button repeatedly, allowing them to spin attack repeatedly.

Scenario C : Mash the attack button for one second

0s -> Start mashing button; animation changes to “Spin Attack”
1s -> Stop mashing button
2s ->
3s -> Animation changes to “Normal”
4s -> Animation changes to “Normal”; no change technically occurs
5s ->

* * * * *

Your spin attack, or at least the animation, still only lasted for three seconds. Why? Because each time you hit the button, you are firing off another “Do After” timed event. The problem is none of those “Do After” events, for all practical purposes, know about each other. The first event is still going to try and set the animation back to “Normal” after three seconds, despite the fact we wanted to continue the spin attack animation beyond three seconds.

This problem may be more common than you think. What if the player can perform a different move, like a follow-up combo move, that cancels out of the spin attack and go into a new attack? That “Do After” event is STILL going to try and change your animation back to “Normal” after three seconds.

* * * * *

This tutorial will introduce you to a more robust way of handling time-sensitive situations like these. With a little legwork and creative coding, you can keep your character from dilemma such as animation spaz-outs, just to name one. We are going to build our own timer that you can inject into your
behaviors as you see fit.

STEP 1 : Set up your attributes

So what kind of attributes do we need? This can vary depending on the functionality. For this tutorial, we will use two core attribute. First, one that is non-hidden :

—Timer Duration (Number) : How many seconds do we want to put on our timer? This can be determined many ways and not just through setting it in the Behavior Pane of an actor. For this particular tutorial, I felt this would be the simplest way to understand.

And one attribute that is hidden:

—Countdown (Number) : This is our stopwatch attribute, if you will. Its part of how we will manually track time instead of what you saw above.

STEP 2 : Determine your entry condition and default time

That is, what will trigger the timer? Second, once you’ve done this, what are we going to set the timer to?

In this tutorial, our entry condition will be a mouse click and the timer (Countdown attribute) will be set based on our default in the attribute Timer Duration.

Timer 2

STEP 3 : Building the timer

Believe it or not, we actually are going to use a “Do Every X Seconds” event in our timer! But don’t worry, we are going to keep it under control. Its going to function as a way for us decrement the value inside of Countdown. So let’s add one of those.

First, our timed loop needs to decrement Countdown for every run of the loop. Second, it needs to stop once it gets Countdown to 0, in which case we will cancel out of the loop. Simple, right?

Now, the whole point of this is to make sure timed events DON’T cause problems among themselves. And what better way to do this than making sure we only have one timed event? In order to prevent a second “Do Every X Seconds” loop, we are going to enclose this whole section in a conditional that only executes if the Countdown attribute is equal to or less than 0 (the “less than” part is a sort of fail safe; if for some reason the timer does fall below 0, having “less than” prevents the timer from just flat-out “breaking”).

Timer 3

STEP 4 : Timer management and repeat commands

Right now, this doesn’t accomplish much outside of our original scenario. All it does different is prevent a repeat action by being a little fancy. But that would defeat the purpose of the tutorial. We WANT repeat commands to be able to do their jobs, all while not messing each other up.

This is where the beauty of the Countdown attribute comes into play.

Let’s add an “Otherwise” statement to the end of our “If” statement. Now, when a repeat command comes in, just set the timer back up to its default. Voila!

Timer 4

“Do Every X Seconds” just keeps going about its business. And the way it is structured right now, it will just keep on chugging until it finally gets that Countdown attribute to 0. Your button mashing can actually produce that repeated result you are looking for! Woohoo!

And there you have it. A more powerful timer for your behaviors. That being said, I think this still deserves a bit more elaboration (and I highly suggest you read the second extra section).

* * * * *

EXTRA 1 : Bells and Whistles

Again, the beauty of this set-up is the Countdown attribute. There are a lot of ways to manipulate this timer.

For instance, what if you have a timed challenge in your game where the player can collect time bonuses? Just have your code add those bonuses to the Countdown! Or maybe you have a time bomb, and the player just accidentally stepped on a trap that detonates it instantly. Just set Countdown to zero and let the fireworks commence. That kind of stuff isn’t quite so easy if you are using a straight “Do After” event.

There are a lot of things you can do. That’s why I think this form of time management can be very powerful!

EXTRA 2 :  Precision and Changing The Intervals

SERIOUSLY! PLEASE READ THIS PART!

For the tutorial, I decremented the timer in one second intervals. However, this is not very precise. Let’s timeline one more scenario:

Scenario D : Press the command and then 1.5 seconds later, press it again.

0.0s -> Command used; Countdown set to 3
0.5s ->
1.0s -> Countdown decremented to 2
1.5s -> Command used; Countdown set to 3
2.0s -> Countdown decremented to 2
2.5s ->
3.0s -> Countdown decremented to 1
3.5s ->
4.0s -> Countdown decremented to 0; timer stops

See what just happened there? You pressed at 1.5s, which reset Countdown to 3 seconds. However, the countdown stopped at 4s, which was only 2.5 seconds later. That’s because “Do Every X Seconds” isn’t starting over with each press. Its still checking in every one second from when it started to see if countdown needs to be decremented.

As such, you may find it appropriate to set the interval inside the “Do Every” and the decrement value to lower values. Setting both to “.1” would give you much better precision.

The only other thing worth mentioning is that sometimes decimal point numbers can be messy and not quite exact. This isn’t a Stencyl thing; in general, computers store decimal place numbers in a way that sometimes “estimates”. I’m not going to go into all the technical details about computer memory, so just know that when you say “.1”, the computer may store it as “.099999999999” or something similar. Try printing decimal numbers to the Stencyl console and you might catch some of those instances.

You may find it useful then to keep your decrement value at 1. Now, for the above example, you still have to put “.1” into your “Do Every” event. To execute it every “.1” seconds, you can’t get around putting “.1” in there. That just means you have to set Countdown a little differently based on your timer interval. It may sound complicated, but trust me when I say keeping numbers as straight whole numbers is more precise (An example right in Stencyl is how it stores animation times in milliseconds; a half second is stored as 500 milliseconds as opposed to .5 seconds).

Let “x” represent your decrement interval, or rather the x in “Do Every X Seconds” (they are the same thing). To set your Countdown attribute:

Countdown = Timer Duration * (1 / x)

In this instance, for a 3 second timer duration and a decrement interval of .1, Countdown will be set to 30.

Still with me? Here’s a visual to help solidify where everything goes.

Values underlined with the same color should be EQUAL to each other.

Values underlined with the same color should be EQUAL to each other.

* * * * *

Hope you found this helpful! Happy Stencyling!

Advertisements
Posted in Stencyl, Timed Events

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: