No se han encontrado resultados
Howdy folks! If you have been following along with my previous blog entries you may have noticed I used a lot of self coded timers, rather than the alarm system that is built into GameMaker. I prefer to code my own timers for two reasons. One, the alarms in GameMaker are somewhat limited. You can only have a set amount of alarms per object. Two, alarms aren’t very transparent and I get lost trying to remember what alarm[0] was set to. In this entry, I will go over how to write your own timers, and how to use them.
So what exactly is a timer? A timer is a mechanism that allows you to count up, or down, to a certain value and then trigger something once that value is reached. So for example, let’s say you have a character who has been poisoned. Poison damage is generally a damage over time status effect, that deals a small amount of damage every so often. Imagine your game runs at 60 frames per second, and you decided that poison damage should be 1 damage. Your character has 100 hp and your code looks like this.
Example poison code
poisonDamage = 1;
if(poisoned){
hp -= poisonDamage;
}
This does not have a timer, or any sort of limitation on it, so it ticks down your hp by 1 every frame at 60 frames per second. Which means… your character with 100 hp dies in 1.6 seconds! That is some pretty hardcore poison! What you would really want to do, is tick down your poison damage every couple of frames. Maybe even every second. That code looks something like this.
Example poison timer code
poisonDamage = 1;
if(poisoned){
poisonTick --;
if(poisonTick <= 0){
hp -= poisonDamage;
poisonTick = 60;
}
}
In this example I am using a new variable, poisonTick, to determine when to apply poison damage. So now, what took 1.6 seconds previously, takes 100 seconds. poisonTick counts down by 1 every frame. Once poisonTick reaches 0, the player hp is reduced by the poisonDamage value, and poisonTick is reset back to its maximum of 60. This requires slightly more management than using alarms, but is much more versatile.
To use timers in this way you need at least one variable, which is the variable that stores whatever you are counting. In the above example that is poisonTick. I would highly recommend a second variable to use when you reset your counted variable. This makes it much easier to manage. I’ll go over this in an example below.
Another benefit to using manual timers is you can use the same timer variable in multiple cases. I often use a variable called actionDur (action duration) in my games to determine how long any one character action can be performed. Let’s say a character has two actions, attack and dash, both of which are timer dependent. The character is locked into either action for the duration of the timer. You could use two timers to manage this. Say something like attackDur and dashDur. Or you can use a single timer, and use it in both places. Check out the example below.
Multi-use timer
actionDurMax = 60;
actionDur = actionDurMax;
if(attack){
actionDur --;
if(actionDur <= 0){
actionDur = actionDurMax;
attack = false;
}
}
if(dash){
actionDur --;
if(actionDur <= 0){
actionDur = actionDurMax;
dash = false;
}
}
As you can see, both actions are able to use the same timer variables. Be aware that if you are using the same timer variable in multiple places, each use of the timer has to be completely independent of the other uses. So, using the above example again, I have to make sure that attack and dash cannot be true at the same time. If both variables were ever true at the same time, actionDur would countdown twice as fast. I highly recommend setting up a state machine for your character (see link at the end of this blog) which will help you manage what code is running when.
You can also count up with your timers, which changes the structure slightly. It is somewhat personal preference whether you choose to count up or down. You may run into some cases where counting up or down is more beneficial than the alternative.
Timer counting up
actionDur = 0;
actionDurMax = 60;
if(attack){
actionDur ++;
if(actionDur >= actionDurMax){
actionDur = 0;
attack = false;
}
}
There are some slight differences here. Our timer starts at 0, rather than the max, and counts up towards the max.
So what happens if you want to use a single timer for multiple actions, but have those action durations differ? The easiest way to do this, if you are using the same kind of setup that I’ve been talking about, is to define the starting point of your timer when the action happens. Using the attack action again, let’s see how that might work.
Different timer duration with a single timer variable
actionDur = 0;
actionDurMax = 60;
if(attack_button){
attack = true;
actionDur = 30;
}
if(attack){
actionDur ++;
if(actionDur >= actionDurMax){
actionDur = 0;
attack = false;
}
}
In this example we had to make use of a new block of code. We’ve added the attack_button variable, which you can imagine is a player pushing the attack button in a game. When that button is pressed, attack becomes true, and actionDur is set to 30. By default actionDur is set to 0, and we are overriding that when pressing our imaginary attack button. However actionDur is still counting up to the actionDurMax when attack is set to true. Only this time, instead of starting from 0, it starts from 30. This effectively halves the duration of our attack action. Here is another example using a second action.
Multiple actions with different timer durations
actionDur = 0;
actionDurMax = 60;
if(attack_button){
attack = true;
actionDur = 30;
}
if(attack){
actionDur ++;
if(actionDur >= actionDurMax){
actionDur = 0;
attack = false;
}
}
if(dash_button){
dash= true;
actionDur = 10;
}
if(dash){
actionDur ++;
if(actionDur >= actionDurMax){
actionDur = 0;
dash = false;
}
}
That about wraps it up for timers. Though it requires a teeny tiny bit more management than using alarms, using timers is a much more flexible and transparent setup. Thank you for taking the time to read over this, and I’ll catch you next time. As always, you can reach me on Twitter or visit my website for more gamedev stuff.
Nathan Ranney is the founder of game development studio Gutter Arcade. He's best known for the creation and development of Knight Club, an online indie fighting game.