Skip to content

Commit

Permalink
Multi-step jump paths in galaxy map
Browse files Browse the repository at this point in the history
Resolves #54.
  • Loading branch information
jspahrsummers committed Aug 23, 2024
2 parents 6ed0530 + cbe9a49 commit 9a54d98
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 59 deletions.
13 changes: 9 additions & 4 deletions actors/player.gd
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ func _on_hyperdrive_changed() -> void:

func _next_system_connection() -> StarSystem:
var current_destination_name: Variant = null
if self.ship.hyperdrive_system.jump_destination:
current_destination_name = self.ship.hyperdrive_system.jump_destination.name
if self.ship.hyperdrive_system.get_jump_destination():
current_destination_name = self.ship.hyperdrive_system.get_jump_destination().name

var current_system := self.ship.hyperdrive_system.current_system()
var galaxy: Galaxy = current_system.galaxy.get_ref()
Expand Down Expand Up @@ -175,7 +175,12 @@ func _unhandled_key_input(event: InputEvent) -> void:
return

if event.is_action_pressed("cycle_jump_destination", true):
self.ship.hyperdrive_system.jump_destination = self._next_system_connection()
var next_system := self._next_system_connection()
if next_system:
self.ship.hyperdrive_system.set_jump_path([next_system])
else:
self.ship.hyperdrive_system.clear_jump_path()

self.get_viewport().set_input_as_handled()

if event.is_action_pressed("cycle_target", true):
Expand Down Expand Up @@ -212,7 +217,7 @@ func _on_broadcasted_input_event(receiver: Node, event: InputEvent) -> void:
return

func _jump_to_hyperspace() -> void:
if not self.ship.hyperdrive_system.jump_destination:
if not self.ship.hyperdrive_system.get_jump_destination():
return

if not self.hyperspace_scene_switcher.start_jump():
Expand Down
100 changes: 74 additions & 26 deletions galaxy/map/galaxy_map.gd
Original file line number Diff line number Diff line change
Expand Up @@ -34,31 +34,40 @@ var hyperdrive_system: HyperdriveSystem
## Maps from each [member StarSystem.name] to the [GalaxyMapSystem] used to represent it.
var _system_nodes: Dictionary = {}

## Maps from a hyperlane's name to the [GalaxyMapHyperlane] used to represent it.
##
## Hyperlane names are formatted as "from > to".
var _hyperlane_nodes: Dictionary = {}

func _ready() -> void:
self.hyperdrive_system.jumping_changed.connect(_on_jumping_changed)
self.hyperdrive_system.jump_destination_changed.connect(_on_jump_destination_changed)
self.hyperdrive_system.jump_path_changed.connect(_on_jump_path_changed)

var current_system := self.hyperdrive_system.current_system()

for system in galaxy.systems:
var system_node: GalaxyMapSystem = self.galaxy_map_system.instantiate()
self._system_nodes[system.name] = system_node
system_node.clicked.connect(func(node: GalaxyMapSystem) -> void: self._on_system_clicked(system, node))

system_node.clicked.connect(func(node: GalaxyMapSystem) -> void: self._on_system_clicked(system))
system_node.name = system.name
system_node.current = (system == current_system)
self._system_nodes[system.name] = system_node
self.galaxy_map_3d.add_child(system_node)

system_node.transform.origin = system.position

for connection in system.connections:
var reverse_name := "%s > %s" % [connection, system.name]
if reverse_name in self._hyperlane_nodes:
# Only create one lane even if it's bidirectional
continue

var connected_system := self.galaxy.get_system(connection)
var hyperlane: GalaxyMapHyperlane = self.galaxy_map_hyperlane.instantiate()
hyperlane.clicked.connect(func(node: GalaxyMapHyperlane) -> void: self._on_hyperlane_clicked(system, connected_system, node))

hyperlane.clicked.connect(func(_node: GalaxyMapHyperlane) -> void: self._on_hyperlane_clicked(system, connected_system))
hyperlane.name = "%s > %s" % [system.name, connection]
hyperlane.starting_position = system.position
hyperlane.ending_position = connected_system.position
self._hyperlane_nodes[hyperlane.name] = hyperlane
self.galaxy_map_3d.add_child(hyperlane)

self._update_selection_state()
Expand All @@ -74,21 +83,41 @@ func _on_jumping_changed(_hyperdrive_system: HyperdriveSystem) -> void:
self.camera.center = new_system.position
self._system_nodes[new_system.name].current = true

func _on_jump_destination_changed(_hyperdrive_system: HyperdriveSystem) -> void:
func _on_jump_path_changed(_hyperdrive_system: HyperdriveSystem) -> void:
assert(self.hyperdrive_system == _hyperdrive_system)
self._update_selection_state()

func _update_selection_state() -> void:
var current_system := self.hyperdrive_system.current_system()

