Animate ship crafter deliveries
This commit is contained in:
parent
fc68c4e8cf
commit
798deb48a1
5 changed files with 140 additions and 4 deletions
33
GameState.gd
33
GameState.gd
|
|
@ -308,6 +308,11 @@ var next_building_id: int = 1
|
|||
# Production is simulated here, in the autoload, the same way extractor
|
||||
# haulers are, so a build finishes whether or not the player is in space.
|
||||
var stored_vessels: Array = []
|
||||
# Finished crafter orders travel to the mothership before appearing in its
|
||||
# hangar. State is authoritative here so delivery continues off-screen.
|
||||
# {"type", "from", "to", "progress"}
|
||||
var vessel_deliveries: Array = []
|
||||
const VESSEL_DELIVERY_SPEED: float = 950.0
|
||||
|
||||
signal order_completed(building_id: int, type: String)
|
||||
|
||||
|
|
@ -695,9 +700,15 @@ func _advance_production(delta: float) -> void:
|
|||
# hub and wait for work (#19).
|
||||
_station_transporter(b.position)
|
||||
else:
|
||||
# Everything else is delivered to the mothership and waits there
|
||||
# until the player crews it (#23).
|
||||
stored_vessels.append(product)
|
||||
# A finished hull launches from the crafter and physically flies to
|
||||
# the mothership hangar. With no mothership there is nowhere to fly,
|
||||
# so preserve the old safe fallback of holding it immediately.
|
||||
var mothership: Variant = get_mothership_position()
|
||||
if mothership == null:
|
||||
stored_vessels.append(product)
|
||||
else:
|
||||
vessel_deliveries.append({"type": product, "from": b.position,
|
||||
"to": mothership, "progress": 0.0})
|
||||
order_completed.emit(int(b.id), product)
|
||||
|
||||
|
||||
|
|
@ -818,6 +829,7 @@ func _process(delta: float) -> void:
|
|||
# Runs in the autoload, so mining and transport continue while the player
|
||||
# is on a planet's surface or nowhere near either.
|
||||
_advance_production(delta)
|
||||
_advance_vessel_deliveries(delta)
|
||||
for e in extractors:
|
||||
e.mining_progress = float(e.get("mining_progress", 0.0)) + delta * EXTRACTOR_RATE
|
||||
var whole: int = int(floor(float(e.mining_progress)))
|
||||
|
|
@ -827,6 +839,21 @@ func _process(delta: float) -> void:
|
|||
_advance_transporters(delta)
|
||||
|
||||
|
||||
func vessel_delivery_position(delivery: Dictionary) -> Vector2:
|
||||
return (delivery.from as Vector2).lerp(delivery.to as Vector2,
|
||||
clampf(float(delivery.progress), 0.0, 1.0))
|
||||
|
||||
|
||||
func _advance_vessel_deliveries(delta: float) -> void:
|
||||
for i in range(vessel_deliveries.size() - 1, -1, -1):
|
||||
var delivery: Dictionary = vessel_deliveries[i]
|
||||
var distance: float = (delivery.from as Vector2).distance_to(delivery.to as Vector2)
|
||||
delivery.progress = float(delivery.progress) + delta / maxf(distance / VESSEL_DELIVERY_SPEED, 0.001)
|
||||
if float(delivery.progress) >= 1.0:
|
||||
stored_vessels.append(String(delivery.type))
|
||||
vessel_deliveries.remove_at(i)
|
||||
|
||||
|
||||
# --- transporters (#19) ---------------------------------------------------
|
||||
|
||||
# Vessels stationed at a transport hub that fetch ore from the mothership and
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=22 format=3]
|
||||
[gd_scene load_steps=23 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Starfield.gd" id="1"]
|
||||
[ext_resource type="Script" path="res://Fleet.gd" id="2"]
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
[ext_resource type="Script" path="res://TransporterField.gd" id="23"]
|
||||
[ext_resource type="Script" path="res://ResourceBar.gd" id="24"]
|
||||
[ext_resource type="Script" path="res://GasCounter.gd" id="25"]
|
||||
[ext_resource type="Script" path="res://VesselDeliveryField.gd" id="26"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="1"]
|
||||
shader = ExtResource("5")
|
||||
|
|
@ -74,6 +75,9 @@ script = ExtResource("14")
|
|||
[node name="TransporterField" type="Node2D" parent="."]
|
||||
script = ExtResource("23")
|
||||
|
||||
[node name="VesselDeliveryField" type="Node2D" parent="."]
|
||||
script = ExtResource("26")
|
||||
|
||||
[node name="BuildController" type="Node2D" parent="."]
|
||||
script = ExtResource("15")
|
||||
|
||||
|
|
|
|||
16
VesselDelivery.gd
Normal file
16
VesselDelivery.gd
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
extends Node2D
|
||||
|
||||
# Visual-only craft-to-mothership flight. GameState owns position/progress;
|
||||
# this node just renders a finished hull headed toward the hangar.
|
||||
var vessel_type: String = GameState.VESSEL_INTERCEPTOR
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
z_index = -1
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
var color: Color = Color(0.45, 0.8, 1.0) if vessel_type == GameState.VESSEL_SHIELD else Color(0.95, 0.55, 0.85) if vessel_type == GameState.VESSEL_TRANSPORTER else Color(0.25, 0.85, 1.0)
|
||||
var hull := PackedVector2Array([Vector2(0, -20), Vector2(13, 15), Vector2(0, 9), Vector2(-13, 15)])
|
||||
NeonDraw.draw_glowing_polygon(self, hull, color, 1.0)
|
||||
37
VesselDeliveryField.gd
Normal file
37
VesselDeliveryField.gd
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
extends Node2D
|
||||
|
||||
@export var visible_radius: float = 2600.0
|
||||
@onready var fleet: Node2D = get_node("../Fleet")
|
||||
var delivery_script: Script = preload("res://VesselDelivery.gd")
|
||||
var active: Dictionary = {}
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
var centre: Vector2 = fleet.get_centroid()
|
||||
for i in range(GameState.vessel_deliveries.size()):
|
||||
var delivery: Dictionary = GameState.vessel_deliveries[i]
|
||||
var pos := GameState.vessel_delivery_position(delivery)
|
||||
if pos.distance_to(centre) > visible_radius:
|
||||
_despawn(i)
|
||||
continue
|
||||
var node: Node2D = active.get(i)
|
||||
if node == null or not is_instance_valid(node):
|
||||
node = delivery_script.new()
|
||||
get_parent().add_child(node)
|
||||
active[i] = node
|
||||
node.vessel_type = String(delivery.type)
|
||||
node.position = pos
|
||||
var direction: Vector2 = (delivery.to as Vector2) - (delivery.from as Vector2)
|
||||
if direction.length() > 0.1:
|
||||
node.rotation = direction.angle() + PI / 2.0
|
||||
node.queue_redraw()
|
||||
for key in active.keys():
|
||||
if key >= GameState.vessel_deliveries.size():
|
||||
_despawn(key)
|
||||
|
||||
|
||||
func _despawn(index: int) -> void:
|
||||
var node: Node2D = active.get(index)
|
||||
if node != null and is_instance_valid(node):
|
||||
node.queue_free()
|
||||
active.erase(index)
|
||||
52
tests/test_vessel_delivery.gd
Normal file
52
tests/test_vessel_delivery.gd
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
extends SceneTree
|
||||
|
||||
# Forgejo #28: a completed crafter order visibly travels to the mothership,
|
||||
# rather than appearing in the hangar at the instant the build timer ends.
|
||||
var game_state: Node
|
||||
var scene: Node
|
||||
var stage := 0
|
||||
var elapsed := 0.0
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
game_state = root.get_node("GameState")
|
||||
game_state.buildings.clear()
|
||||
game_state.extractors.clear()
|
||||
game_state.transporters.clear()
|
||||
game_state.vessel_deliveries.clear()
|
||||
game_state.stored_vessels.clear()
|
||||
game_state.build_time_scale = 0.02
|
||||
game_state.add_building(GameState.BUILDING_MOTHERSHIP, Vector2.ZERO)
|
||||
game_state.add_building(GameState.BUILDING_SHIP_CRAFTER, Vector2(900, 0))
|
||||
game_state.deposit_to_building(2, GameState.SHIP_COST)
|
||||
game_state.queue_order(2, GameState.PRODUCT_SHIP)
|
||||
scene = load("res://Main.tscn").instantiate()
|
||||
root.add_child(scene)
|
||||
|
||||
|
||||
func _process(delta: float) -> bool:
|
||||
elapsed += delta
|
||||
if stage == 0 and not game_state.vessel_deliveries.is_empty():
|
||||
if not game_state.stored_vessels.is_empty():
|
||||
return _fail("ship reached hangar before its delivery flight")
|
||||
var field: Node = scene.get_node("VesselDeliveryField")
|
||||
if field.active.is_empty():
|
||||
return _fail("delivery flight was not rendered")
|
||||
print("finished ship launched from crafter toward mothership")
|
||||
stage = 1
|
||||
if stage == 1 and game_state.vessel_deliveries.is_empty():
|
||||
if game_state.stored_vessels.size() != 1:
|
||||
return _fail("delivered ship did not arrive in hangar")
|
||||
print("delivery arrived in mothership hangar")
|
||||
print("TEST_VESSEL_DELIVERY: PASS")
|
||||
quit(0)
|
||||
return true
|
||||
if elapsed > 8.0:
|
||||
return _fail("delivery timed out")
|
||||
return false
|
||||
|
||||
|
||||
func _fail(message: String) -> bool:
|
||||
print("TEST_VESSEL_DELIVERY: FAIL (%s)" % message)
|
||||
quit(1)
|
||||
return true
|
||||
Loading…
Reference in a new issue