Example

Projectile System

A complete projectile game — player fires, enemies spawn, power-ups drop. This example reveals how EGTK handles spawnable objects: game logic lives on persistent scene GameObjects, while spawned prefabs are just tagged colliders.

Player fires projectiles
Enemies spawn and chase
Health power-ups restore health
Score on projectile kill
Timer counts down to game over

Core Pattern

The Two-Tier Architecture

EGTK games that spawn objects use two kinds of GameObjects with very different responsibilities. Understanding the split is the key to making this pattern work.

Tier 1 — The Brains persistent scene objects
These objects live in the scene permanently. All UnityEvent wiring happens here — they watch for tagged objects and call managers when they detect them.
⚙️
MANAGERS
GameHealthManager GameCollectionManager GameTimerManager GameStateManager
🎯
ProjectileSpawner
ActionSpawnProjectile InputActionEvent InputTriggerZone ×3
🔄
Spawners
enemySpawner healthPowerUpSpawner projectilePowerUpSpawner
Tier 2 — The Bodies spawnable prefabs
These are minimal. A mesh, a collider, and a tag. No cross-scene event wiring — they can't reference scene objects because they don't exist until runtime.
👾
enemy.prefab
tag: enemy EnemyControllerCC Collider
💊
healthPowerUp.prefab
tag: health Collider (trigger)
projectilePowerUp.prefab
tag: projectilePowerUp Collider (trigger)
🔵
projectile.prefab
tag: projectile ProjectileVelocity Collider (trigger)
How It Works

Detection lives on the persistent object, not the spawned one

The player (ProjectileSpawner) carries an InputTriggerZone for each tag it cares about. When an enemy wanders into that zone, the zone fires — and the player's wired event calls the manager. The enemy itself doesn't need to know about any manager.

💡
The rule of thumb
The object that detects is the persistent one — it lives in the scene and holds the wired event. The object being detected just needs the right tag and a collider. You never need to wire events on the spawned object to talk to a scene manager.

Important Constraint

UnityEvents are not stored in prefabs

This is the most important thing to understand about EGTK and Unity prefabs. A UnityEvent that points to a scene object — a manager, a door, another player — cannot be saved inside a prefab. The prefab doesn't know which scene it will land in.

⚠️
What Unity actually saves
When you save a GameObject as a prefab, any UnityEvent that references a scene object gets saved as m_Target: {fileID: 0} — a null. The method name is remembered, but the target is gone. At runtime, the event fires and silently does nothing.

What each prefab stores (and what it doesn't)

👾 enemy.prefab
Tag enemy ✓
EnemyControllerCC saved ✓
Collider saved ✓
OnEnter → GameHealthManager null target ✗
OnEnter → SetActive(false) self-ref works ✓
💊 healthPowerUp.prefab
Tag health ✓
Collider (trigger) saved ✓
OnEnter → GameHealthManager not wired
Destroy self on collect self-ref works ✓
🔵 projectile.prefab
Tag projectile ✓
ProjectileVelocity saved ✓
Collider (trigger) saved ✓
OnEnter → any scene obj null target ✗
Destroy self on hit self-ref works ✓
Self-references inside a prefab always work
An event that targets another component on the same prefab — like an enemy disabling its own GameObject on death — is saved correctly. Only cross-scene references (prefab → scene object) break. Design around this by putting detection on the persistent object, not the spawned one.

Tactical Pattern

Configure once, then duplicate

When you need scene-wired events on an object that appears many times — different enemy types, collectibles with different sounds — don't make a prefab. Configure the first one in the scene, then duplicate it (Ctrl+D). The duplicated object keeps all its wired events intact.

  1. 1
    Place and configure the first instance in the scene
    Drop your enemy (or power-up) into the scene. Add the components you need. Wire all events — drag in the GameHealthManager, set the method, set the value. Test that it works.
  2. 2
    Duplicate, don't re-prefab
    Select the configured object in the Hierarchy. Press Ctrl+D. The copy has all the same component settings and event wiring — it's a snapshot of the configured state, not a blank prefab instance. Reposition and rename as needed.
  3. 3
    Use the scene objects as prefabs for your spawner
    Drag either scene object into your Project to create a prefab from it — or just reference the configured instance directly if you don't need to spawn it dynamically. If you do convert to prefab, remember: the cross-scene event wiring will be lost in the prefab asset. The workaround is to keep the detection on the persistent object and let the spawned object remain minimal.
  4. 4
    For multiple variants, duplicate the configured version each time
    Want a fast enemy and a slow enemy? Configure the slow one, duplicate → fast one, adjust the EnemyControllerCC speed. Both keep their GameHealthManager wiring. This is faster than rebuilding from a blank prefab every time.
⚠️
When you need dynamic spawning
If ActionAutoSpawner needs to spawn the object, assign it a Prefab asset in the Inspector — not a scene object. In that case, design the prefab so it needs no cross-scene wiring: give it a tag, and put the detection logic on the persistent spawner/player object using InputTriggerZone. That's exactly how the projectile example is built.

Complete Reference

Every wire in the projectile example

All the connections, in order of what fires what.