Modular Wave System

Overview

The Modular Wave System is a pair of wave managers with a clean C# API and a matching Game Creator 2 integration layer.

- Default Wave System (KingEdward.WaveSystem.Default): classic wave/stage progression, optional boss waves. - Survivors‑Like Wave Syste (KingEdward.WaveSystem.SurvivorsLike): continuous spawning loop in a given duration (difficulty over time, elites, bosses). - Core utilities (KingEdward.WaveSystem.Core): shared pieces (WaveCharacter, ObjectPool, SpawnArea, WaveSystemEffects). - GC2 integration (KingEdward.WaveSystem.GC2Integration): Property Gets, Conditions, Triggers and one Instruction, under a separate namespace. Install via .unitypackage on Integrations folder.

You can drive everything directly from code, from GC2, or mix both.

Folder Structure

Core Concepts

WaveCharacter (Core)

Namespace: KingEdward.WaveSystem.Core

Attach this to any GameObject that should participate in the wave systems (player or enemy).

How to use from your own health/damage code:

using KingEdward.WaveSystem.Core;

public class EnemyHealth : MonoBehaviour
{
    [SerializeField] private int maxHealth = 100;
    private int currentHealth;
    private WaveCharacter waveCharacter;

    private void Awake()
    {
        currentHealth = maxHealth;
        waveCharacter = GetComponent<WaveCharacter>();

        if (waveCharacter == null)
        {
            waveCharacter = gameObject.AddComponent<WaveCharacter>();
            waveCharacter.MarkAsEnemy();
        }
    }

    public void TakeDamage(int amount)
    {
        currentHealth -= amount;
        if (currentHealth <= 0 && waveCharacter != null)
        {
            waveCharacter.Die();
        }
    }
}

Both wave managers subscribe to WaveCharacter.OnDeath on spawned enemies, so your only job is to call Die() when the enemy actually dies.

ObjectPool (Core)

Simple prefab pooling used by both managers to avoid excessive Instantiate/Destroy.

Main methods:

Both managers handle pooling automatically; you typically do not need to call these yourself unless you want manual control elsewhere in your project.

SpawnArea (Core)

Namespace: KingEdward.WaveSystem.Core

Component that defines a 3D spawn volume for enemies. Can be a sphere or box, with visual gizmos similar to Unity's Colliders.

- Volume Types:

- Methods:

- Gizmos: The volume is visualized in the Scene view with colored wireframe (semi-transparent when not selected, more opaque when selected). Uses Unity's Handles for better visual quality.

- Settings:

How to use:

  1. Create a GameObject in your scene.
  2. Add the SpawnArea component.
  3. Choose Sphere or Box volume type.
  4. Adjust Radius (for sphere) or Size (for box - X, Y, Z dimensions).
  5. Position and rotate the GameObject to define where enemies should spawn.
  6. Assign the SpawnArea to the manager's Spawn Areas array.

You can have multiple SpawnArea components in your scene; the manager will randomly pick one for each spawn. The volumes respect the GameObject's transform (position, rotation, scale).

Default Wave System

Components & Data

WaveData – configuring waves

Each WaveData asset defines a single wave:

- Fields

For boss waves, typically you add a single EnemyGroup with the boss prefab and count = 1, and mark isBossWave = true.

WaveManagerDefault – scene setup

1. Create a GameObject in your scene, e.g. Wave Manager Default. 2. Add the WaveManagerDefault component. 3. Referencing the manager: Prefer assigning the manager by reference in the inspector (e.g. on WaveDefaultUI, or on your own scripts that need to read state or subscribe to events). You can have multiple managers in the same scene (e.g. one per arena); each UI or script should reference the manager it uses. A static Instance is still set to the first active manager at runtime for backward compatibility and simple single-manager setups; when in doubt, use an explicit reference. 4. Assign fields:

The custom inspector groups these settings under Setup / Player / Performance with foldouts and warnings for missing waves or spawn areas.

Runtime API (code)

Get the manager by reference (assign in the inspector on your MonoBehaviour) or, in code-only cases, via the static Instance (first active manager). Prefer reference when you have multiple managers or want clear wiring.

using KingEdward.WaveSystem.Default;

// Option A: reference assigned in inspector (recommended)
[SerializeField] private WaveManagerDefault waveManager;

void SomeMethod()
{
    if (waveManager != null && waveManager.IsGameActive)
        Debug.Log($"Wave {waveManager.CurrentWave}/{waveManager.TotalWaves}, enemies left: {waveManager.EnemiesRemaining}");
}

