Skip to content

Commit

Permalink
Merge pull request #61 from jspahrsummers/save-games
Browse files Browse the repository at this point in the history
Save games
  • Loading branch information
jspahrsummers authored Aug 4, 2024
2 parents 837e582 + 035b2d4 commit adf5bf8
Show file tree
Hide file tree
Showing 48 changed files with 975 additions and 319 deletions.
32 changes: 24 additions & 8 deletions actors/ai/ai_navigation.gd
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ class_name AINavigation
@export var auto_start: bool = true

## State machine for this AI.
##
## Note that these values are saved via [SaveGame], so be careful not to break backwards compatibility!
enum State {
IDLE,
ROTATING_TO_ACCELERATE,
ACCELERATING_TOWARD_DESTINATION,
ROTATING_TO_DECELERATE,
DECELERATING_TO_STOP,
IDLE = 0,
ROTATING_TO_ACCELERATE = 1,
ACCELERATING_TOWARD_DESTINATION = 2,
ROTATING_TO_DECELERATE = 3,
DECELERATING_TO_STOP = 4,
}

var navigating: bool:
Expand Down Expand Up @@ -88,7 +90,7 @@ func _accelerate_toward_destination() -> void:
var stopping_distance := self._calculate_stopping_distance(self._rigid_body.linear_velocity.length())

# Account for rotation time in stopping distance
var rotation_time := self._estimate_rotation_time( - self._rigid_body.linear_velocity.normalized())
var rotation_time := self._estimate_rotation_time(-self._rigid_body.linear_velocity.normalized())
var rotation_distance := self._rigid_body.linear_velocity.length() * rotation_time
stopping_distance += rotation_distance

Expand Down Expand Up @@ -121,18 +123,32 @@ func _decelerate_to_stop() -> void:
self.destination_reached.emit(self)

func _pointing_in_direction(direction: Vector3) -> bool:
var current_direction := - self._rigid_body.global_transform.basis.z
var current_direction := -self._rigid_body.global_transform.basis.z
return current_direction.angle_to(direction) <= self.direction_tolerance

func _calculate_stopping_distance(current_velocity: float) -> float:
var acceleration := self.rigid_body_thruster.thruster.thrust_force / self._rigid_body.mass
return (current_velocity * current_velocity) / (2 * acceleration)

func _estimate_rotation_time(target_direction: Vector3) -> float:
var current_direction := - self._rigid_body.global_transform.basis.z
var current_direction := -self._rigid_body.global_transform.basis.z
var angle_to_rotate := current_direction.angle_to(target_direction)
return angle_to_rotate / self.rigid_body_direction.spin_thruster.turning_rate

func set_destination(new_destination: Vector3) -> void:
self.destination = new_destination
self.navigating = true

## See [SaveGame].
func save_to_dict() -> Dictionary:
var result := {}
result["navigating"] = self.navigating
result["state"] = self._state
result["target_direction"] = SaveGame.serialize_vector3(self._target_direction)
return result

## See [SaveGame].
func load_from_dict(dict: Dictionary) -> void:
self.navigating = dict["navigating"]
self._state = dict["state"]
self._target_direction = SaveGame.deserialize_vector3(dict["target_direction"])
28 changes: 21 additions & 7 deletions actors/ai/archetypes/pirate.gd
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,17 @@ class_name Pirate
@export var patrol_target_tolerance: float = 1.0

## State machine for this AI. How it behaves will depend on which state it's in at any given time.
##
## Note that these values are saved via [SaveGame], so be careful not to break backwards compatibility!
enum State {
## Patrolling around, waiting to detect a target.
PATROL,
PATROL = 0,

## Engaging a target.
ENGAGE,
ENGAGE = 1,

## Retreating from the target.
RETREAT,
RETREAT = 2,
}

@onready var _ship := self.get_parent() as Ship
Expand All @@ -50,8 +52,8 @@ func _ready() -> void:
self._connect_notifications.call_deferred()

func _connect_notifications() -> void:
self._ship.combat_object.hull.changed.connect(_on_damage_received)
self._ship.combat_object.shield.changed.connect(_on_damage_received)
self._ship.hull.changed.connect(_on_damage_received)
self._ship.shield.changed.connect(_on_damage_received)

