spaceship/Planet.gd
2026-08-14 22:16:40 +02:00

123 lines
4.6 KiB
GDScript

extends Node2D
const PLANET_DEFINITIONS = preload("res://PlanetDefinitions.gd")
# A landable world-object - unlike regular Asteroid.gd, planets are
# stationary ("Big Stable Asteroid" - stable means it doesn't drift or
# destroy ships on touch). Whether the fleet counts as "landed" is decided
# by PlanetField comparing the fleet's CENTROID distance to landing_radius,
# not per-ship Area2D collision - a single stable number, immune to the
# constant minor jostling of individual ships holding formation, which
# used to make the "enter atmosphere" prompt flicker on/off as ships
# drifted in and out of the boundary independently of each other even
# while the fleet as a whole was clearly sitting on the planet.
@export var planet_name: String = ""
@export var planet_id: String = ""
@export var definition_id: String = PLANET_DEFINITIONS.DEFAULT_DEFINITION_ID
@export var landing_radius: float = 140.0
# Set by whoever spawns this planet (PlanetField, seeded from the chunk's
# own coordinates) so the outline shape is stable across respawns of the
# same chunk, instead of reading as a "different" planet every time.
@export var shape_seed: int = 0
var definition: Resource
var visual: Node2D
var resource_type: String:
get: return String(definition.resource_id) if definition != null else "ore"
var surface_profile_id: String:
get: return String(definition.surface_profile_id) if definition != null else "rocky"
var shape_points: PackedVector2Array:
get:
if visual != null and "shape_points" in visual:
return visual.shape_points
return PackedVector2Array()
var gas_phase: float:
get:
if visual != null and "gas_phase" in visual:
return float(visual.gas_phase)
return 0.0
# An extractor is built down on this planet's SURFACE, in a different scene
# the player is no longer looking at, so from space nothing distinguished a
# planet already being mined from an untouched one - you had to land to find
# out. This is a derrick planted on the rim: the same amber the world map
# uses for its extractor badge, so the two read as the same fact.
const EXTRACTOR_MARKER_COLOR: Color = Color(1.0, 0.85, 0.3)
const DERRICK_HEIGHT: float = 44.0
const DERRICK_HALF_WIDTH: float = 16.0
# Kept in step with GameState.extractor_added rather than polled per frame.
# An extractor is built from SPACE (BuildController._planet_under_fleet(),
# with the fleet parked on the planet), so this node is already in the tree
# with its _ready() long since run when the answer changes - resolving it
# only at _ready() left the planet looking untouched until it happened to
# despawn and respawn.
var shows_extractor: bool = false
func _ready() -> void:
add_to_group("planets")
z_index = -1
definition = PLANET_DEFINITIONS.get_definition(definition_id)
visual = definition.visual_scene.instantiate()
visual.configure(shape_seed)
get_node("VisualHost").add_child(visual)
if planet_id == "":
planet_id = planet_name
shows_extractor = GameState.has_extractor_at(planet_id)
GameState.extractor_added.connect(_on_extractor_added)
queue_redraw()
func _on_extractor_added(built_on: String) -> void:
# Only the planet it was actually built on, and only a redraw when the
# answer really changed - every other planet in range gets this too.
if built_on != planet_id or shows_extractor:
return
shows_extractor = true
queue_redraw()
func extractor_derrick_anchor() -> Vector2:
if visual != null and visual.has_method("extractor_anchor"):
return visual.extractor_anchor()
return Vector2(0.0, -100.0)
func extractor_derrick_tip() -> Vector2:
# Exposed separately from the polygon because "does the derrick clear the
# planet's outline" is a question about the TIP alone. The base corners
# sit a half-width off to either side, so they are sqrt(|base|^2 + w^2)
# from the centre and can clear the rim on their own even when the tower
# points straight into the ground.
var base: Vector2 = extractor_derrick_anchor()
var out: Vector2 = base.normalized()
if out == Vector2.ZERO:
out = Vector2.UP
return base + out * DERRICK_HEIGHT
func extractor_derrick_points() -> PackedVector2Array:
var base: Vector2 = extractor_derrick_anchor()
var out: Vector2 = base.normalized()
if out == Vector2.ZERO:
out = Vector2.UP
var side: Vector2 = Vector2(-out.y, out.x)
var tip: Vector2 = extractor_derrick_tip()
return PackedVector2Array([
base - side * DERRICK_HALF_WIDTH,
tip - side * (DERRICK_HALF_WIDTH * 0.35),
tip + side * (DERRICK_HALF_WIDTH * 0.35),
base + side * DERRICK_HALF_WIDTH,
])
func _draw() -> void:
if shows_extractor:
NeonDraw.draw_glowing_polygon(self, extractor_derrick_points(), EXTRACTOR_MARKER_COLOR, 1.0)