Manual
Create a New Enemy Instruction
Add a custom action to an enemy's turn sequence. Enemy instructions run in parallel with the player's instruction each turn.
How Enemy Actions Work
Each enemy has an ordered list of EnemyAction ScriptableObjects. Every turn, the enemy's task returns its current action to the TaskSchedule, which runs it in parallel with the player's instruction.
EnemyController implements ITaskReceiver → returns a Task each turn
↓
Task runs EnemyAction.GetInstruction() → EnemyInstruction.Run(context)
↓
EnemyInstruction.Tick(context) ← your logic goes here
Step-by-Step
-
Create the C# class in
Assets/Scripts/Enemies/Instructions/
ExtendEnemyInstruction. -
Override
displayName
Shown in the enemy's action HUD indicator during execution. -
Override
Execute()
Instant effects (damage, state changes). Can be empty. -
Override
Tick(ExecutionContext ctx)
Coroutine logic. Usecontrollerto access the enemy's position, animation, and health. Usectx.playerto read player state. -
Create an EnemyAction ScriptableObject
Right-click in the Project → Create > Loop Adventure > Enemy Action. Assign your new instruction type. -
Add to the enemy
In the enemy prefab'sEnemyControllercomponent, add the newEnemyActionasset to the action list.
Example — Heal
Restores 2 HP to the enemy every turn.
using System.Collections; using UnityEngine; namespace LoopAdventure { public class EnemyInstruction_Heal : EnemyInstruction { public override string displayName => "Heal"; public override void Execute() { controller.GetComponent<EnemyHealth>().Heal(2); } protected override IEnumerator Tick(ExecutionContext ctx) { Execute(); controller.PlayAnimation("Heal"); yield return new WaitForSeconds(0.8f); } } }
Example — Arrow Shot
Fires a projectile aimed at the player's position.
using System.Collections; using UnityEngine; namespace LoopAdventure { public class EnemyInstruction_ArrowShot : EnemyInstruction { public override string displayName => "Arrow Shot"; [SerializeField] Projectile projectilePrefab; [SerializeField] int damage = 1; public override void Execute() { } protected override IEnumerator Tick(ExecutionContext ctx) { controller.PlayAnimation("Attack Side"); Vector2 dir = (ctx.player.position - (Vector2)controller.transform.position).normalized; Projectile p = Object.Instantiate( projectilePrefab, controller.transform.position, Quaternion.identity); p.Launch(dir, damage); yield return new WaitForSeconds(1f); } } }
Player vs Enemy Instructions
| Player Instruction | Enemy Instruction | |
|---|---|---|
| Base class | PlayerInstruction | EnemyInstruction |
| Runs | One per turn, in sheet order | In parallel with the player's turn |
| Character ref | ctx.player | controller field |
| Direction source | Set by the player in the UI | Set in the EnemyAction ScriptableObject |
| Registered in | InstructionSheet palette | EnemyController action list |
Animation state names
Call
controller.PlayAnimation("StateName") using the exact state name from the enemy's Animator Controller. Common states: "Idle", "Attack Side", "Attack Up", "Block", "Die".