The AI made this

This commit is contained in:
Chris Bell 2024-12-19 20:18:58 -06:00
parent dc635482c8
commit 2b5935feae

View File

@ -1,6 +1,5 @@
class_name Ship
extends RigidBody3D extends RigidBody3D
class_name Ship
@export var player_detection_area: Area3D @export var player_detection_area: Area3D
@export var helm_location_marker: Marker3D @export var helm_location_marker: Marker3D
@ -26,62 +25,89 @@ var old_global_position_cache: Vector3
@export var move_speed: float = 1.0 @export var move_speed: float = 1.0
@export var acceleration: float = 0.1 @export var acceleration: float = 0.1
# Network Synchronization Variables
var last_sync_time: float = 0.0
var sync_interval: float = 0.1 # Sync every 0.1 seconds
var predicted_position: Vector3
var predicted_rotation: Quaternion
func _ready(): func _ready():
network_uuid = NetworkManager.register_node(self) network_uuid = NetworkManager.register_node(self)
NetworkManager.property_update_received.connect(_on_property_update) NetworkManager.property_update_received.connect(_on_property_update)
#connect signals #connect signals
player_detection_area.body_entered.connect(_on_area_3d_body_entered) player_detection_area.body_entered.connect(_on_area_3d_body_entered)
player_detection_area.body_exited.connect(_on_area_3d_body_exited) player_detection_area.body_exited.connect(_on_area_3d_body_exited)
_add_ship_helm(ship_helm_scene) #TEMPORARY TEST _add_ship_helm(ship_helm_scene) #TEMPORARY TEST
ship_id = randi_range(1000, 9999) #assign a random id to the ship as a unique identifier ship_id = randi_range(1000, 9999) #assign a random id to the ship as a unique identifier
GameConsole.log_debug("Ship ID: " + str(ship_id)) GameConsole.log_debug("Ship ID: " + str(ship_id))
# Initialize predicted values
predicted_position = global_position
predicted_rotation = Quaternion.from_euler(global_rotation)
func _process(delta: float) -> void: func _process(delta: float) -> void:
delta_time = delta delta_time = delta
func _physics_process(_delta) -> void: func _physics_process(_delta) -> void:
if piloting_player != null and !piloting_player.is_network_authority: return # Predict movement only for non-authority clients
if ship_is_piloted: if not piloting_player or piloting_player.is_network_authority:
var turn_speed = base_turn_speed / max(mass, 1) _predict_movement(_delta)
var lift_speed = base_lift_speed / max(mass, 1) else:
# Apply predicted values until server correction arrives
global_position = predicted_position
global_rotation = predicted_rotation.get_euler()
if Input.is_action_pressed("move_left"): # Apply actual input if it's the authority client
angular_velocity.y += turn_speed if piloting_player != null and piloting_player.is_network_authority:
elif Input.is_action_pressed("move_right"): _apply_local_input(_delta)
angular_velocity.y -= turn_speed
else:
global_rotation.z = lerpf(global_rotation.z, 0, 0.8)
if Input.is_action_pressed("jump"):
linear_velocity.y += lift_speed
elif Input.is_action_pressed("crouch"):
linear_velocity.y -= lift_speed
var target_velocity = Vector3.ZERO
if Input.is_action_pressed("move_forwards"):
target_velocity = -transform.basis.z * top_speed
elif Input.is_action_pressed("move_backwards"):
target_velocity = transform.basis.z * top_speed
var current_acceleration = (target_velocity - linear_velocity) * acceleration
apply_central_force(current_acceleration * mass)
if linear_velocity.length() > top_speed:
linear_velocity = linear_velocity.normalized() * top_speed
angular_velocity.y = clamp(angular_velocity.y, -max_turn_speed, max_turn_speed)
# Self level slowly if host # Self level slowly if host
global_rotation.x = lerpf(global_rotation.x, 0, 0.1) global_rotation.x = lerpf(global_rotation.x, 0, 0.1)
global_rotation.z = lerpf(global_rotation.z, 0, 0.1) global_rotation.z = lerpf(global_rotation.z, 0, 0.1)
_send_ship_sync()
_send_ship_sync()
func _predict_movement(_delta):
# Simple linear prediction
var predicted_velocity = linear_velocity
predicted_position += predicted_velocity * _delta
# Basic rotation prediction (can be improved)
var predicted_angular_velocity = angular_velocity
var predicted_rotation_delta = Quaternion()
predicted_rotation_delta.set_axis_angle(predicted_angular_velocity, _delta)
predicted_rotation = predicted_rotation * predicted_rotation_delta
func _apply_local_input(_delta):
var turn_speed = base_turn_speed / max(mass, 1)
var lift_speed = base_lift_speed / max(mass, 1)
if Input.is_action_pressed("move_left"):
angular_velocity.y += turn_speed
elif Input.is_action_pressed("move_right"):
angular_velocity.y -= turn_speed
else:
global_rotation.z = lerpf(global_rotation.z, 0, 0.8)
if Input.is_action_pressed("jump"):
linear_velocity.y += lift_speed
elif Input.is_action_pressed("crouch"):
linear_velocity.y -= lift_speed
var target_velocity = Vector3.ZERO
if Input.is_action_pressed("move_forwards"):
target_velocity = -transform.basis.z * top_speed
elif Input.is_action_pressed("move_backwards"):
target_velocity = transform.basis.z * top_speed
var current_acceleration = (target_velocity - linear_velocity) * acceleration
apply_central_force(current_acceleration * mass)
if linear_velocity.length() > top_speed:
linear_velocity = linear_velocity.normalized() * top_speed
angular_velocity.y = clamp(angular_velocity.y, -max_turn_speed, max_turn_speed)
func _on_area_3d_body_entered(body: Node3D) -> void: func _on_area_3d_body_entered(body: Node3D) -> void:
if body is Player and body.get_parent() != self: if body is Player and body.get_parent() != self:
@ -90,7 +116,6 @@ func _on_area_3d_body_entered(body: Node3D) -> void:
body.call_deferred("reparent", self, true) #reparents player onto self (RigidBody3D) body.call_deferred("reparent", self, true) #reparents player onto self (RigidBody3D)
print("ENTERED") print("ENTERED")
func _on_area_3d_body_exited(body: Node3D) -> void: func _on_area_3d_body_exited(body: Node3D) -> void:
if body is Player and body.get_parent() != get_node("/root/DevLevel/"): if body is Player and body.get_parent() != get_node("/root/DevLevel/"):
body.ship_exited() body.ship_exited()
@ -99,48 +124,52 @@ func _on_area_3d_body_exited(body: Node3D) -> void:
body.call_deferred("reparent", get_node("/root/DevLevel/"), true) #reparents player back onto world node body.call_deferred("reparent", get_node("/root/DevLevel/"), true) #reparents player back onto world node
print("EXITED") print("EXITED")
func _add_ship_helm(_ship_helm_scene: PackedScene): func _add_ship_helm(_ship_helm_scene: PackedScene):
var ship_helm_instance = _ship_helm_scene.instantiate() var ship_helm_instance = _ship_helm_scene.instantiate()
helm_location_marker.add_child(ship_helm_instance) helm_location_marker.add_child(ship_helm_instance)
ship_helm_instance = helm_location_marker.get_node("ShipHelm") ship_helm_instance = helm_location_marker.get_node("ShipHelm")
func _on_property_update(uuid: String, property_name: String, value: Variant): func _on_property_update(uuid: String, property_name: String, value: Variant):
if NetworkManager.node_map.has(uuid): if NetworkManager.node_map.has(uuid):
var node = NetworkManager.node_map[uuid] var node = NetworkManager.node_map[uuid]
if property_name == "global_position": if property_name == "global_position":
_handle_ship_sync_position(value) _handle_ship_sync_position(value)
elif property_name == "global_rotation": elif property_name == "global_rotation":
_handle_ship_sync_rotation(value) _handle_ship_sync_rotation(value)
else: else:
node.set(property_name, value) node.set(property_name, value)
else: else:
printerr("Received property update but node_id is wrong? Expected " + str(uuid) + " but got " + str(uuid)) printerr("Received property update but node_id is wrong? Expected " + str(uuid) + " but got " + str(uuid))
func _sync_piloting_state(): func _sync_piloting_state():
NetworkManager.sync_property(network_uuid, "ship_is_piloted", ship_is_piloted) NetworkManager.sync_property(network_uuid, "ship_is_piloted", ship_is_piloted)
NetworkManager.sync_property(network_uuid, "piloting_player", piloting_player) NetworkManager.sync_property(network_uuid, "piloting_player", piloting_player)
func _send_ship_sync(): func _send_ship_sync():
if piloting_player != null && !piloting_player.is_network_authority: if Time.get_ticks_msec() - last_sync_time > sync_interval * 1000:
var sync_buffer: float = 2 last_sync_time = Time.get_ticks_msec()
if old_global_position_cache.distance_squared_to(global_position) > sync_buffer: NetworkManager.sync_property(network_uuid, "global_position", global_position)
NetworkManager.sync_property(network_uuid, "global_position", global_position) NetworkManager.sync_property(network_uuid, "global_rotation", global_rotation)
old_global_position_cache = global_position NetworkManager.sync_property(network_uuid, "linear_velocity", linear_velocity)
NetworkManager.sync_property(network_uuid, "angular_velocity", angular_velocity)
if old_global_rotation_cache.distance_squared_to(global_rotation) > sync_buffer:
NetworkManager.sync_property(network_uuid, "global_rotation", global_rotation)
old_global_rotation_cache = global_rotation
func _handle_ship_sync_position(pos: Vector3):
global_position = lerp(global_position, pos, 0.1 * delta_time)
func _handle_ship_sync_position(pos: Vector3):
if piloting_player and not piloting_player.is_network_authority:
# Correct prediction with server data
predicted_position = pos
linear_velocity = (pos - global_position) / delta_time
func _handle_ship_sync_rotation(rot: Vector3): func _handle_ship_sync_rotation(rot: Vector3):
global_rotation = lerp(global_rotation, rot, 0.1 * delta_time) if piloting_player and not piloting_player.is_network_authority:
# Correct prediction with server data
predicted_rotation = Quaternion.from_euler(Vector3(rot.x, rot.y, rot.z))
# Calculate angular velocity based on rotation change
var received_rotation = Quaternion.from_euler(Vector3(rot.x, rot.y, rot.z))
var delta_rot = received_rotation * global_rotation.inverse()
if delta_rot.length() > 0.001:
angular_velocity = delta_rot.get_euler() / delta_time
# Apply server rotation directly
global_rotation = Quaternion.from_euler(rot).get_euler()