func _select_new_patrol_target() -> void:
self._patrol_target = MathUtils.random_unit_vector() * self.patrol_radius
Expand All @@ -74,12 +76,12 @@ func _desired_direction() -> Vector3:
var target := self._ship.targeting_system.target
if target:
var target_direction := (target.global_transform.origin - self._ship.global_transform.origin).normalized()
return target_direction if self._current_state != State.RETREAT else - target_direction
return target_direction if self._current_state != State.RETREAT else -target_direction
else:
return (self._patrol_target - self._ship.global_transform.origin).normalized()

func _pointing_in_direction(direction: Vector3) -> bool:
var current_direction := - self._ship.global_transform.basis.z
var current_direction := -self._ship.global_transform.basis.z
return current_direction.angle_to(direction) <= self.direction_tolerance

func _patrol_behavior(_delta: float) -> void:
Expand Down Expand Up @@ -165,3 +167,15 @@ func _on_damage_received() -> void:
if attacker != self._ship.targeting_system.target:
self._ship.targeting_system.target = attacker
self._current_state = State.ENGAGE

## See [SaveGame].
func save_to_dict() -> Dictionary:
var result := {}
result["current_state"] = self._current_state
result["patrol_target"] = SaveGame.serialize_vector3(self._patrol_target)
return result

## See [SaveGame].
func load_from_dict(dict: Dictionary) -> void:
self._current_state = dict["current_state"]
self._patrol_target = SaveGame.deserialize_vector3(dict["patrol_target"])
2 changes: 1 addition & 1 deletion actors/ai/archetypes/pirate.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

[ext_resource type="Script" path="res://actors/ai/archetypes/pirate.gd" id="1_ndoop"]

[node name="Pirate" type="Node3D"]
[node name="Pirate" type="Node3D" groups=["saveable"]]
script = ExtResource("1_ndoop")
57 changes: 42 additions & 15 deletions actors/player.gd
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ var landing_target: PlanetInstance = null:
if landing_target:
landing_target.targeted_by_player = true

## Used to save and restore the player object correctly across launches.
var save_node_path_override: NodePath

## Created to turn the [Ship] when using the relative control scheme.
var _rigid_body_turner: RigidBodyTurner

Expand All @@ -65,51 +68,63 @@ const MAX_LANDING_DISTANCE = 2.0
const MAX_LANDING_VELOCITY = 4.0

func _ready() -> void:
if not self.save_node_path_override:
self.save_node_path_override = self.get_path()
self.ship.save_node_path_override = self.ship.get_path()

self._rigid_body_turner = RigidBodyTurner.new()
self._rigid_body_turner.spin_thruster = self.ship.rigid_body_direction.spin_thruster
self._rigid_body_turner.battery = self.ship.rigid_body_direction.battery
self._rigid_body_turner.battery = self.ship.battery
self.ship.add_child.call_deferred(self._rigid_body_turner)
self.ship.radar_object.iff = RadarObject.IFF.SELF
self.ship.targeting_system.is_player = true

self.ship.combat_object.hull.changed.connect(_on_hull_changed)
self.ship.combat_object.hull.hull_destroyed.connect(_on_hull_destroyed)
self.ship.combat_object.shield.changed.connect(_on_shield_changed)
self.ship.power_management_unit.battery.changed.connect(_on_power_changed)
self.ship.hull.changed.connect(_on_hull_changed)
self.ship.hull.hull_destroyed.connect(_on_hull_destroyed)
self.ship.battery.changed.connect(_on_power_changed)
self.ship.targeting_system.target_changed.connect(_on_target_changed)
self.ship.hyperdrive_system.hyperdrive.changed.connect(_on_hyperdrive_changed)

InputEventBroadcaster.input_event.connect(_on_broadcasted_input_event)

# Initial notifications so the UI can update.
self._on_hull_changed()
self._on_shield_changed()
self._on_power_changed()
self._on_hyperdrive_changed()

if self.ship.shield:
self.ship.shield.changed.connect(_on_shield_changed)
self._on_shield_changed()