// Option B: single-manager scene, no reference
var mgr = WaveManagerDefault.Instance;
if (mgr != null && mgr.IsGameActive)
    Debug.Log($"Wave {mgr.CurrentWave}/{mgr.TotalWaves}");

- Read‑only properties

- Control methods

- Events

Example: custom reward on boss death

using KingEdward.WaveSystem.Default;

public class BossReward : MonoBehaviour
{
    [SerializeField] private WaveManagerDefault waveManager;

    private void OnEnable()
    {
        if (waveManager == null) waveManager = WaveManagerDefault.Instance;
        if (waveManager != null)
            waveManager.OnBossDefeated += HandleBossDefeated;
    }

    private void OnDisable()
    {
        if (waveManager != null)
            waveManager.OnBossDefeated -= HandleBossDefeated;
    }

    private void HandleBossDefeated(int waveIndex)
    {
        // Grant loot, XP, play cutscene, etc.
    }
}

Default UI

WaveDefaultUI is a simple HUD component:

Survivors‑Like Wave System

Components & Data

GameConfiguration

- Game Settings

Helper methods (used internally but also safe to call):

EnemySpawnData

BossData

WaveManagerSurvivors – scene setup

1. Create a GameObject Wave Manager Survivors. 2. Add WaveManagerSurvivors. 3. Referencing the manager: Assign the manager by reference on WaveSurvivorsUI or your scripts when possible. If left empty, the UI uses WaveManagerSurvivors.Instance (first active manager). Prefer explicit reference if you have multiple managers. 4. Assign:

The manager automatically:

Runtime API (code)

Get the manager by reference (assign in inspector) or via WaveManagerSurvivors.Instance in single-manager setups:

using KingEdward.WaveSystem.SurvivorsLike;

[SerializeField] private WaveManagerSurvivors waveManager;

void SomeMethod()
{
    if (waveManager == null) waveManager = WaveManagerSurvivors.Instance;
    if (waveManager != null && waveManager.IsGameActive)
        Debug.Log($"Time: {waveManager.GameTime:0.0}s | Difficulty: {waveManager.CurrentDifficulty:0.00} | Enemies: {waveManager.EnemiesAlive}");
}

- Read‑only properties

- Control methods

- Events

Example: custom power‑up logic

using KingEdward.WaveSystem.SurvivorsLike;

public class SurvivorsPowerUpController : MonoBehaviour
{
    [SerializeField] private WaveManagerSurvivors waveManager;

    private void OnEnable()
    {
        if (waveManager == null) waveManager = WaveManagerSurvivors.Instance;
        if (waveManager == null) return;

        waveManager.OnEnemyKilled += OnEnemyKilled;
        waveManager.OnEliteKilled += OnEliteKilled;
        waveManager.OnBossKilled += OnBossKilled;
    }

    private void OnDisable()
    {
        if (waveManager == null) return;

        waveManager.OnEnemyKilled -= OnEnemyKilled;
        waveManager.OnEliteKilled -= OnEliteKilled;
        waveManager.OnBossKilled -= OnBossKilled;
    }

    private void OnEnemyKilled(GameObject enemy) { /* base XP, coins, etc. */ }
    private void OnEliteKilled(GameObject enemy) { /* stronger rewards */ }
    private void OnBossKilled(GameObject boss)   { /* big chest, relics, etc. */ }
}

Survivors UI

WaveSurvivorsUI provides a minimal HUD:

Attach it to a Canvas and assign the Text/Image references.

Game Creator 2 Integration

All GC2 integration lives under:

KingEdward/WaveSystem/GC2Integration/Runtime/Visual Scripting

Instruction

Usage:

  1. In a Trigger or visual script, add Kill Wave Character.
  2. Set Target to:
  3. When executed, it will fire the WaveCharacter.OnDeath event, which both managers interpret as that enemy dying.

Conditions

Two condition types, each with Default and Survivors flavours:

Example: Only allow a door to open if the current wave is cleared:

Property Gets

All under KingEdward/Wave System/ categories.

Default

Survivors‑Like

Example: show wave number in a GC2 UI Text

Triggers (Events)

All triggers derive from GameCreator.Runtime.VisualScripting.Event and are in the Triggers folder.

Default events

All listen to the corresponding WaveManagerDefault C# events.

Survivors‑Like events

All listen to WaveManagerSurvivors events.

Example: GC2 power‑up drop on elite kill

  1. Add a Trigger: Wave System/On Elite Killed (SurvivorsLike).
  2. Inside the Trigger, use Instructions to spawn your power‑up, play VFX, etc.
  3. The event passes context via Args with the killed elite as the Trigger’s target (depending on your GC2 wiring).

Best Practices & Notes

📞 Support

🔄 Changelog

Version 1.0.0