Posted April 06, 2025 by Goutamraj
#Enemy
Added an Enemy Handling System.
The Enemy System in this project manages the creation, registration, and removal of enemy entities. It comprises four core components:
EnemyManager: Central controller handling enemy registration, spawning, and cleanup.
EnemyFactory: Responsible for instantiating enemy prefabs based on type.
EnemySpawner: Handles delayed enemy spawning and spawn cancellation.
IEnemy (Interface): Abstract base class for all enemy types.
Acts as the central hub for managing all active enemies, coordinating their spawning, and handling cleanup when needed.
[SerializeField] public Transform enemiesHolder; [SerializeField] public GameObject guardEnemy; [SerializeField] public GameObject dogEnemy; public EnemySpawner enemySpawner; public EnemyFactory enemyFactory; private HashSet<IEnemy> activeEnemies = new HashSet<IEnemy>();
void Start()
Initializes EnemySpawner
and EnemyFactory
Subscribes to game events for spawning enemies and handling results
void CreateSomeDummyEnemies()
Collects valid spawn cells from the maze
Schedules guard enemies to spawn on these cells
void OnResult()
Cancels all ongoing enemy spawns
Clears all active enemies from the scene
void RegisterEnemy(IEnemy enemy)
Adds an enemy to the active enemies list
void UnregisterEnemy(IEnemy enemy)
Removes an enemy from the active enemies list
void ClearAllEnemies()
Destroys all currently active enemies (note: can be updated to return to a pool)
Instantiates enemy GameObjects based on their EnemyType
.
public EnemyManager enemyManager;
public EnemyFactory(EnemyManager enemyManager)
IEnemy CreateEnemy(EnemyType enemyType, Vector3 position)
Uses a switch case to determine which prefab to instantiate
Initializes the enemy by calling InitializeEnemy()
Returns the initialized enemy object
Handles scheduling and executing enemy spawns after a delay.
private EnemyManager enemyManager; private int spawnIdCounter = 0; private Dictionary<int, Coroutine> activeSpawns = new Dictionary<int, Coroutine>();
public EnemySpawner(EnemyManager enemyManager)
int ScheduleEnemySpawn(EnemyType type, Vector3 position, float delay)
Starts a coroutine that spawns the enemy after a delay
Stores the coroutine in a dictionary with a unique spawn ID
void CancelSpawn(int spawnId)
Stops the coroutine associated with the given spawn ID
void CancelAllSpawns()
Stops and clears all ongoing enemy spawn coroutines
IEnumerator SpawnEnemyWithDelay(int spawnId, EnemyType type, Vector3 position, float delay)
Waits for the specified delay and then calls SpawnEnemy()
void SpawnEnemy(EnemyType type, Vector3 position)
Delegates enemy creation to the factory
Base class for defining behavior and common attributes of enemies.
[SerializeField] public EnemyData data; [SerializeField] public EnemyType type; [SerializeField] public float health; [SerializeField] public float damagePow; protected EnemyManager enemyManager;
public virtual void InjectManager(EnemyManager manager)
Injects manager reference into the enemy.
protected void RegisterSelf()
Registers this enemy with the manager.
protected void UnregisterSelf()
Unregisters this enemy from the manager.
public abstract void InitializeEnemy(EnemyManager manager)
Must be implemented by subclasses to set initial properties.
public abstract void TakeDamage(float damage)
Must be implemented to define damage logic.
Implements IEnemy
for a guard-type enemy with health UI.
[SerializeField] Slider healthBar;
public override void InjectManager(EnemyManager manager)
Passes manager to base method.
public override void InitializeEnemy(EnemyManager enemyManager)
Sets type, health, and damage from EnemyData
Injects and registers with manager
public override void TakeDamage(float damage)
Reduces health
Updates health bar UI
Destroys self when health <= 0 and unregisters from manager
if(health <= 0) { UnregisterSelf(); Destroy(gameObject); // Replace with object pool return in future }
Modular Design: The enemy system is split across dedicated classes for factory creation, timed spawning, centralized management, and behavior abstraction.
Reusable: Enemies follow a shared interface, enabling reusable and extensible code.
Event-Driven & Coroutine-Based: Ties into gameplay events and handles asynchronous spawning with coroutines.
Extensible: New enemy types can be easily added by implementing IEnemy
.
Check out this for code implementation: Enemy