Implemented a complete grid-based combat system with movement, positioning, and range-based attacks. The system transforms static combat into dynamic spatial warfare where agents must move into range before attacking.
WeaponType enum (Melee, Ranged, Magic)_range field (int, default 1 for melee)MonsterSize enum (Small, Medium, Large)_size field (default Medium)GetMovementRange() methodGridPosition property (Vector2Int)Size property (MonsterSize)DistanceTo(Combatant) - Manhattan distanceIsAdjacentTo(Combatant) - 1 square away checkCanReachTarget(Combatant, Weapon) - Range validationGetFootprintSize() - Grid size based on monster sizeGetCreaturesPerSquare() - Stacking limitpublic enum ActionType { Move, Attack, UseItem, Defend, Pass }
public class CombatAction
Static utility class for all combat rules:
CanAttack() - Range validation (melee adjacency, ranged within range)CanMoveTo() - Movement validation (in bounds, speed limit, grid valid)IsAdjacentTo() - Melee range check (1 square away)ManhattanDistance() - Distance calculationGetDirectionTowards() - Direction for pathfindingGetNextPositionTowards() - Single step toward targetCore spatial management system:
Constructor: CombatGrid(Vector2Int gridSize, float cellSize)
Key Methods:
PlaceAllCombatants() - Agents left side, monsters right sideIsPositionValid() - Respects grid bounds and size rulesTryMoveCombatant() - Atomic move with validationGetReachablePositions() - BFS pathfinding within movement rangePlaceCombatant() - Place individual combatantRemoveCombatant() - Remove from grid (on death)GridToWorldPosition() / WorldToGridPosition() - Coordinate conversionOccupancy Rules:
New Event Kinds:
MovementStart - Actor begins movingMovementComplete - Actor finishes movingOutOfRange - Attack failed (ranged/magic out of range)TooFarForMelee - Attack failed (not adjacent)TargetUnreachable - Movement failedNew Event Fields:
SourcePosition (Vector2Int) - Where movement startedTargetPosition (Vector2Int) - Destination or target locationMovementDistance (int) - Squares movedOld: Pick target → Attack every turn New:
InitializeGrid()SelectActions()ExecuteActions()ExecuteMovement()ExecuteAttack()ExecuteUseItem()Round starts
├─ SelectActions (all actors decide)
│ └─ Pick target
│ ├─ In range? → Attack
│ └─ Out of range? → Move
├─ ExecuteActions (process decisions)
│ ├─ Movement (all moves for round)
│ ├─ Attacks (validated against actual positions)
│ └─ Items (consumables used)
└─ Check win conditions
CurrentGridPos - Tracks position on gridSmall: 0.4f scale (smaller creatures)
Medium: 0.58f scale (default, human-sized)
Large: 1.2f scale (larger creatures)
New Event Handlers:
MovementStart - Brief pause (0.2s)MovementComplete → Movement() animationOutOfRange / TooFarForMelee → RangeFailure() animationHealthPotionUsed → HealPotion() animationMovement(CombatEvent e)RangeFailure(int combatantId)HealPotion(CombatEvent e)BattleArenaView (Animation)
↑
│ replays events with positions
│
CombatResolver (Logic)
├─ InitializeGrid() → CombatGrid
├─ SelectActions() → CombatAction[]
├─ ExecuteActions()
│ ├─ ExecuteMovement() → uses MovementValidator
│ ├─ ExecuteAttack() → uses MovementValidator
│ └─ ExecuteUseItem()
│
└─ Emits CombatEvent[] (with positions)
├─ MovementStart
├─ MovementComplete
├─ OutOfRange
├─ TooFarForMelee
├─ TargetUnreachable
├─ Hit/Miss
└─ Death
CombatGrid (Spatial State)
├─ PlaceAllCombatants()
├─ IsPositionValid()
├─ TryMoveCombatant()
└─ GetReachablePositions()
MovementValidator (Rules)
├─ CanAttack()
├─ CanMoveTo()
├─ IsAdjacentTo()
└─ ManhattanDistance()
Weapon (Type/Range)
├─ WeaponType enum
└─ Range property
Monster (Size)
└─ MonsterSize enum
Combatant (Positioning)
├─ GridPosition
├─ Size
├─ DistanceTo()
├─ CanReachTarget()
└─ GetFootprintSize()
✅ Spatial Combat - No more "attack from anywhere" ✅ Melee vs Ranged - Different weapons have different reach ✅ Speed-Based Movement - Faster = more squares per turn ✅ Smart AI - Agents automatically move into range ✅ Monster Sizes - Large/Medium/Small occupy different space ✅ Grid Stacking - Small creatures can stack (4 per square) ✅ Replayable Events - All movement recorded for animation ✅ Extensible - Easy to add Defend, Flee, abilities, etc.
Melee with Range=1 if not specifiedMonsterSize.MediumMonsterSize.MediumWeapon.cs - Added WeaponType, RangeMonster.cs - Added MonsterSizeCharacterStats.cs - Added GetMovementRange()Combatant.cs - Added positioning and range methodsCombatEvent.cs - Added movement event kinds, position fieldsCombatResolver.cs - Complete refactor with grid systemBattleArenaView.cs - Updated animation, position trackingCombatAction.cs - Action type systemCombatGrid.cs - Spatial grid managementMovementValidator.cs - Rule validation systemTotal: 7 modified, 3 new = 10 files changed