Transport Hub building
Forgejo #18, part 5 of #12. The building only - the vessels that do the hauling are #19. Placeable, costed at 30, gated behind a new "Freight Handling" research node hanging off Logistics, with its own info popup, build-menu glyph and map marker. Drawn as an octagonal dock ring with berth arms and a squared-off freight core: deliberately radial-but-flat so it does not read as a small mothership, which is the only structure with swept arms. Its stationed transports are NeonPiece children of one rotating holder, per #10 - the geometry is rasterised once and only the holder's rotation changes, so the traffic costs no redraws. Building._draw()'s match has a catch-all that renders anything unrecognised as a ship crafter, so a missing case is silent and looks almost right. The test checks for the hub's own _hub_traffic holder rather than trusting that something plausible appeared - which caught exactly that: a _ready() patch had silently not applied and the hub was rendering through the crafter branch. The build menu grew a third row. Every button, label and price moved: the old row occupied 332px against a 372px pitch, and three of those do not fit above a 1280px screen. Rows are now shorter (128px buttons, 40px price digits) at a 290px pitch, ending at y=1176. Rendered and looked at - the first attempt tightened the pitch alone and left every price overlapping the row beneath it, which no headless test would have seen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
ff162faef5
commit
823828f3b3
10 changed files with 400 additions and 52 deletions
65
Building.gd
65
Building.gd
|
|
@ -28,6 +28,19 @@ extends Node2D
|
|||
const MOTHERSHIP_COLOR: Color = Color(0.45, 0.9, 0.55)
|
||||
const CRAFTER_COLOR: Color = Color(1.0, 0.72, 0.25)
|
||||
const COMMAND_COLOR: Color = Color(0.55, 0.6, 1.0)
|
||||
const TRANSPORT_HUB_COLOR: Color = Color(0.95, 0.55, 0.85)
|
||||
|
||||
# Transport hub: an octagonal dock ring with berths around it and a freight
|
||||
# core in the middle. Deliberately radial-but-flat, so it does not read as a
|
||||
# small mothership - the mothership is the only thing with swept arms.
|
||||
const HUB_RING_RADIUS: float = 74.0
|
||||
const HUB_DECK_RADIUS: float = 54.0
|
||||
const HUB_CORE_RADIUS: float = 22.0
|
||||
const HUB_BERTH_COUNT: int = 8
|
||||
const HUB_BERTH_LENGTH: float = 20.0
|
||||
const HUB_DOCKED_COUNT: int = 3
|
||||
const HUB_DOCKED_ORBIT: float = 96.0
|
||||
const HUB_SPIN_SPEED: float = 0.22
|
||||
# The vessel on the assembly line is drawn in the fleet's own colour, so it
|
||||
# reads as "one of yours being built" rather than as shipyard machinery.
|
||||
const HULL_COLOR: Color = Color(0.25, 0.85, 1.0)
|
||||
|
|
@ -85,6 +98,8 @@ var _hoist: NeonPiece = null
|
|||
var _sparks: Node2D = null
|
||||
var _hull_holder: Node2D = null
|
||||
var _hull_pieces: Array = []
|
||||
# Rotating holder for the transports stationed at a transport hub (#18).
|
||||
var _hub_traffic: Node2D = null
|
||||
var _flash_ring: NeonPiece = null
|
||||
var _wash: NeonPiece = null
|
||||
|
||||
|
|
@ -103,6 +118,8 @@ func _ready() -> void:
|
|||
_build_crafter_pieces()
|
||||
elif building_type == GameState.BUILDING_MOTHERSHIP:
|
||||
_build_mothership_pieces()
|
||||
elif building_type == GameState.BUILDING_TRANSPORT_HUB:
|
||||
_build_hub_pieces()
|
||||
queue_redraw()
|
||||
|
||||
|
||||
|
|
@ -121,6 +138,8 @@ func apply_animation() -> void:
|
|||
_animate_mothership()
|
||||
GameState.BUILDING_SHIP_CRAFTER:
|
||||
_animate_crafter()
|
||||
GameState.BUILDING_TRANSPORT_HUB:
|
||||
_animate_transport_hub()
|
||||
|
||||
|
||||
# Where the satellites are, and how open the reactor core is. Both are read
|
||||
|
|
@ -161,6 +180,8 @@ func _draw() -> void:
|
|||
_draw_command_center()
|
||||
GameState.BUILDING_MOTHERSHIP:
|
||||
_draw_mothership_static(self)
|
||||
GameState.BUILDING_TRANSPORT_HUB:
|
||||
_draw_transport_hub_static(self)
|
||||
_:
|
||||
_draw_crafter_static(self)
|
||||
|
||||
|
|
@ -203,6 +224,50 @@ const CMD_TOKEN_RADIUS: float = 9.0
|
|||
const CMD_STUD_RADIUS: float = 7.0
|
||||
|
||||
|
||||
# --- transport hub --------------------------------------------------------
|
||||
|
||||
func _draw_transport_hub_static(target: CanvasItem) -> void:
|
||||
var c: Color = TRANSPORT_HUB_COLOR
|
||||
|
||||
# Dock ring and the deck nested inside it.
|
||||
NeonDraw.draw_glowing_polygon(target, _ring(Vector2.ZERO, HUB_RING_RADIUS, HUB_BERTH_COUNT, PI / 8.0), c, 1.0)
|
||||
NeonDraw.draw_glowing_polygon(target, _ring(Vector2.ZERO, HUB_DECK_RADIUS, HUB_BERTH_COUNT, PI / 8.0), c, 0.45, NeonDraw.DEFAULT_CORE, 0.7)
|
||||
|
||||
# Freight core: a squared-off hold rather than a reactor, so it reads as
|
||||
# storage and not as another power plant.
|
||||
NeonDraw.draw_glowing_polygon(target, _ring(Vector2.ZERO, HUB_CORE_RADIUS, 4, PI / 4.0), c, 0.95)
|
||||
|
||||
for i in range(HUB_BERTH_COUNT):
|
||||
var a: float = (float(i) / HUB_BERTH_COUNT) * TAU + PI / 8.0
|
||||
var dir: Vector2 = Vector2(cos(a), sin(a))
|
||||
NeonDraw.draw_glowing_line(target, dir * HUB_CORE_RADIUS, dir * HUB_DECK_RADIUS, c, 0.5, 0.32)
|
||||
# Berth arm standing off the ring, where a transporter parks.
|
||||
NeonDraw.draw_glowing_line(target, dir * HUB_RING_RADIUS,
|
||||
dir * (HUB_RING_RADIUS + HUB_BERTH_LENGTH), c, 0.75, 0.38)
|
||||
|
||||
|
||||
func _build_hub_pieces() -> void:
|
||||
# Stationed transports, as NeonPiece children of one holder that turns.
|
||||
# Per #10 the geometry is rasterised once and only the holder's rotation
|
||||
# changes, so the traffic costs no redraws at all.
|
||||
_hub_traffic = Node2D.new()
|
||||
add_child(_hub_traffic)
|
||||
for i in range(HUB_DOCKED_COUNT):
|
||||
var a: float = (float(i) / HUB_DOCKED_COUNT) * TAU
|
||||
var at: Vector2 = Vector2(cos(a), sin(a)) * HUB_DOCKED_ORBIT
|
||||
var piece: NeonPiece = NeonPiece.create(_hub_traffic, at, TRANSPORT_HUB_COLOR)
|
||||
# A stubby freighter: blunt, boxy, nothing like the fleet's darts.
|
||||
piece.add_polygon(PackedVector2Array([
|
||||
Vector2(-9, -5), Vector2(9, -5), Vector2(12, 0), Vector2(9, 5), Vector2(-9, 5),
|
||||
]))
|
||||
piece.rotation = a + PI / 2.0
|
||||
piece.queue_redraw()
|
||||
|
||||
|
||||
func _animate_transport_hub() -> void:
|
||||
_hub_traffic.rotation = phase_time * HUB_SPIN_SPEED
|
||||
|
||||
|
||||
func _diamond(centre: Vector2, r: float) -> PackedVector2Array:
|
||||
return PackedVector2Array([
|
||||
centre + Vector2(0, -r), centre + Vector2(r, 0),
|
||||
|
|
|
|||
Loading…
Reference in a new issue