if self.ship.hyperdrive:
self._on_hyperdrive_changed()
self.ship.hyperdrive.changed.connect(_on_hyperdrive_changed)

func _on_hull_changed() -> void:
self.hull_changed.emit(self, self.ship.combat_object.hull)
self.hull_changed.emit(self, self.ship.hull)

func _on_shield_changed() -> void:
self.shield_changed.emit(self, self.ship.combat_object.shield)
self.shield_changed.emit(self, self.ship.shield)

func _on_power_changed() -> void:
self.power_changed.emit(self, self.ship.power_management_unit.battery)
self.power_changed.emit(self, self.ship.battery)

func _on_hull_destroyed(hull: Hull) -> void:
assert(hull == self.ship.combat_object.hull, "Received hull_destroyed signal from incorrect hull")
assert(hull == self.ship.hull, "Received hull_destroyed signal from incorrect hull")
self.ship_destroyed.emit(self)

func _on_target_changed(targeting_system: TargetingSystem) -> void:
self.target_changed.emit(self, targeting_system.target)

func _on_jump_destination_loaded(_new_system_instance: StarSystemInstance) -> void:
if not self.ship.hyperdrive_system.jumping:
# A bit of a hack to ignore this notification when reloading from a saved game, while allowing it to propagate to other nodes (e.g., UI).
return

self._reset_velocity()
self.ship.position = MathUtils.random_unit_vector() * HYPERSPACE_ARRIVAL_RADIUS
self.ship.targeting_system.target = null

func _on_hyperdrive_changed() -> void:
self.hyperdrive_changed.emit(self, self.ship.hyperdrive_system.hyperdrive)
self.hyperdrive_changed.emit(self, self.ship.hyperdrive)

func _next_system_connection() -> StarSystem:
var current_destination_name: Variant = null
Expand Down Expand Up @@ -252,7 +267,7 @@ func _absolute_input_direction() -> Vector3:
return Vector3(input_direction.x, 0, input_direction.y)

func _physics_process(_delta: float) -> void:
if self.ship.hyperdrive_system.jumping:
if not self.ship.hyperdrive_system or self.ship.hyperdrive_system.jumping:
return

if Input.is_action_pressed("jump"):
Expand Down Expand Up @@ -286,8 +301,20 @@ func _physics_process(_delta: float) -> void:
var desired_direction := self._absolute_input_direction()
self.ship.rigid_body_direction.direction = desired_direction

var current_direction := - self.ship.transform.basis.z
var current_direction := -self.ship.transform.basis.z
if desired_direction != Vector3.ZERO and desired_direction.angle_to(current_direction) <= ABSOLUTE_DIRECTION_TOLERANCE_RAD:
self.ship.rigid_body_thruster.throttle = desired_direction.length()
else:
self.ship.rigid_body_thruster.throttle = 0.0

## See [SaveGame].
func save_to_dict() -> Dictionary:
var result := {}
SaveGame.save_resource_property_into_dict(self, result, "bank_account")
SaveGame.save_resource_property_into_dict(self, result, "calendar")
return result

## See [SaveGame].
func load_from_dict(dict: Dictionary) -> void:
SaveGame.load_resource_property_from_dict(self, dict, "bank_account")
SaveGame.load_resource_property_from_dict(self, dict, "calendar")
7 changes: 6 additions & 1 deletion actors/player.tscn
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
[gd_scene load_steps=6 format=3 uid="uid://cxlg0yj8cjbrf"]
[gd_scene load_steps=8 format=3 uid="uid://cxlg0yj8cjbrf"]

[ext_resource type="Script" path="res://actors/player.gd" id="1_qxs3b"]
[ext_resource type="PackedScene" uid="uid://d1kbmfvjs6nrv" path="res://screens/landing/landing.tscn" id="2_2bp8c"]
[ext_resource type="AudioStream" uid="uid://b5h867m6j0kb2" path="res://screens/landing/audio/LandingGear.ogg" id="2_lqyst"]
[ext_resource type="Script" path="res://mechanics/economy/bank_account.gd" id="3_0316y"]
[ext_resource type="Script" path="res://mechanics/time/calendar.gd" id="4_x2dfd"]

[sub_resource type="Resource" id="Resource_bycam"]
script = ExtResource("3_0316y")
currencies = {}