var jump_path := self.hyperdrive_system.get_jump_path()
var jump_names := jump_path.map(func(system: StarSystem) -> StringName: return system.name)
for system_name: String in self._system_nodes:
var node: GalaxyMapSystem = self._system_nodes[system_name]
node.selected = self.hyperdrive_system.jump_destination and self.hyperdrive_system.jump_destination.name == system_name
node.current = system_name in jump_names or system_name == current_system.name
node.selected = system_name == jump_names[-1] if jump_path else false

for hyperlane_name: String in self._hyperlane_nodes:
var node: GalaxyMapHyperlane = self._hyperlane_nodes[hyperlane_name]
node.selected = false

var presented_system: StarSystem
if self.hyperdrive_system.jump_destination:
presented_system = self.hyperdrive_system.jump_destination
if jump_path:
for i in range(0, jump_path.size()):
var last_name := jump_path[i - 1].name if i > 0 else self.hyperdrive_system.current_system().name

var forward_name := "%s > %s" % [last_name, jump_path[i].name]
if forward_name in self._hyperlane_nodes:
self._hyperlane_nodes[forward_name].selected = true

var backward_name := "%s > %s" % [jump_path[i].name, last_name]
if backward_name in self._hyperlane_nodes:
self._hyperlane_nodes[backward_name].selected = true

presented_system = jump_path[-1]
self.current_or_destination_heading.text = "Destination system"
else:
presented_system = self.hyperdrive_system.current_system()
presented_system = current_system
self.current_or_destination_heading.text = "Current system"

self.system_name_label.text = presented_system.name
Expand Down Expand Up @@ -153,30 +182,49 @@ func _input(event: InputEvent) -> void:
func _on_window_close_requested() -> void:
self.queue_free()

func _on_system_clicked(star_system: StarSystem, _system_node: GalaxyMapSystem) -> void:
func _on_system_clicked(star_system: StarSystem) -> void:
if not is_instance_valid(self.hyperdrive_system) or self.hyperdrive_system.jumping:
return

if star_system == self.hyperdrive_system.current_system():
self.hyperdrive_system.jump_destination = null
self.hyperdrive_system.clear_jump_path()
return

if star_system.name not in self.hyperdrive_system.current_system().connections:
return

self.hyperdrive_system.jump_destination = star_system
if Input.is_key_pressed(KEY_SHIFT):
self._update_multi_path(star_system)
else:
self._replace_single_path(star_system)

func _on_hyperlane_clicked(from_system: StarSystem, to_system: StarSystem, _hyperlane_node: GalaxyMapHyperlane) -> void:
func _on_hyperlane_clicked(from_system: StarSystem, to_system: StarSystem) -> void:
if not is_instance_valid(self.hyperdrive_system) or self.hyperdrive_system.jumping:
return

var current_system := self.hyperdrive_system.current_system()
var connection: StarSystem
if from_system == current_system:
connection = to_system
elif to_system == current_system:
connection = from_system
else:
var jump_path := self.hyperdrive_system.get_jump_path()
if from_system == current_system or from_system in jump_path:
self._on_system_clicked(to_system)
elif to_system == current_system or to_system in jump_path:
self._on_system_clicked(from_system)

func _update_multi_path(star_system: StarSystem) -> void:
var current_path := self.hyperdrive_system.get_jump_path()
if not current_path:
return self._replace_single_path(star_system)

var current_path_names := self.hyperdrive_system.get_jump_path().map(func(system: StarSystem) -> StringName: return system.name)
var index := current_path_names.find(star_system.name)
if index != -1:
# Reset path back to the clicked node
self.hyperdrive_system.set_jump_path(current_path.slice(0, index + 1))
return

# Add to end of path
var last_system := current_path[-1]
if star_system.name in last_system.connections:
self.hyperdrive_system.add_to_jump_path(star_system)

func _replace_single_path(star_system: StarSystem) -> void:
if star_system.name not in self.hyperdrive_system.current_system().connections:
return

self.hyperdrive_system.jump_destination = connection
self.hyperdrive_system.set_jump_path([star_system])
2 changes: 1 addition & 1 deletion galaxy/map/galaxy_map_3d.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ sky_mode = 1
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform3D(1, -6.97574e-16, -1.5246e-23, -1.5246e-23, -4.37114e-08, 1, -6.97574e-16, -1, -4.37114e-08, 2.08165e-12, 5, 2.08165e-12)
current = true
near = 1.0
near = 0.001
far = 50.0
script = ExtResource("3_h6pmd")

Expand Down
9 changes: 9 additions & 0 deletions galaxy/map/galaxy_map_hyperlane.gd
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ class_name GalaxyMapHyperlane
## This is expected to have a [CylinderMesh] attached.
@export var mesh: MeshInstance3D

