Use this guide first when you need to replace a unit (swap prefabs per team via pools). It also explains how marching units spawn, move, fight, return to pools, and how to change unit types in code.
High-Level Flow
- Towers spawn UnitType.Soldier along completed paths. Factories spawn UnitType.Tank. This mapping is fixed in code (TowerModel / FactoryModel property "SpawnUnitType"), not in building prefab fields.
- When a path reaches "live" state, PathLiveState fires EventManager "ON_PATH_CREATED". UnitsModule listens and starts spawning for that path.
- Each tick, UnitsModule advances a per-path timer. When the timer reaches the interval from GameConfig "UnitSpawnIntervals" (indexed by source building level), another unit is spawned. Details: BuildingUnitSpawnRateAndEnemyStrengthTiersGuide.txt.
- Unit visuals come from object pools on UnitsModuleView ("_soldiersPools", "_tankPools"), keyed by (UnitType, TeamIDType). Missing pool logs an error and nothing spawns.
Core Types (code)
- UnitModel: holds "ID", "UnitType", "TeamID", "Radius", "Color", "Damage", "Health". "Damage" and "Health" are set from "UnitType" in the UnitModel constructor (Soldier 1/1, Tank 2/2).
- UnitController: ties UnitView + UnitModel to a PathController ("Source" and "Target" buildings). Runs a small state machine (UnitMoveState, UnitDiedState).
- UnitView: base view; requires "_rotateNode" for facing. HumanoidUnitView drives Animator states named "Walk" and "Die". VehicleUnitView is a minimal subclass (no default animation hooks).
Where UnitsModule Lives in the Editor
- Gameplay scene: Assets/GorodiskiGames/TowerClash/Scenes/Gameplay.unity
- Select the root object "Controller" (same GameObject carries GameView and several modules).
- Component UnitsModuleView exposes "_soldiersPools" and "_tankPools". Each entry is TeamPoolEntry: "TeamID" + ComponentPoolFactory "Pool".
Path and Spawn Rules
- UnitsModule ignores paths until PathController "IsComplete" is true (target building assigned).
- If source building model "SpawnUnitType" is UnitType.None, no spawns (non-spawning building types).
- First spawn happens immediately when the path is registered; later spawns use "UnitSpawnIntervals".
- When a path is removed, UnitsModule drops it from the active spawn map (no further spawns for that path).
Passive Unit Count on Buildings (not the same as marching units)
- BuildingAddUnitState increases building "UnitsCount" on a timer using GameConfig "UnitAddInterval", for teams other than Neutral.
- TowerController overrides "HasPath": while the tower has at least one active path ("PathsCount" greater than 0), passive unit gain is paused. Other building controllers use the default "HasPath" false, so factories and other types keep gaining passive units even when paths exist.
Movement and Arrival (UnitMoveState)
- Move speed comes from GameConfig "UnitMoveSpeed".
- Unit moves in a straight line from source building position toward the path target position captured at move start ("GetTargetBuildingPosition").
- On overlap in XZ with the target building (radii from unit model and building model), the unit "arrives":
- If target team equals source team: target "AddHealth" by unit damage, then unit "ReleaseImmediately" (no attack on own building).
- Else: unit applies self-damage equal to its remaining health first, then target "ApplyDamage" with unit damage. Order matters for level-end side effects (see UnitMoveState source).
Unit vs Unit Combat
- Each frame, UnitsModule checks all pairs of units on different teams for XZ circle overlap using positions and "Radius".
- Each colliding pair trades damage once per pair per encounter (pair tracked by sorted unit "ID" values). Damage values are each unit model "Damage".
Death and Pooling
- When health reaches zero, UnitController enters UnitDiedState: plays "Die" on HumanoidUnitView, then after "GetCurrentStateLength" fires release.
- On release or level end, the view is returned to the same ComponentPoolFactory that created it, keyed by (UnitType, TeamID).
- UnitModel uses a static incrementing "ID" for collision bookkeeping across the session.
Weapons vs Units
- Cannontower weapons prefer enemy units inside range before enemy buildings (closest wins). Artillery uses attack-range logic, not this unit list.
- Homing bullets subscribed to a unit are cancelled if that unit dies first (WeaponsModule).