1. Create the projectile prefab

  1. Create a new GameObject with a SpriteRenderer and assign a sprite.
  2. Add a Collider2D (typically a small CircleCollider2D) set to Is Trigger.
  3. Add an AudioSource component.
  4. Add the Projectile component and configure it:
    • Speed — world units per second the projectile travels.
    • Damage — hit points removed on impact.
    • Shoot Sound — clip played at launch.
    • Hit Sound — clip played on impact.
  5. Save as a prefab.

2a. Use in a player instruction

Both PlayerController and EnemyController use the same execution pattern: the instruction's Execute() runs first, then OnExecute fires all IExecutionSuscriber components. The projectile is fired by ShootSuscriber via that event — the instruction itself does not call Shoot().

Create a PlayerInstruction subclass with an empty Execute() and the shoot animation in Tick():

[System.Serializable]
[TypeName("Shoot")]
public class Instruction_Shoot : PlayerInstruction
{
    public override string displayName => "Shoot";

    public override void Execute() { }

    protected override IEnumerator Tick(ExecutionContext context)
    {
        context.player.SetDirection(direction);
        context.player.PlayAnimation("Shoot");
        yield return new WaitForSeconds(1.5f);
    }
}

Then add ShootSuscriber to the player root (or any child) and assign the prefab. PlayerController.Initialize() auto-discovers it via GetComponentsInChildren<IExecutionSuscriber>() and wires it to OnExecute — no manual wiring needed.

2b. Use on an enemy with ShootSuscriber

The setup for enemies is identical: create an EnemyInstruction with an empty Execute() and the animation in Tick(), then add ShootSuscriber to the enemy root (or any child) and assign the prefab.

EnemyController.Initialize() auto-discovers it the same way and wires it to OnExecute automatically.

ℹ️
See Projectile for the full scripting reference.