Show buildings on the world map, and extractors on their planets
Forgejo #11: buildings the player has placed now appear on the world map. They are placed freely in space rather than tied to a chunk, so they get their own pass in WorldMapContent._draw() rather than riding along with the chunk markers. Each type has its own shape and colour, mirroring Building.gd's constants so a marker reads as the same building you built. Forgejo #9: a planet with an extractor built on it now shows it, in both places you look at a planet - an amber derrick on its outline in space, and a matching badge on its world-map marker. The extractor lives on PlanetSurface.tscn, a scene you are not looking at from space, so an already-mined planet was otherwise indistinguishable from an untouched one until you landed on it. The positioning steps are factored out (building_markers(), chunk_has_extractor_badge(), extractor_derrick_tip()) so headless tests can assert on them - --headless has no GPU and draws no pixels, so there is nothing to check in _draw() itself. Both features were also rendered for real via tests/screenshot.sh and looked at. extractor_derrick_tip() exists because the first version of the "derrick is not buried inside the planet" check measured the furthest of all four derrick points, which passes a derrick pointing straight into the ground: the base corners sit a half-width off the rim vertex and clear the outline on their own. Mutation-testing caught it. screenshot.sh now clears a stale /tmp/.X99-lock. A run killed mid-screenshot leaves it behind and Xvfb then refuses :99, which resurfaces later as Godot's misleading "X11 Display is not available". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
b641fa5891
commit
8dd5d7b78f
13 changed files with 472 additions and 0 deletions
|
|
@ -2,6 +2,23 @@ extends Node2D
|
|||
|
||||
const WORLD_TO_LOCAL: float = 0.04
|
||||
|
||||
# Mirrors Building.gd's own MOTHERSHIP_COLOR/CRAFTER_COLOR/COMMAND_COLOR so a
|
||||
# marker on the map reads as "the same building" at a glance. Duplicated
|
||||
# rather than cross-referenced - the same colour is already independently
|
||||
# duplicated between Ship.gd, Fleet.gd and Building.gd's HULL_COLOR, so this
|
||||
# follows the codebase's existing convention rather than inventing a new one.
|
||||
const MOTHERSHIP_MARKER_COLOR: Color = Color(0.45, 0.9, 0.55)
|
||||
const CRAFTER_MARKER_COLOR: Color = Color(1.0, 0.72, 0.25)
|
||||
const COMMAND_MARKER_COLOR: Color = Color(0.55, 0.6, 1.0)
|
||||
|
||||
# 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
|
||||
|
||||
@onready var tracker: Node2D = get_node("../../../ExplorationTracker")
|
||||
@onready var fleet: Node2D = get_node("../../../Fleet")
|
||||
|
||||
|
|
@ -11,6 +28,59 @@ func _process(_delta: float) -> void:
|
|||
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:
|
||||
markers.append({
|
||||
"position": b.position * WORLD_TO_LOCAL,
|
||||
"type": b.type,
|
||||
"color": _building_marker_color(b.type),
|
||||
})
|
||||
return markers
|
||||
|
||||
|
||||
func _building_marker_color(type: String) -> Color:
|
||||
match type:
|
||||
GameState.BUILDING_MOTHERSHIP:
|
||||
return MOTHERSHIP_MARKER_COLOR
|
||||
GameState.BUILDING_SHIP_CRAFTER:
|
||||
return CRAFTER_MARKER_COLOR
|
||||
_:
|
||||
return COMMAND_MARKER_COLOR
|
||||
|
||||
|
||||
# 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).name)
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
|
@ -32,6 +102,22 @@ func _draw() -> void:
|
|||
draw_circle(planet_local, 5.0, Color(0.7, 0.65, 0.55))
|
||||
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():
|
||||
match marker.type:
|
||||
GameState.BUILDING_MOTHERSHIP:
|
||||
_draw_marker_polygon(_regular_polygon(marker.position, 8.0, 6, PI / 6.0), marker.color)
|
||||
GameState.BUILDING_SHIP_CRAFTER:
|
||||
_draw_marker_polygon(_regular_polygon(marker.position, 7.0, 4, 0.0), marker.color)
|
||||
_:
|
||||
_draw_marker_polygon(_regular_polygon(marker.position, 6.0, 4, PI / 4.0), marker.color)
|
||||
|
||||
var fleet_local: Vector2 = fleet.get_centroid() * WORLD_TO_LOCAL
|
||||
var marker_points: PackedVector2Array = PackedVector2Array([
|
||||
fleet_local + Vector2(0, -10),
|
||||
|
|
|
|||
Loading…
Reference in a new issue