MOVEMENT_COMBAT_SUMMARY.md 11 KB

Movement-Based Combat System Implementation

Overview

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.


Phase 1: Data Model Extensions ✅

1.1 Weapon.cs

  • Added: WeaponType enum (Melee, Ranged, Magic)
  • Added: _range field (int, default 1 for melee)
  • Impact: Weapons now declare their combat class and effective range

1.2 Monster.cs

  • Added: MonsterSize enum (Small, Medium, Large)
  • Added: _size field (default Medium)
  • Mapping:
    • Small: 4 creatures per square
    • Medium: 1 creature per square (1x1)
    • Large: 1 creature in 4x4 squares
  • Impact: Monsters occupy different amounts of grid space

1.3 CharacterStats.cs

  • Added: GetMovementRange() method
  • Formula: Speed / 2 (minimum 1 square per turn)
  • Impact: Speed stat now determines both initiative and movement capability

1.4 Combatant.cs

  • Added: GridPosition property (Vector2Int)
  • Added: Size property (MonsterSize)
  • Added Methods:
    • DistanceTo(Combatant) - Manhattan distance
    • IsAdjacentTo(Combatant) - 1 square away check
    • CanReachTarget(Combatant, Weapon) - Range validation
    • GetFootprintSize() - Grid size based on monster size
    • GetCreaturesPerSquare() - Stacking limit

Phase 2: Combat Infrastructure ✅

2.1 CombatAction.cs (NEW)

public enum ActionType { Move, Attack, UseItem, Defend, Pass }
public class CombatAction
  • Represents turn decisions
  • Holds actor, action type, targets (combatant/position/item)
  • Flexible constructors for different action types
  • Used by CombatResolver to make combat determinate

2.2 MovementValidator.cs (NEW)

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 calculation
  • GetDirectionTowards() - Direction for pathfinding
  • GetNextPositionTowards() - Single step toward target

2.3 CombatGrid.cs (NEW)

Core spatial management system:

Constructor: CombatGrid(Vector2Int gridSize, float cellSize)

  • Default: 11x7 grid
  • Tracks all occupancy per cell

Key Methods:

  • PlaceAllCombatants() - Agents left side, monsters right side
  • IsPositionValid() - Respects grid bounds and size rules
  • TryMoveCombatant() - Atomic move with validation
  • GetReachablePositions() - BFS pathfinding within movement range
  • PlaceCombatant() - Place individual combatant
  • RemoveCombatant() - Remove from grid (on death)
  • GridToWorldPosition() / WorldToGridPosition() - Coordinate conversion

Occupancy Rules:

  • Large (4x4): Cannot share any space
  • Medium (1x1): Needs empty cell
  • Small: Up to 4 per square (stacking)

Phase 3: Event System Extensions ✅

3.1 CombatEvent.cs

New Event Kinds:

  • MovementStart - Actor begins moving
  • MovementComplete - Actor finishes moving
  • OutOfRange - Attack failed (ranged/magic out of range)
  • TooFarForMelee - Attack failed (not adjacent)
  • TargetUnreachable - Movement failed

New Event Fields:

  • SourcePosition (Vector2Int) - Where movement started
  • TargetPosition (Vector2Int) - Destination or target location
  • MovementDistance (int) - Squares moved

Phase 4: Combat Resolver Refactor ✅

4.1 Core Flow Changes

Old: Pick target → Attack every turn New:

  1. InitializeGrid() - Create 11x7 grid, place all combatants
  2. SelectActions() - Each combatant decides Move/Attack/UseItem
  3. ExecuteActions() - Process decisions in order

4.2 New Methods

InitializeGrid()

  • Creates CombatGrid with 11x7 cells
  • Places combatants (agents left, monsters right)

SelectActions()

  • Agents check health, use potions if <20% HP
  • Pick random enemy target
  • Decision logic:
    • If target in weapon range → Attack action
    • If out of range → Move action (toward target)
    • If no weapon or can't move → Pass action

ExecuteActions()

  • Processes all actions in turn order
  • Dispatches to specific executors

ExecuteMovement()

  • Updates grid position
  • Emits MovementStart, MovementComplete events
  • Records source, destination, distance in events

ExecuteAttack()

  • Validates range BEFORE attacking
  • Melee: Must be adjacent (distance = 1)
  • Ranged/Magic: Must be ≤ weapon.Range
  • Emits OutOfRange/TooFarForMelee if validation fails
  • Only calls TakeSwing() if valid

