i like to get some thoughts on how to implement a tick based system.
Every action a player or non player got has a initial time to perform and a cooldown time. Once a creatures cooldown time has passed it gets to choose a new action. If the player has to choose a action the game is “paused”.
Example:
1: Player heavy swing (50 ticks to perform, 50 ticks to cool down)
2: Game goes on for 50 ticks.
3: NPC’s can set actions.
4: Player swings and cools down for 50 ticks.
5: NPC’s can set actions.
6: Game paused for the player.
What i currently have works but is not efficient. I have a class with each action as a static method. These method output a struct containing all the data. This will be passed to a actioncue of a individual creature.
Every update loop call the cue and start counting down the attack time if the player has put in a action. Once the attack should be solved i call a static method in the actions class again. And i start counting down the cooldown timer.
So what i should have is probably a list holding all actions and sorting that list skipping unnecessary time/ticks and go straight to the next action. But there will be different types of actions like move, attack, ability and i cant wrap my head around a good implementation of this.
When a creature performs a basic attack this gets called (attack is the creatures own instanced attack struct)
attack = Actions.BasicAttack(this, player, rand);
This is how the Actions class looks like.
public struct Attack
{
public int Damage;
public string Type;
public int Time;
public int Cooldown;
public Creature target;
public bool solved;
}
public static Attack BasicAttack(Creature attacker, Creature defender, Random rand)
{
Attack attack = new Attack();
attack.Damage = rand.Next(attacker.MinBaseDmg, attacker.MaxBaseDmg + 1);
attack.Type = "Melee";
attack.Time = 50;
attack.Cooldown = 30;
attack.target = defender;
attack.solved = false;
return attack;
}
And this gets called in the update method of each creature when the player has a action cued. Tick = 0 if player has no action cued and tick = 1 when player has a action cued up.
protected void ActionCue(int tick)
{
if (attack.target != null)
{
if (attack.Time > 1)
{
Console.WriteLine(attack.Time);
attack.Time -= tick;
this.free = false;
}
else if (!attack.solved)
{
Actions.SolveAttack(attack.Damage, attack.Type, attack.target);
attack.solved = true;
}
else if (attack.solved && attack.Cooldown > 1)
{
//Console.WriteLine(attack.Cooldown);
attack.Cooldown -= tick;
}
else
free = true;
}
}
Consider something like this (i will use pseudocode – its far from being optimized etc. but it might be just fast enough, or set you on your way to optimize what youre trying to do)
So, how this works?
We got a list of events.
The list checks all the events that are supposed to happen now and, executes their CombatAction.
In their CombatAction, the events add new events to the list. For example a PlayerMeeleAttack event sets the PlayerActionChoice event after an appropriate cooldown, so that he can take another action later.
After all current CombatEvents are resolved and have added their own CombatEvents to the list, the list checks the next Event (lowest delay)
The list sleeps for the specified number of ticks (the delay of the next Event). Once its done sleeping, it lowers the cooldowns on all events by an appropriate amount, and handles all the current events (those that just hit 0 delay)
This goes in a loop
The list starts with the CombatStartEvent on it, thats going to happen right away(delay 0). It sets the PlayerActionChoice and MonsterActionChoice events in the CombatAction method.
Of course this is far from being optimal, its just a sketch, or an idea for you to think through. There may be better ideas, i didnt give the problem very much thought – but this is obviously more efficient than your current solution 🙂