Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019AJMdB7iuHuLFZM1aBu3GD
137 lines
5.8 KiB
GDScript
137 lines
5.8 KiB
GDScript
extends Node2D
|
|
|
|
const PLANET_DEFINITIONS = preload("res://planets/PlanetDefinitions.gd")
|
|
const BUILDING_DEFINITIONS = preload("res://buildings/BuildingDefinitions.gd")
|
|
|
|
const WORLD_TO_LOCAL: float = 0.04
|
|
|
|
# A structure built on a planet's surface (see GameState.extractors) is not
|
|
# itself a map marker - it is a small badge on the existing planet marker,
|
|
# in a colour distinct from both the planets and the space buildings so it
|
|
# reads as "something is mined here" rather than another building type.
|
|
const EXTRACTOR_BADGE_COLOR: Color = Color(1.0, 0.85, 0.3)
|
|
const EXTRACTOR_BADGE_OFFSET: Vector2 = Vector2(8.0, -8.0)
|
|
const EXTRACTOR_BADGE_RADIUS: float = 5.0
|
|
const SCANNER_TARGET_COLOR: Color = Color(0.3, 0.95, 1.0)
|
|
|
|
@onready var tracker: Node2D = get_node("../../../ExplorationTracker")
|
|
@onready var fleet: Node2D = get_node("../../../Fleet")
|
|
|
|
|
|
func _process(_delta: float) -> void:
|
|
if is_visible_in_tree():
|
|
queue_redraw()
|
|
|
|
|
|
# Local-space marker data for every player-placed building (GameState.
|
|
# buildings), one entry per building with its colour already resolved. Kept
|
|
# as a separate, callable step (rather than inlined in _draw()) so a
|
|
# headless test - which has no GPU and cannot check drawn pixels - can
|
|
# verify a built building actually produces a marker.
|
|
func building_markers() -> Array:
|
|
var markers: Array = []
|
|
for b in GameState.buildings:
|
|
var definition: Resource = BUILDING_DEFINITIONS.get_definition(String(b.type))
|
|
if definition == null:
|
|
continue
|
|
markers.append({
|
|
"position": b.position * WORLD_TO_LOCAL,
|
|
"type": b.type,
|
|
"color": definition.map_color,
|
|
"sides": definition.map_sides,
|
|
"radius": definition.map_radius,
|
|
"phase": definition.map_phase,
|
|
})
|
|
return markers
|
|
|
|
|
|
# Whether the planet in this (explored) chunk has an extractor on it, per
|
|
# GameState.has_extractor_at(). A separate predicate for the same
|
|
# GPU-less-testability reason as building_markers().
|
|
func chunk_has_extractor_badge(chunk: Vector2i) -> bool:
|
|
if not WorldGen.has_planet_at_chunk(chunk):
|
|
return false
|
|
return GameState.has_extractor_at(WorldGen.planet_data_at_chunk(chunk).planet_id)
|
|
|
|
|
|
func scanner_target_marker() -> Dictionary:
|
|
var target: Dictionary = GameState.active_scanner_target()
|
|
if target.is_empty():
|
|
return {}
|
|
return {
|
|
"position": Vector2(target.world_position) * WORLD_TO_LOCAL,
|
|
"planet_id": String(target.planet_id),
|
|
"definition_id": String(target.definition_id),
|
|
}
|
|
|
|
|
|
func _regular_polygon(center: Vector2, radius: float, sides: int, phase: float = 0.0) -> PackedVector2Array:
|
|
var pts: PackedVector2Array = PackedVector2Array()
|
|
for i in range(sides):
|
|
var a: float = (float(i) / float(sides)) * TAU + phase
|
|
pts.append(center + Vector2(cos(a), sin(a)) * radius)
|
|
return pts
|
|
|
|
|
|
# Filled shape plus a thin white outline - the same construction the fleet
|
|
# marker below already uses, just factored out since buildings now need it
|
|
# three times over (once per type) and the extractor badge needs it too.
|
|
func _draw_marker_polygon(pts: PackedVector2Array, color: Color) -> void:
|
|
draw_colored_polygon(pts, color)
|
|
var closed: PackedVector2Array = pts.duplicate()
|
|
closed.append(pts[0])
|
|
draw_polyline(closed, Color(1, 1, 1), 1.5, true)
|
|
|
|
|
|
func _draw() -> void:
|
|
var chunk_size_local: float = WorldGen.CHUNK_SIZE * WORLD_TO_LOCAL
|
|
|
|
for chunk in tracker.get_explored_chunks():
|
|
var origin_local: Vector2 = WorldGen.chunk_origin(chunk) * WORLD_TO_LOCAL
|
|
var biome: int = WorldGen.biome_at_chunk(chunk)
|
|
var color: Color = WorldGen.biome_color(biome)
|
|
var rect: Rect2 = Rect2(origin_local, Vector2(chunk_size_local, chunk_size_local))
|
|
draw_rect(rect, color, true)
|
|
draw_rect(rect, Color(0.0, 0.0, 0.0, 0.4), false, 1.5)
|
|
|
|
if WorldGen.has_planet_at_chunk(chunk):
|
|
# Same deterministic per-chunk data PlanetField spawns the
|
|
# actual Planet from - the marker stays put on the map even
|
|
# for a chunk whose Planet node isn't currently loaded (out of
|
|
# spawn_radius_chunks of the fleet).
|
|
var data: Dictionary = WorldGen.planet_data_at_chunk(chunk)
|
|
var planet_local: Vector2 = origin_local + data.local_pos * WORLD_TO_LOCAL
|
|
var definition: Resource = PLANET_DEFINITIONS.get_definition(String(data.definition_id))
|
|
draw_circle(planet_local, 5.0, definition.map_color)
|
|
draw_arc(planet_local, 5.0, 0.0, TAU, 16, Color(1.0, 1.0, 1.0, 0.9), 1.0, true)
|
|
|
|
if chunk_has_extractor_badge(chunk):
|
|
var badge_pts: PackedVector2Array = _regular_polygon(
|
|
planet_local + EXTRACTOR_BADGE_OFFSET, EXTRACTOR_BADGE_RADIUS, 4, PI / 4.0)
|
|
_draw_marker_polygon(badge_pts, EXTRACTOR_BADGE_COLOR)
|
|
|
|
# Buildings are placed freely in space rather than tied to a chunk, so
|
|
# they get their own pass rather than living inside the chunk loop above.
|
|
for marker in building_markers():
|
|
_draw_marker_polygon(_regular_polygon(marker.position, marker.radius, marker.sides, marker.phase), marker.color)
|
|
|
|
# A scan is an intentional destination, distinct from passive exploration.
|
|
# Draw its reticle independently of the explored-chunk pass so the point is
|
|
# guaranteed to remain visible even when it lies beyond travelled space.
|
|
var scan_marker: Dictionary = scanner_target_marker()
|
|
if not scan_marker.is_empty():
|
|
var target_position := Vector2(scan_marker.position)
|
|
draw_arc(target_position, 11.0, 0.0, TAU, 24,
|
|
SCANNER_TARGET_COLOR, 2.5, true)
|
|
for direction in [Vector2.LEFT, Vector2.RIGHT, Vector2.UP, Vector2.DOWN]:
|
|
draw_line(target_position + direction * 13.0,
|
|
target_position + direction * 19.0, SCANNER_TARGET_COLOR, 2.0, true)
|
|
|
|
var fleet_local: Vector2 = fleet.get_centroid() * WORLD_TO_LOCAL
|
|
var marker_points: PackedVector2Array = PackedVector2Array([
|
|
fleet_local + Vector2(0, -10),
|
|
fleet_local + Vector2(7, 8),
|
|
fleet_local + Vector2(-7, 8),
|
|
])
|
|
draw_colored_polygon(marker_points, Color(0.3, 0.9, 1.0))
|
|
draw_polyline(PackedVector2Array([marker_points[0], marker_points[1], marker_points[2], marker_points[0]]), Color(1, 1, 1), 1.5, true)
|