I'm prototyping a board game which has 20 "blocks" where an enemy character jumps one block at a time (from 1-20) when spacebar is pressed. If the enemy makes it to block 20 - it's the winner.
Each block has different obstacles and the enemy can get frozen, burned, trapped, melted, teleported, etc. Some blocks can have multiple of those obstacles.
What I'm trying to do is create a separate class for each of those obstacles and add them to different blocks using .AddComponent<>
. When an enemy lands on a block, the block goes through the obstacle(s) added on that block and punishes the enemy accordingly.
This is the block prefab class:
public class CompositeBlock : MonoBehaviour{
void Start(){
gameObject.AddComponent<ActionFreeze>();
gameObject.AddComponent<ActionTrap>();
}
// This is called when enemy steps on the block
public void ExecuteActions(Enemy enemy){
Debug.Log("Enemy has landed on this block");
IBlockAction[] actionArray = GetComponents<IBlockAction>();
foreach(IBlockAction action in actionArray){
action.Execute(enemy);
}
}
}
Here are the classes that can perform an "Action" on the ememy. Right now let's say blocks can only freeze or trap an enemy:
public interface IBlockAction{
void Execute(Enemy enemy);
void OnActionComplete();
}
public class ActionFreeze : MonoBehaviour, IBlockAction{
public void Execute(Enemy enemy){
Debug.Log("Freezing Enemy");
enemy.Freeze(); // Change enemy's sprite to frozen
Invoke("OnActionComplete", 2f); // Wait for 2 seconds
}
public void OnActionComplete(){
Debug.Log("Freeze completed");
}
}
public class ActionTrap : MonoBehaviour, IBlockAction{
public void Execute(Enemy enemy){
Debug.Log("Trapping Enemy");
enemy.Trap(); // Change enemy's sprite to trapped
Invoke("OnActionComplete", 3f); // Wait for 3 seconds
}
public void OnActionComplete(){
Debug.Log("Trap completed");
}
}
This works as expected but since ExecuteActions
has a for loop, all the actions are executed at once. The enemy's "Frozen" sprite will not be visible at all because the next action is performed immediately. Here's how the log looks:
Enemy has landed on this block
Freezing Enemy
Trapping Enemy
Freeze completed
Trap completed
How can the next action's .Execute()
be called only after the current action's OnActionComplete()
is called so that the enemy's "Frozen" sprite is shown for 2 seconds, then the enemy's sprite is changed to "Trapped" which is then shown for 3 seconds. The log should look like this:
Enemy has landed on this block
Freezing Enemy
Freeze completed
Trapping Enemy
Trap completed
The duration (frozen or trapped) sprite is shown is not important, as instead of a sprite change, an animation could be played. No matter how the enemy (frozen or trapped) state is displayed - OnActionComplete()
should be called after it's completion.