[sub_resource type="Resource" id="Resource_8aheh"]
script = ExtResource("4_x2dfd")

[node name="Player" type="Node3D" node_paths=PackedStringArray("takeoff_sound")]
script = ExtResource("1_qxs3b")
landing_scene = ExtResource("2_2bp8c")
takeoff_sound = NodePath("TakeoffSound")
bank_account = SubResource("Resource_bycam")
calendar = SubResource("Resource_8aheh")

[node name="MinimapCameraRemoteTransform" type="RemoteTransform3D" parent="."]
update_rotation = false
Expand Down
11 changes: 5 additions & 6 deletions galaxy/star_system/scenes/alpha_centauri.tscn
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
[gd_scene load_steps=6 format=3 uid="uid://cyoasaafloxke"]

[ext_resource type="Script" path="res://galaxy/star_system/star_system_instance.gd" id="1_hu4s2"]
[ext_resource type="PackedScene" uid="uid://cji43wyk7116p" path="res://stars/base_star.tscn" id="1_hyeo5"]
[ext_resource type="Resource" uid="uid://cs1x8gyt6a7kw" path="res://galaxy/star_system/star_systems/alpha_centauri.tres" id="2_ex383"]
[ext_resource type="PackedScene" uid="uid://bqhgqgsbi7ofa" path="res://stars/main_sequence/star_class_k.tscn" id="4_daplr"]
[ext_resource type="PackedScene" uid="uid://d27pdcik2lwf1" path="res://stars/main_sequence/star_class_m.tscn" id="5_gjyye"]
[ext_resource type="PackedScene" uid="uid://fxemun7o6rix" path="res://galaxy/star_system/star_system_instance.tscn" id="star_system_instance"]

[node name="Alpha Centauri" type="Node3D"]
script = ExtResource("1_hu4s2")
[node name="Alpha Centauri" instance=ExtResource("star_system_instance")]
star_system = ExtResource("2_ex383")

[node name="Rigil Kentaurus" parent="." instance=ExtResource("1_hyeo5")]
[node name="Rigil Kentaurus" parent="." index="0" instance=ExtResource("1_hyeo5")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10.5019, 2.08165e-12, -4.44388)

[node name="Toliman" parent="." instance=ExtResource("4_daplr")]
[node name="Toliman" parent="." index="1" instance=ExtResource("4_daplr")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.83202, 2.08165e-12, 3.46602)

[node name="Proxima Centauri" parent="." instance=ExtResource("5_gjyye")]
[node name="Proxima Centauri" parent="." index="2" instance=ExtResource("5_gjyye")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 18.8751, 2.08165e-12, -15.3346)
11 changes: 5 additions & 6 deletions galaxy/star_system/scenes/barnard's_star.tscn
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
[gd_scene load_steps=6 format=3 uid="uid://cghdtnx2qen2u"]

[ext_resource type="Script" path="res://galaxy/star_system/star_system_instance.gd" id="1_pqej6"]
[ext_resource type="Resource" uid="uid://shiglva7yxl0" path="res://galaxy/star_system/star_systems/barnard's_star.tres" id="2_y4tl8"]
[ext_resource type="PackedScene" uid="uid://d27pdcik2lwf1" path="res://stars/main_sequence/star_class_m.tscn" id="3_cqasn"]
[ext_resource type="PackedScene" uid="uid://ccdkamqw03rk7" path="res://fx/asteroids/multi_asteroid_field.tscn" id="5_x1i1i"]
[ext_resource type="PackedScene" uid="uid://culoat6jnbwc8" path="res://actors/ai/pirate_frigate.tscn" id="9_xdjbl"]
[ext_resource type="PackedScene" uid="uid://fxemun7o6rix" path="res://galaxy/star_system/star_system_instance.tscn" id="star_system_instance"]

[node name="Barnard\'s Star" type="Node3D"]
script = ExtResource("1_pqej6")
[node name="Barnard\'s Star" instance=ExtResource("star_system_instance")]
star_system = ExtResource("2_y4tl8")

[node name="Star Class M" parent="." instance=ExtResource("3_cqasn")]
[node name="Star Class M" parent="." index="0" instance=ExtResource("3_cqasn")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.65429, 2.08165e-12, 11.1402)