ExecuteUseItem()

  • Agents can use consumables during their turn
  • Immediate health restoration

4.3 Combat Flow

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

Phase 5: BattleArenaView Animation ✅

5.1 Slot Class Enhancement

  • Added: CurrentGridPos - Tracks position on grid

5.2 PlaceCombatants() Refactor

  • Old: Hard-coded team layout
  • New: Uses grid positions from Combatant objects
  • Respects actual CombatGrid placement

5.3 CreateSlot() Size Scaling

Small:  0.4f scale  (smaller creatures)
Medium: 0.58f scale (default, human-sized)
Large:  1.2f scale  (larger creatures)

5.4 Replay() Event Handling

New Event Handlers:

  • MovementStart - Brief pause (0.2s)
  • MovementComplete → Movement() animation
  • OutOfRange / TooFarForMelee → RangeFailure() animation
  • HealthPotionUsed → HealPotion() animation

5.5 New Animation Methods

Movement(CombatEvent e)

  • Animates combatant from source to target position
  • Updates CurrentGridPos
  • Smooth glide over 0.6 beats

RangeFailure(int combatantId)

  • Visual feedback: brief shake effect
  • 3 cycles of left-right motion
  • Indicates attack couldn't connect

HealPotion(CombatEvent e)

  • Green color flash
  • Green floating text (+amount)
  • Updates displayed health
  • 0.6s total animation

5.6 Position Tracking Updates

  • Strike(): Uses actual grid positions from events
  • ApplyFinalState(): Uses final combatant GridPosition
  • DrawNameplates(): Uses Transform.position (dynamic)
  • AddFloater(): Uses Transform.position (dynamic)

Architecture Integration 🔗

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()

What This Enables ✨

✅ 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.


Compatibility Notes ⚠️

Backwards Compatibility

  • Existing weapons default to Melee with Range=1 if not specified
  • Existing monsters default to MonsterSize.Medium
  • Agents default to MonsterSize.Medium
  • CombatResolver interface unchanged (still takes combatants, returns BattleResult)
  • CombatDirector calls unchanged

Testing Recommendations

  1. Test melee combat (agent must be adjacent to monster)
  2. Test ranged combat (agent moves into range, then attacks)
  3. Test monster sizes:
    • Small creatures stacking
    • Large creatures blocking movement
    • Medium creatures standard behavior
  4. Test grid boundaries (combatants can't move off grid)
  5. Test multiple combatants (ensure pathfinding avoids allies)
  6. Test movement range calculation (Speed/2)
  7. Test speed stat affecting both initiative and movement

Future Enhancements

  1. Defend Action - Reduce incoming damage this turn
  2. Ranged Abilities - Spells with area of effect
  3. Terrain Effects - Obstacles, difficult terrain
  4. Crowd Control - Stuns, roots, slows
  5. Smart Pathfinding - Avoid allies, seek advantage
  6. Flanking Mechanics - Bonuses for surrounding enemy
  7. Line of Sight - Visibility-based targeting
  8. Formations - Coordinated group movement

Performance Considerations

  • CombatGrid uses Dictionary for O(1) occupancy lookup
  • BFS pathfinding is O(n) where n = grid cells (77 for 11x7)
  • Movement validation is O(1) per cell
  • All spatial queries happen once per turn
  • No per-frame updates (resolved completely before animation)

Files Modified/Created

Modified

  • Weapon.cs - Added WeaponType, Range
  • Monster.cs - Added MonsterSize
  • CharacterStats.cs - Added GetMovementRange()
  • Combatant.cs - Added positioning and range methods
  • CombatEvent.cs - Added movement event kinds, position fields
  • CombatResolver.cs - Complete refactor with grid system
  • BattleArenaView.cs - Updated animation, position tracking

Created

  • CombatAction.cs - Action type system
  • CombatGrid.cs - Spatial grid management
  • MovementValidator.cs - Rule validation system

Total: 7 modified, 3 new = 10 files changed


Testing Checklist

  • Project compiles without errors
  • Basic fight resolves (agents vs monsters)
  • Melee attacks require adjacency
  • Ranged attacks work at range
  • Agents move into range automatically
  • Movement distance respects Speed stat
  • Large monsters block space
  • Small monsters stack (4 per square)
  • Health potions heal and show animation
  • Out of range attacks emit proper events
  • Movement animation plays correctly
  • Grid placement looks balanced
  • Final positions are accurate
  • Arena playback matches log-only mode