Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
thedivergentai avatar

Godot Genre Rts

  • 140 installs
  • 454 repo stars
  • Updated July 28, 2026
  • thedivergentai/gd-agentic-skills

Use godot-genre-rts for development tasks

About

godot-genre-rts: A skill for development. This provides functionality for development workflows.

  • godot-genre-rts

Godot Genre Rts by the numbers

  • 140 all-time installs (skills.sh)
  • +9 installs in the week ending Jul 27, 2026 (Skillselion tracking)
  • Ranked #2,605 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-genre-rts

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs140
repo stars454
Last updatedJuly 28, 2026
Repositorythedivergentai/gd-agentic-skills

What it does

Use godot-genre-rts for development tasks

Files

SKILL.mdMarkdownGitHub ↗

Genre: Real-Time Strategy (RTS)

Expert blueprint for RTS games balancing strategy, micromanagement, and performance.

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 is_equal_approx() 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.multimesh_set_buffer().
  • 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/)

Original Expert Patterns

  • selection_manager_marquee_2d.gd - Professional-grade unit selection system with drag-box, unit filtering, and shift-add support.

Modular Components

  • rts_army_manager.gd - Multithreaded AI update system for managing mass units on background cores.
  • selection_manager_raycast_3d.gd - Optimized 3D selection using direct PhysicsServer raycasting.
  • rts_path_query_pool.gd - Pooled Navigation query system to prevent memory allocations.
  • navigation_mask_helper.gd - Bitmask utilities for dynamic navigation layers and avoidance.
  • rts_targeting_logic.gd - Distance-squared performance optimization for mass enemy filtering.
  • rts_group_commander.gd - SceneTree group broadcasting pattern for decoupled mass units.
  • rts_unit_stat_duplicator.gd - Pattern for deep duplicating unit data for isolation.
  • rts_unit.gd - Comprehensive unit controller with state management and navigation integration.
  • building_grid_astar.gd - High-speed grid-based pathfinding for building placement.
  • fog_of_war_tile_mask.gd - Efficient Fog of War clearing using the TileMapLayer API and Vector2i.
  • rendering_ghost_spawner.gd - Optimized placement ghosts using RenderingServer RIDs.

---

Core Loop

1. Gather: Units collect resources (Gold, Wood, etc.). 2. Build: Construct base buildings to unlock tech/units. 3. Train: Produce an army of diverse units. 4. Command: Micromanage units in real-time battles. 5. Expand: Secure map control and resources.

Skill Chain

PhaseSkillsPurpose
1. Controlsgodot-input-handling, camera-rtsSelection box, camera panning/zoom
2. Unitsnavigation-server, state-machinesPathfinding, avoidance, states (Idle/Move/Attack)
3. Systemsfog-of-war, building-systemMap visibility, grid placement
4. AIbehavior-trees, utility-aiEnemy commander logic
5. Polishui-minimap, godot-particlesStrategic overview, battle feedback

Architecture Overview

1. Selection Manager (Singleton or Commander Node)

Handles mouse input for selecting units.

# selection_manager.gd
extends Node2D

var selected_units: Array[Unit] = []
var drag_start: Vector2
var is_dragging: bool = false
@onready var selection_box: Panel = $SelectionBox

func _unhandled_input(event):
    if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
        if event.pressed:
            start_selection(event.position)
        else:
            end_selection(event.position)
    elif event is InputEventMouseMotion and is_dragging:
        update_selection_box(event.position)

func end_selection(end_pos: Vector2):
    is_dragging = false
    selection_box.visible = false
    var rect = Rect2(drag_start, end_pos - drag_start).abs()
    
    if Input.is_key_pressed(KEY_SHIFT):
        # Add to selection
        pass
    else:
        deselect_all()
        
    # Query physics server for units in rect
    var query = PhysicsShapeQueryParameters2D.new()
    var shape = RectangleShape2D.new()
    shape.size = rect.size
    query.shape = shape
    query.transform = Transform2D(0, rect.get_center())
    # ... execute query and add units to selected_units
    
    for unit in selected_units:
        unit.set_selected(true)

func issue_command(target_position: Vector2):
    for unit in selected_units:
        unit.move_to(target_position)

2. Unit Controller (State Machine)

Units need robust state management to handle commands and auto-attacks.

# unit.gd
extends CharacterBody2D
class_name Unit

enum State { IDLE, MOVE, ATTACK, HOLD }
var state: State = State.IDLE
var command_queue: Array[Command] = []

@onready var nav_agent: NavigationAgent2D = $NavigationAgent2D

func move_to(target: Vector2):
    nav_agent.target_position = target
    state = State.MOVE

func _physics_process(delta):
    if state == State.MOVE:
        if nav_agent.is_navigation_finished():
            state = State.IDLE
            return
            
        var next_pos = nav_agent.get_next_path_position()
        var direction = global_position.direction_to(next_pos)
        velocity = direction * speed
        move_and_slide()

### 3. Group Movement & Flocking
Instead of moving all units directly to a single point (clumping), use **Relative Offsets**:
- Calculate the **Center of Mass** for the selected group.
- On click, calculate each unit's **Relative Offset** from the center.
- Issue `target_position + unit_offset` to each unit to maintain formation.

3. Fog of War

A system to hide unvisited areas. Usually implemented with a texture and a shader.

  • Grid Approach: 2D array of "visibility" values.
  • Viewport Texture: A SubViewport drawing white circles for units on a black background. This texture is then used as a mask in a shader on a full-screen ColorRect overlay.