[node name="PirateFrigate" parent="." instance=ExtResource("9_xdjbl")]
[node name="PirateFrigate" parent="." index="1" instance=ExtResource("9_xdjbl")]
transform = Transform3D(0.866897, -1.28496e-16, 0.498488, 3.48787e-16, 1, -3.48787e-16, -0.498488, 4.76228e-16, 0.866897, -8.39, 2.08165e-12, 1.15)

[node name="AsteroidField" parent="." instance=ExtResource("5_x1i1i")]
[node name="AsteroidField" parent="." index="2" instance=ExtResource("5_x1i1i")]
15 changes: 7 additions & 8 deletions galaxy/star_system/scenes/nova_lumina.tscn
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[gd_scene load_steps=12 format=3 uid="uid://di4weo7brixhh"]

[ext_resource type="Script" path="res://galaxy/star_system/star_system_instance.gd" id="1_fii8b"]
[ext_resource type="Resource" uid="uid://ku5qjeo4jlkt" path="res://galaxy/star_system/star_systems/nova_lumina.tres" id="2_etutf"]
[ext_resource type="PackedScene" uid="uid://d1sevq56wdchx" path="res://stars/main_sequence/star_class_b.tscn" id="3_kweak"]
[ext_resource type="PackedScene" uid="uid://b04hfgkcuq7k6" path="res://planet/planet_instance.tscn" id="3_qge20"]
Expand All @@ -11,34 +10,34 @@
[ext_resource type="Texture2D" uid="uid://ceccjdfupojph" path="res://planet/sprites/planet_30.png" id="8_7sr4w"]
[ext_resource type="Texture2D" uid="uid://evirpay5c0bq" path="res://planet/sprites/planet_48.png" id="9_w331x"]
[ext_resource type="Texture2D" uid="uid://b2qu75vy8ncsx" path="res://planet/sprites/planet_07.png" id="11_o76pq"]
[ext_resource type="PackedScene" uid="uid://fxemun7o6rix" path="res://galaxy/star_system/star_system_instance.tscn" id="star_system_instance"]

[node name="Nova Lumina" type="Node3D"]
script = ExtResource("1_fii8b")
[node name="Nova Lumina" instance=ExtResource("star_system_instance")]
star_system = ExtResource("2_etutf")

[node name="Star Class B" parent="." instance=ExtResource("3_kweak")]
[node name="Star Class B" parent="." index="0" instance=ExtResource("3_kweak")]

[node name="Auroris" parent="." instance=ExtResource("3_qge20")]
[node name="Auroris" parent="." index="1" instance=ExtResource("3_qge20")]
transform = Transform3D(2, 0, 0, 0, 1, 0, 0, 0, 2, -1.1093, 0, -11.1902)
planet = ExtResource("5_kad6o")

[node name="Sprite3D" parent="Auroris" index="1"]
texture = ExtResource("8_7sr4w")

[node name="Lumina Prime" parent="." instance=ExtResource("3_qge20")]
[node name="Lumina Prime" parent="." index="2" instance=ExtResource("3_qge20")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -16.7791, 0, -2.37476)
planet = ExtResource("4_mwi45")

[node name="Sprite3D" parent="Lumina Prime" index="1"]
texture = ExtResource("6_cyr6t")

[node name="Stellara" parent="." instance=ExtResource("3_qge20")]
[node name="Stellara" parent="." index="3" instance=ExtResource("3_qge20")]
transform = Transform3D(2, 0, 0, 0, 1, 0, 0, 0, 2, -12.3399, 0, 15.6569)

[node name="Sprite3D" parent="Stellara" index="1"]
texture = ExtResource("9_w331x")

[node name="Novus" parent="." instance=ExtResource("3_qge20")]
[node name="Novus" parent="." index="4" instance=ExtResource("3_qge20")]
transform = Transform3D(0.75, 0, 0, 0, 1, 0, 0, 0, 0.75, 13.69, 0, 19.5674)
planet = ExtResource("6_anm5q")

Expand Down
Loading

0 comments on commit adf5bf8

Please sign in to comment.