## When [member selected] is true, this material overrides the [member mesh]'s material.
@export var selected_material: Material

## Whether this hyperlane is selected.
@export var selected: bool:
set(value):
selected = value
self.mesh.material_override = self.selected_material if value else null

## The shape defining the clickable region of this hyperlane.
##
## This is expected to have a [CylinderShape3D] attached.
Expand Down
4 changes: 3 additions & 1 deletion galaxy/map/galaxy_map_hyperlane.tscn
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[gd_scene load_steps=5 format=3 uid="uid://d3lphosly5y8b"]
[gd_scene load_steps=6 format=3 uid="uid://d3lphosly5y8b"]

[ext_resource type="Script" path="res://galaxy/map/galaxy_map_hyperlane.gd" id="1_qtr5l"]
[ext_resource type="Material" uid="uid://wjykkjty1dt5" path="res://galaxy/map/galaxy_map_current_mat.tres" id="2_xrjew"]

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_futeo"]
emission = Color(1, 1, 1, 1)
Expand All @@ -20,6 +21,7 @@ radius = 0.1
[node name="Hyperlane" type="StaticBody3D" node_paths=PackedStringArray("mesh", "collision_shape", "debugging_label")]
script = ExtResource("1_qtr5l")
mesh = NodePath("MeshInstance3D")
selected_material = ExtResource("2_xrjew")
collision_shape = NodePath("CollisionShape3D")
debugging_label = NodePath("DebuggingLabel")
node_radius = 0.1
Expand Down
4 changes: 2 additions & 2 deletions galaxy/map/galaxy_map_system.gd
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class_name GalaxyMapSystem
## When [member current] is true, this material overrides the [member mesh]'s material.
@export var current_node_material: Material

## Whether the system represented by this node is the player's current system.
## Whether the system represented by this node is the player's current system or part of the current hyperspace path.
@export var current: bool:
set(value):
current = value
Expand All @@ -21,7 +21,7 @@ class_name GalaxyMapSystem
## When [member selected] is true, this sprite is shown.
@export var selected_sprite: Sprite3D

## Whether this system has been selected by the player in the galaxy map.
## Whether this system is currently selected by the player in the galaxy map.
@export var selected: bool:
set(value):
selected = value
Expand Down
53 changes: 38 additions & 15 deletions mechanics/hyperspace/hyperdrive_system.gd
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,25 @@ var hyperdrive: Hyperdrive
## At the moment, changing this has no effect besides firing [signal jumping_changed].
var jumping: bool = false:
set(value):
assert(not value or self.jump_destination != null, "If jumping, a jump destination should already be set")
assert(not value or self._jump_path, "If jumping, a jump path should already be set")

if jumping == value:
return

jumping = value
self.jumping_changed.emit(self)

## The current jump destination, if one is selected.
var jump_destination: StarSystem = null:
set(value):
assert(value != self.current_system(), "Jump destination should not be the same as the current system")
assert(value == null or value.name in self.current_system().connections, "Jump destination should be connected to the current system")

if jump_destination == value:
return

jump_destination = value
self.jump_destination_changed.emit(self)

## The [Ship] this hyperdrive system is attached to.
@onready var ship := get_parent() as Ship

## The planned multi-step hyperspace path.
var _jump_path: Array[StarSystem] = []

## Fires when [member jumping] changes.
signal jumping_changed(hyperdrive_system: HyperdriveSystem)

## Fires when [member jump_destination] changes.
signal jump_destination_changed(hyperdrive_system: HyperdriveSystem)
## Fires when the [member jump_path] changes.
signal jump_path_changed(hyperdrive_system: HyperdriveSystem)

## The current system the ship is located in.
func current_system() -> StarSystem:
Expand All @@ -50,3 +41,35 @@ func current_system() -> StarSystem:
return null

return instance.star_system

## Returns the planned jump path.
func get_jump_path() -> Array[StarSystem]:
return self._jump_path.duplicate()

## Returns the immediately next jump destination.
func get_jump_destination() -> StarSystem:
return self._jump_path[0] if self._jump_path else null

## Sets the planned jump path.
func set_jump_path(path: Array[StarSystem]) -> void:
if path == self._jump_path:
return

self._jump_path = path.duplicate()
self.jump_path_changed.emit(self)

## Adds a system to the end of the jump path.
func add_to_jump_path(system: StarSystem) -> void:
self._jump_path.append(system)
self.jump_path_changed.emit(self)

## Clears the current jump path.
func clear_jump_path() -> void:
self._jump_path.clear()
self.jump_path_changed.emit(self)

## Updates the jump path after a successful jump.
func shift_jump_path() -> void:
assert(self._jump_path, "Jump path must not be empty")
self._jump_path.pop_front()
self.jump_path_changed.emit(self)
8 changes: 4 additions & 4 deletions mechanics/hyperspace/hyperspace_scene_switcher.gd
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ func start_jump() -> bool:
if not self._hyperdrive_system.hyperdrive.consume_for_jump():
return false