shader_type canvas_item;
uniform sampler2D visibility_texture; 
uniform vec4 fog_color : source_color;

void fragment() {
    float visibility = texture(visibility_texture, UV).r;
    COLOR = mix(fog_color, vec4(0,0,0,0), visibility);
}

Key Mechanics Implementation

Command Queue

Allow players to chain commands (Shift-Click).

  • Implementation: Store commands in an Array. When one finishes, pop the next.
  • Visuals: Draw lines showing the queued path.

Resource Gathering

  • Nodes: ResourceNode (Tree/GoldMine) and DropoffPoint (TownCenter).
  • Logic:

1. Move to Resource. 2. Work (Timer). 3. Move to Dropoff. 4. Deposit (Global Economy update). 5. Repeat.

Common Pitfalls

1. Pathfinding Jitter: Units pushing each other endlessly. Fix: Use RVO (Reciprocal Velocity Obstacles) built into Godot's NavigationAgent2D (properties avoidance_enabled, radius). 2. Too Much Micro: Automate mundane tasks (auto-attack nearby, auto-gather behavior). 3. Performance: Too many nodes. Fix: Use MultiMeshInstance2D for rendering thousands of units if needed, and run logic on a Server node rather than individual scripts for mass units.

Godot-Specific Tips

  • Avoidance: NavigationAgent2D has built-in RVO avoidance. Make sure to call set_velocity() and use the velocity_computed signal for the actual movement!
  • Server Architecture: For 100+ units, don't use _process on every unit. Have a central UnitManager iterate through active units to save function call overhead.
  • Groups: Use Groups heavily (Units, Buildings, Resources) for easy selection filters.

---

🚀 Elite Technical Implementations (Batch 09)

1. Center-of-Mass Formation Movement Pattern

To prevent CPU bottlenecks when moving hundreds of units, avoid querying individual paths. Instead, calculate the "Center of Mass" of the selection and perform a single NavigationServer3D (or 2D) path query.

class_name RTSFormationManager extends Node

## Moves a group of units in formation to a target destination using a single path query.
static func move_group_to_target(units: Array[CharacterBody3D], target_position: Vector3, map_rid: RID) -> void:
    if units.is_empty():
        return
        
    # 1. Calculate the Center of Mass (Average Position)
    var center_of_mass := Vector3.ZERO
    for unit in units:
        center_of_mass += unit.global_position
    center_of_mass /= units.size()
    
    # 2. Query NavigationServer for the optimized central path
    var central_path: PackedVector3Array = NavigationServer3D.map_get_path(
        map_rid,
        center_of_mass,
        target_position,
        true 
    )
    
    if central_path.is_empty():
        return
        
    var final_center_destination: Vector3 = central_path[central_path.size() - 1]
    
    # 3. Distribute commands with relative offsets to maintain formation
    for unit in units:
        var offset: Vector3 = unit.global_position - center_of_mass
        var unit_destination: Vector3 = final_center_destination + offset
        
        if unit.has_method("set_movement_target"):
            unit.set_movement_target(unit_destination)

2. MultiMeshInstance Rendering for Massive Armies

Standard nodes fail when unit counts reach thousands. Use MultiMeshInstance3D to draw millions of objects in a single draw call via the GPU.

  • Architectural Tip: Pre-allocate the maximum expected units and toggle visibility via visible_instance_count.
  • Performance: Note that individual frustum culling is disabled for MultiMesh instances; the entire group is either drawn or not.
class_name RTSMassiveUnitRenderer extends MultiMeshInstance3D

@export var max_units: int = 10000
@export var unit_mesh: Mesh

func _ready() -> void:
    multimesh = MultiMesh.new()
    multimesh.transform_format = MultiMesh.TRANSFORM_3D
    multimesh.use_colors = true 
    multimesh.instance_count = max_units
    multimesh.mesh = unit_mesh
    multimesh.visible_instance_count = 0

## Sync logical unit transforms to GPU instances
func synchronize_rendering(active_units: Array[Transform3D]) -> void:
    var count: int = min(active_units.size(), max_units)
    multimesh.visible_instance_count = count
    
    for i in range(count):
        multimesh.set_instance_transform(i, active_units[i])

3. SubViewport Fog-of-War System

Avoid complex geometry. Use a SubViewport as a dynamic render target to generate a vision mask (White = Vision, Black = Fog).

Mask Generator Logic:

class_name FogOfWarManager extends SubViewport

@export var terrain_material: ShaderMaterial
@export var world_bounds: Vector2 = Vector2(1024, 1024)

func _ready() -> void:
    disable_3d = true 
    render_target_update_mode = SubViewport.UPDATE_ALWAYS
    
    await RenderingServer.frame_post_draw 
    var fow_texture: ViewportTexture = get_texture()
    terrain_material.set_shader_parameter("fow_mask", fow_texture)
    terrain_material.set_shader_parameter("world_bounds", world_bounds)

Projection Shader (Spatial):

shader_type spatial;
uniform sampler2D fow_mask : hint_default_black, filter_linear;
uniform vec2 world_bounds;
uniform vec3 fog_color : source_color = vec3(0.1, 0.1, 0.15);

void fragment() {
    // Map World X/Z to 2D UV Coordinates
    vec2 fow_uv = (NODE_POSITION_WORLD.xz / world_bounds) + vec2(0.5);
    float visibility = texture(fow_mask, fow_uv).r;
    
    ALBEDO = mix(fog_color, ALBEDO, visibility);
}
  • Master Skill: godot-master

Related skills

Backend & APIsbackendintegrations

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.