I'm developing a roguelike game in Unity using the RogueSharp library. Currently I'm stuck on realizing the turn-based combat aspect of the game (inspired by this tutorial), which is made up of a scheduling system that keeps track of the actors (i.e., the player and monsters) and handles the order of actions they can perform.
private async void ActivateMonsters()
{
var scheduleable = SchedulingSystem.NextActor;
UnityEngine.Debug.Log($"Turn of {scheduleable}!");
if (scheduleable is Player)
{
IsPlayerTurn = true;
SchedulingSystem.Add(Player);
}
else
{
if (IsPlayerDead)
{
return;
}
if (scheduleable is Monster monster)
{
UnityEngine.Debug.Log("Start monster turn!");
if (await monster.PerformAction(InputCommand.None))
{
UnityEngine.Debug.Log("Monster action done!");
SchedulingSystem.Add(monster);
}
}
ActivateMonsters();
}
}
At the bottom of the method, there is a recursive call to ActivateMonsters()
for ensuring that all monsters perform their actions until the player has a turn again.
Since my roguelike game is graphical and not text-based, the monsters have animations for attacking, walking, etc., that should be displayed on every turn. Therefore, the game should wait for each monster to perform its attack including playing the corresponding animation, before moving on to the next monster's turn. To achieve that, I've made the ActivateMonsters()
method async
and wait for monster.PerformAction()
to end (the InputCommand.None
input enum can be ignored).
ActivateMonsters()
is initially called in this event handler method invoked in Unity's Update() method:
private void UpdateGame(object sender, EventArgs e)
{
if (IsPlayerTurn)
{
HandleKeyboardInput();
}
else
{
UnityEngine.Debug.Log("First ActivateMonsters() call!");
ActivateMonsters();
RenderRequired = true;
}
}
monster.PerformAction()
first calculates the next position of the monster via pathfinding in an async method, which then calls the following method:
public static async Task<bool> Move(Actor actor, Loc location)
{
EnsurePropertiesAreSet();
var previousActorPosition = actor.Loc;
// Return true if moving the actor to the given location was successful.
if (DungeonMap.SetActorPosition(actor, location))
{
if (actor is Monster monster)
{
var moveDirection = location - previousActorPosition;
await Task.Delay(3000);
// Move the monster on the map.
Game.SetMonsterMoveDirection(monster, moveDirection);
}
return true;
}
return false;
}
For testing purposes, I put in the await Task.Delay(3000)
before the monster moves to the next tile.
With this I get:
First ActivateMonsters() call!
Turn of BrainHero.RogueLike.Actors.Goblin!
Start monster turn!
First ActivateMonsters() call!
Turn of BrainHero.RogueLike.Actors.Player!
[3 second pause]
Monster action done!
Turn of BrainHero.RogueLike.Actors.Player!
However, what I want to get is:
First ActivateMonsters() call!
Turn of BrainHero.RogueLike.Actors.Goblin!
Start monster turn!
[3 second pause]
Monster action done!
Turn of BrainHero.RogueLike.Actors.Player!
The await Task.Delay(3000)
part does work, but it seems like that the if (await monster.PerformAction(InputCommand.None))
is skipped and the code execution returns to UpdateGame()
for some reason. How can I modify the code so that I can achieve the latter execution sequence?
Thanks in advance for any help in solving this issue!