Loading...
Loading...
Expert blueprint for real-time strategy games including unit selection (drag box, shift-add), command systems (move, attack, gather), pathfinding (NavigationAgent2D with RVO avoidance), fog of war (SubViewport mask shader), resource economy (gather/build loop), and AI opponents (behavior trees, utility AI). Use for base-building RTS or tactical combat games. Trigger keywords: RTS, unit_selection, command_system, fog_of_war, pathfinding_RVO, resource_economy, command_queue.
npx skill4agent add thedivergentai/gd-agentic-skills godot-genre-rtsMANDATORY: Read the appropriate script before implementing the corresponding pattern.
| Phase | Skills | Purpose |
|---|---|---|
| 1. Controls | | Selection box, camera panning/zoom |
| 2. Units | | Pathfinding, avoidance, states (Idle/Move/Attack) |
| 3. Systems | | Map visibility, grid placement |
| 4. AI | | Enemy commander logic |
| 5. Polish | | Strategic overview, battle feedback |
# 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)# 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()SubViewportColorRectshader_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);
}ArrayResourceNodeDropoffPointNavigationAgent2Davoidance_enabledradiusMultiMeshInstance2DServerNavigationAgent2Dset_velocity()velocity_computed_processUnitManagerUnitsBuildingsResources