if not self._loaded_system_nodes.has(self._hyperdrive_system.jump_destination.name):
ResourceLoader.load_threaded_request(self._hyperdrive_system.jump_destination.scene_path)
if not self._loaded_system_nodes.has(self._hyperdrive_system.get_jump_destination().name):
ResourceLoader.load_threaded_request(self._hyperdrive_system.get_jump_destination().scene_path)

self._hyperdrive_system.jumping = true
return true

func load_jump_destination() -> void:
assert(self._hyperdrive_system.jumping, "Expected a jump to be in progress")

var destination := self._hyperdrive_system.jump_destination
var destination := self._hyperdrive_system.get_jump_destination()
assert(destination, "Expected to have a jump destination")

var player_ship := self._hyperdrive_system.ship
Expand All @@ -71,7 +71,7 @@ func load_jump_destination() -> void:

self.player.calendar.pass_approximate_days(HYPERSPACE_APPROXIMATE_TRAVEL_DAYS)

self._hyperdrive_system.jump_destination = null
self._hyperdrive_system.shift_jump_path()
self.jump_destination_loaded.emit(star_system_instance)

func finish_jump() -> void:
Expand Down
6 changes: 3 additions & 3 deletions screens/game/game.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ script = ExtResource("11_ag0i7")
max_volume = 10.0
commodities = {}

[sub_resource type="Resource" id="Resource_0rcb3"]
[sub_resource type="Resource" id="Resource_0g6jc"]
resource_local_to_scene = true
script = ExtResource("13_q2g24")
max_fuel = 6.0
Expand Down Expand Up @@ -183,7 +183,7 @@ hull = SubResource("Resource_ffax2")
shield = SubResource("Resource_75c8j")
battery = SubResource("Resource_xpwk4")
cargo_hold = SubResource("Resource_bsv1l")
hyperdrive = SubResource("Resource_0rcb3")
hyperdrive = SubResource("Resource_0g6jc")

[node name="CombatObject" parent="HyperspaceSceneSwitcher/Sol/PlayerCorvette" index="3" node_paths=PackedStringArray("targeted_sound")]
targeted_sound = NodePath("../Player/TargetedSound")
Expand Down Expand Up @@ -644,7 +644,7 @@ script = ExtResource("37_e11x7")

[connection signal="jump_destination_loaded" from="HyperspaceSceneSwitcher" to="HyperspaceSceneSwitcher/Sol/PlayerCorvette/Player" method="_on_jump_destination_loaded"]
[connection signal="jump_destination_loaded" from="HyperspaceSceneSwitcher" to="InGameGUI/MarginContainer/HBoxContainer/Sidebar/SystemName" method="_on_jump_destination_loaded"]
[connection signal="jump_destination_changed" from="HyperspaceSceneSwitcher/Sol/PlayerCorvette/HyperdriveSystem" to="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PanelContainer/VBoxContainer/JumpDestinationName" method="_on_jump_destination_changed"]
[connection signal="jump_path_changed" from="HyperspaceSceneSwitcher/Sol/PlayerCorvette/HyperdriveSystem" to="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PanelContainer/VBoxContainer/JumpDestinationName" method="_on_jump_path_changed"]
[connection signal="jumping_changed" from="HyperspaceSceneSwitcher/Sol/PlayerCorvette/HyperdriveSystem" to="MainCameraTransform/MainCamera/HyperspaceEffect" method="_on_jumping_changed"]
[connection signal="hull_changed" from="HyperspaceSceneSwitcher/Sol/PlayerCorvette/Player" to="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PlayerVitalsContainer/VBoxContainer/PlayerVitals" method="_on_player_hull_changed"]
[connection signal="hyperdrive_changed" from="HyperspaceSceneSwitcher/Sol/PlayerCorvette/Player" to="InGameGUI/MarginContainer/HBoxContainer/Sidebar/PanelContainer/VBoxContainer/FuelBar" method="_on_player_hyperdrive_changed"]
Expand Down
6 changes: 3 additions & 3 deletions screens/game/hud/jump_destination_name.gd
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ extends Label

@export var pick_sound: AudioStreamPlayer

func _on_jump_destination_changed(hyperdrive_system: HyperdriveSystem) -> void:
if hyperdrive_system.jump_destination == null:
func _on_jump_path_changed(hyperdrive_system: HyperdriveSystem) -> void:
if hyperdrive_system.get_jump_destination() == null:
self.text = ""
else:
self.text = hyperdrive_system.jump_destination.name
self.text = hyperdrive_system.get_jump_destination().name
self.pick_sound.play()
Loading

0 comments on commit 9a54d98

Please sign in to comment.