NEVER Do (Expert Anti-Patterns)
Unit Logic & Pathfinding
- NEVER allow pathfinding "Jitter" when moving group units; strictly stagger path queries and enable RVO Avoidance only when units are in motion to save CPU cycles.
- NEVER update RVO avoidance every frame for all units; strictly use Avoidance Threading (Project Settings) and replace static units with
NavigationObstacle.
- NEVER let units get stuck in infinite path loops; strictly implement a timeout and IDLE state if a destination is unreachable.
- NEVER use
process() on hundreds of individual units; strictly use a central UnitManager or physics_process only when required.
- NEVER calculate unit visibility manually for Fog of War; strictly use a Shader-based mask (SubViewport + ColorRect) for GPU efficiency.
- NEVER process unit AI or pathfinding synchronously for mass groups; strictly offload to
WorkerThreadPool and stagger path updates.
- NEVER use high-poly visual meshes as NavMesh source geometry; strictly use simplified Collision Shapes for baking.
Interaction & Commands
- NEVER forget Command Queuing (Shift-Click); strictly store an
Array[Command] and implement a "Force Move/Attack" bypass.
- NEVER create excessive micromanagement; strictly automate low-level tasks like auto-aggro range and auto-return for resource gathering.
- NEVER use exact floating-point equality (==) for grid or timers; strictly use
isequalapprox() for deterministic triggers.
- NEVER rely on the visual SceneTree for selection data; strictly maintain a Typed Selection Set of
RefCounted or Resource objects for deterministic serialization and netcode.
- NEVER forget Command Queuing; strictly implement a Command Pattern using serializable
Dictionary or JSON states for save-game and multiplayer playback.
- NEVER forget to duplicate_deep() globally shared Resources; otherwise, modifying one unit's data (e.g., stats) affects all.
Performance & Simulation
- NEVER render thousands of units using separate
MeshInstance3D nodes; strictly use MultiMeshInstance with INSTANCE_CUSTOM data to drive unique GPU-side state animations (walking/attacking/color).
- NEVER calculate transforms for mass units on the main thread; strictly use
WorkerThreadPool to push buffers to RenderingServer.multimeshsetbuffer().
- NEVER update every unit's navigation path in the same frame; strictly use random timers to stagger updates.
- NEVER use standard Strings for high-frequency AI state identifiers; strictly use StringName (&"harvesting") for pointer-speed comparisons.
- NEVER allow simulation coordinates to exceed 8192 units without float-precision management; strictly use world-origin shifts.
- NEVER use
CSGShape3D for building placement ghosts; strictly use optimized static ArrayMesh geometry.
🛠 Expert Components (scripts/)
MANDATORY: Read the script for the workflow you are implementing — do not re-inline selection/fog recipes in the agent body.
Selection / commands
- [selectionmanagermarquee2d.gd](scripts/selectionmanagermarquee2d.gd) — MANDATORY for 2D drag-box, filter, shift-add.
- [selectionmanagerraycast3d.gd](scripts/selectionmanagerraycast3d.gd) — MANDATORY for 3D PhysicsServer picks.
- [rtsselectionoverlay.gd](scripts/rtsselectionoverlay.gd) — Selection visuals / box overlay.
- [rtsgroupcommander.gd](scripts/rtsgroupcommander.gd) — SceneTree group broadcast for mass orders.
- [rtstargetinglogic.gd](scripts/rtstargetinglogic.gd) — Distance-squared enemy filtering.
Units / navigation / army
- [rtsunit.gd](scripts/rtsunit.gd) — MANDATORY unit controller (states + NavigationAgent).
- [crowdnavigationunit.gd](scripts/crowdnavigationunit.gd) — RVO / crowd agent wiring.
- [rtspathquerypool.gd](scripts/rtspathquerypool.gd) — Pooled Navigation path queries.
- [navigationmaskhelper.gd](scripts/navigationmaskhelper.gd) — Nav layers / avoidance bitmasks.
- [rtsarmymanager.gd](scripts/rtsarmymanager.gd) — WorkerThreadPool army AI batches.
- [rtsunitstatduplicator.gd](scripts/rtsunitstatduplicator.gd) —
duplicate_deep() isolation for unit Resources.
Economy / build / fog / ghosts
- [globaleconomymanager.gd](scripts/globaleconomymanager.gd) — Gather/spend bank Autoload pattern.
- [buildinggridastar.gd](scripts/buildinggridastar.gd) — Grid placement pathing.
- [fogofwartilemask.gd](scripts/fogofwartilemask.gd) — MANDATORY TileMapLayer fog clear (2D/grid).
- [renderingghostspawner.gd](scripts/renderingghostspawner.gd) — Placement ghosts via RenderingServer RIDs.
- [rtsformationmanager.gd](scripts/rtsformationmanager.gd) — Center-of-mass group path + per-unit formation offsets.
- [rtsmassiveunitrenderer.gd](scripts/rtsmassiveunitrenderer.gd) — MultiMeshInstance3D army renderer synced from unit transforms.
Core Loop
- Gather: Units collect resources (Gold, Wood, etc.).
- Build: Construct base buildings to unlock tech/units.
- Train: Produce an army of diverse units.
- Command: Micromanage units in real-time battles.
- Expand: Secure map control and resources.
Skill Chain
| Phase |
Skills |
Purpose |
| 1. Controls |
godot-input-handling, godot-camera-systems |
Selection box, camera pan/zoom/edge-scroll |
| 2. Units |
godot-navigation-pathfinding, godot-state-machine-advanced |
Pathfinding, RVO avoidance, Idle/Move/Attack |
| 3. Systems |
godot-shaders-basics, godot-tilemap-mastery, godot-economy-system |
Fog masks / TileMap fog, gather-spend ledger |
| 4. AI |
godot-ai-navigation, godot-autoload-architecture |
Enemy commander routing + army/economy Autoloads |
| 5. Polish |
godot-ui-containers, godot-particles |
Strategic UI chrome, battle feedback |
| 6. Balance |
godot-monte-carlo-balancer |
Build-order policies vs extracted AI orders |
Decision Tree: NavigationAgent+RVO vs MultiMesh+server sim
| Active units (order of magnitude) |
Simulation / pathing |
Rendering |
Load |
| < ~80 |
Per-unit NavigationAgent2D/3D + RVO; setvelocity → velocitycomputed |
MeshInstance / Sprite nodes OK |
MANDATORY rtsunit.gd, crowdnavigation_unit.gd |
| ~80–400 |
Stagger path queries; RVO only while moving; static → NavigationObstacle; central commander |
Still node visuals; pool path queries |
+ rtspathquerypool.gd, rtsarmy_manager.gd, Batch 09 COM formation |
| > ~400 / thousands |
Server sim: logical transforms on WorkerThreadPool; few NavigationServer map queries (COM / squads), not one agent per soldier |
MultiMeshInstance + INSTANCE_CUSTOM; push buffers off main thread |
rtsarmymanager.gd + MultiMesh path in Batch 09; Do NOT Load per-unit _process agents |
Rule: Keep NavigationAgent+RVO while units need individual collision avoidance and micromanage feel. Switch to MultiMesh + server-side transforms when draw-call/node cost dominates — path as squads, not as thousands of agents.
Architecture Overview
1. Selection Manager
MANDATORY: [selectionmanagermarquee2d.gd](scripts/selectionmanagermarquee2d.gd) (2D) or [selectionmanagerraycast3d.gd](scripts/selectionmanagerraycast3d.gd) (3D). Maintain a typed selection set (not SceneTree-only) for netcode/save. Overlay: [rtsselectionoverlay.gd](scripts/rtsselectionoverlay.gd).
2. Unit Controller (State Machine)
MANDATORY: [rtsunit.gd](scripts/rtsunit.gd) for Idle/Move/Attack/Hold + NavigationAgent. Deep state graphs → godot-state-machine-advanced. Always duplicatedeep() shared stat Resources ([rtsunitstatduplicator.gd](scripts/rtsunitstat_duplicator.gd)).
3. Group Movement & Formations
Avoid clumping on one click target: compute center of mass, apply relative offsets, issue per-unit destinations. For hundreds of units, use one NavigationServer path for the COM (Batch 09) plus [rtsgroupcommander.gd](scripts/rtsgroupcommander.gd) / [rtspathquerypool.gd](scripts/rtspathquerypool.gd).
4. Fog of War
MANDATORY for tile/grid fog: [fogofwartilemask.gd](scripts/fogofwartilemask.gd). SubViewport mask + shader overlay is valid for soft vision — implement via docs (Using Viewports) + godot-shaders-basics; Do NOT paste long fog shaders into this skill body when the tile-mask script covers the grid path.
Key Mechanics Implementation
Command Queue
Shift-click chains: store Array of serializable commands; pop on finish; draw queued path lines. Pair with selection scripts' issue-command hooks.
Resource Gathering
ResourceNode → work timer → DropoffPoint → bank update. Wire bank through [globaleconomymanager.gd](scripts/globaleconomymanager.gd) / godot-economy-system.
Common Pitfalls
- Pathfinding jitter — Enable RVO; call
setvelocity + move on velocitycomputed; stagger group path queries.
- Too much micro — Auto-aggro / auto-return gather; command queue for force-move/attack.
- Node explosion — Past a few hundred units, follow the decision tree (MultiMesh + army manager), not per-unit
_process.
Godot-Specific Tips
- Avoidance:
NavigationAgent* RVO requires setvelocity() + velocitycomputed for the actual move.
- Server architecture: Central
UnitManager / [rtsarmymanager.gd](scripts/rtsarmymanager.gd) for 100+ units.
- Groups:
Units, Buildings, Resources for selection filters.
🚀 Elite Technical Implementations (Batch 09)
1. Center-of-Mass Formation Movement
For large selections, one NavigationServer path from COM → target, then offset each unit (see decision tree). Keep the algorithm in project code or formation helpers; pair with [rtspathquerypool.gd](scripts/rtspathquerypool.gd) so path objects are pooled.
# Sketch only — prefer pooled queries from rts_path_query_pool.gd
static func move_group_to_target(units: Array, target: Vector3, map_rid: RID) -> void:
if units.is_empty():
return
var com := Vector3.ZERO
for u in units:
com += u.global_position
com /= units.size()
var path: PackedVector3Array = NavigationServer3D.map_get_path(map_rid, com, target, true)
if path.is_empty():
return
var dest: Vector3 = path[path.size() - 1]
for u in units:
u.set_movement_target(dest + (u.global_position - com))
2. MultiMesh armies (when decision tree says so)
Pre-allocate instancecount, drive visibleinstancecount, push transforms (optionally via WorkerThreadPool → RenderingServer.multimeshset_buffer). No per-soldier MeshInstance3D. See Official Documentation → Using MultiMesh.
3. Fog — script first
Prefer [fogofwartilemask.gd](scripts/fogofwartilemask.gd). SubViewport vision masks: docs + godot-shaders-basics (do not duplicate long shader bodies here).
MANDATORY for depth beyond decision trees and script catalog: [rts-mass-army-deep.md](references/rts-mass-army-deep.md). Do NOT Load on first-pass wiring — use bundled scripts/ first.
Reference
Progressive disclosure: open Official Documentation links only when researching a specific API;
load Related Skills when routing work to a peer domain — do not preload the whole lattice.
Official Documentation
- Navigation (tutorial index) — Entry map for agents, servers, meshes, layers, and obstacles before wiring army movement.
- Using NavigationAgents —
setvelocity / velocitycomputed RVO loop that stops crowd jitter and stuck IDLE timeouts.
- Using NavigationServers — Direct map path queries for center-of-mass formation moves without per-unit agent spam.
- Using navigation path query objects — Pooled
NavigationPathQueryParameters* patterns for mass move orders without heap churn.
- Optimizing navigation performance — Staggered queries, avoidance budgets, and obstacle swaps when hundreds of units path each tick.
- Using MultiMesh — GPU instance buffers for thousands of units instead of one
MeshInstance per soldier.
- Using multiple threads —
WorkerThreadPool contracts for army AI batches off the main thread.
- Ray-casting — Direct space-state picks for 3D selection and ground click targeting.
- Using Viewports — SubViewport vision masks that feed fog-of-war shaders without CPU tile floods.
- Mouse and input coordinates — Screen-to-world mapping for marquee boxes, unproject selection, and shift-queued orders.
- AStarGrid2D — Fast grid pathing for building footprints and base placement checks.
- Resources — Why unit stats must
duplicate(true) so health/armor never mutate a shared template.
Related Skills
Prerequisites
- godot-project-foundations — Physics ticks, navigation/avoidance project settings, and input map actions before selection and pathing stay deterministic.
- godot-input-handling — Mouse buttons, shift-modifiers, and physics-step sampling that drive marquee select and command queuing.
- godot-navigation-pathfinding — NavigationAgent RVO, maps, layers, and query-object pools this genre's army movement builds on.
Complements
Downstream / consumers
- godot-monte-carlo-balancer — Build-order policies, unit cost curves, and AI opponent strength — simulate win% instead of gut-tuning gather rates.
- godot-performance-optimization — Escalate here when MultiMesh buffers, avoidance, or WorkerThreadPool still dominate the profiler.
- godot-combat-system — Hit/hurt and targeting contracts once move/attack commands need damage resolution.
Master
- godot-master — Library router and mirrored module entry; open when discovering which Domain Skill owns a cross-cutting RTS concern.