Implement production vertical slice foundation

This commit is contained in:
chindit committed 2026-10-02 15:27:48 +02:00
1 parent 9d4a89f355
commit a18e82eb44
104 files changed
+10595 -268

No files matched your search

+139
View File
@@ -0,0 +1,139 @@
class_name SubmarineActor
extends CharacterBody3D
signal collision_sampled(sample: VehicleCollisionSample)
const VehicleCommand = preload("res://game/application/vehicle/vehicle_command.gd")
const VehicleCollisionSample = preload(
"res://game/application/vehicle/vehicle_collision_sample.gd"
)
@export var cruise_speed_mps := 6.0
@export var high_thrust_speed_mps := 9.5
@export var acceleration_mps2 := 2.0
@export var braking_mps2 := 1.35
@export var vertical_speed_mps := 3.5
@export var vertical_acceleration_mps2 := 1.8
@export var lateral_grip_mps2 := 2.2
@export var maximum_yaw_speed_degrees := 45.0
@export var yaw_acceleration_degrees := 30.0
@export var yaw_braking_degrees := 24.0
@export var maximum_depth_m := 500.0
var _command: VehicleCommand = VehicleCommand.neutral(0)
var _yaw_velocity_rps := 0.0
var _collision_sequence := 0
var _last_longitudinal_effort := 0.0
var _last_steering_effort := 0.0
var _last_vertical_effort := 0.0
var _last_high_thrust_active := false
func apply_vehicle_command(command: VehicleCommand) -> void:
_command = command
func current_depth_m() -> float:
return maxf(-global_position.y, 0.0)
func current_yaw_velocity_rps() -> float:
return _yaw_velocity_rps
func actual_longitudinal_effort() -> float:
return _last_longitudinal_effort
func actual_steering_effort() -> float:
return _last_steering_effort
func actual_vertical_effort() -> float:
return _last_vertical_effort
func high_thrust_active() -> bool:
return _last_high_thrust_active
func _physics_process(delta: float) -> void:
_update_yaw(delta)
_update_velocity(delta)
var velocity_before_move := velocity
move_and_slide()
_keep_inside_vertical_bounds()
_publish_collisions(velocity_before_move)
func _update_yaw(delta: float) -> void:
var maximum_yaw_speed := deg_to_rad(maximum_yaw_speed_degrees)
var target_yaw_velocity := -_command.steering * maximum_yaw_speed
var yaw_change_degrees := (
yaw_acceleration_degrees
if not is_zero_approx(_command.steering)
else yaw_braking_degrees
)
_yaw_velocity_rps = move_toward(
_yaw_velocity_rps,
target_yaw_velocity,
deg_to_rad(yaw_change_degrees) * delta
)
rotation.y = wrapf(rotation.y + _yaw_velocity_rps * delta, -PI, PI)
_last_steering_effort = _command.steering
func _update_velocity(delta: float) -> void:
var local_velocity := global_basis.inverse() * velocity
var requested_speed := (
high_thrust_speed_mps if _command.high_thrust_active else cruise_speed_mps
)
var target_forward_speed := _command.longitudinal * requested_speed
var current_forward_speed := -local_velocity.z
var forward_change_rate := (
acceleration_mps2
if not is_zero_approx(target_forward_speed)
else braking_mps2
)
current_forward_speed = move_toward(
current_forward_speed,
target_forward_speed,
forward_change_rate * delta
)
local_velocity.z = -current_forward_speed
var target_vertical_speed := _command.vertical * vertical_speed_mps
local_velocity.y = move_toward(
local_velocity.y,
target_vertical_speed,
vertical_acceleration_mps2 * delta
)
local_velocity.x = move_toward(local_velocity.x, 0.0, lateral_grip_mps2 * delta)
velocity = global_basis * local_velocity
_last_longitudinal_effort = _command.longitudinal
_last_vertical_effort = _command.vertical
_last_high_thrust_active = _command.high_thrust_active
func _keep_inside_vertical_bounds() -> void:
if global_position.y > -2.0:
global_position.y = -2.0
velocity.y = minf(velocity.y, 0.0)
if global_position.y < -maximum_depth_m:
global_position.y = -maximum_depth_m
velocity.y = maxf(velocity.y, 0.0)
func _publish_collisions(previous_velocity: Vector3) -> void:
for collision_index in get_slide_collision_count():
var collision := get_slide_collision(collision_index)
var impact_speed := absf(previous_velocity.dot(collision.get_normal()))
if impact_speed <= 0.01:
continue
var sample_id := StringName(
"collision-%d-%d" % [_collision_sequence, collision_index]
)
collision_sampled.emit(
VehicleCollisionSample.new(sample_id, _collision_sequence, impact_speed)
)
_collision_sequence += 1
+75
View File
@@ -0,0 +1,75 @@
[gd_scene load_steps=8 format=3]
[ext_resource type="Script" path="res://game/world/submarine/submarine_actor.gd" id="1_actor"]
[sub_resource type="CapsuleShape3D" id="CapsuleCollision"]
radius = 0.72
height = 3.8
[sub_resource type="CapsuleMesh" id="CapsuleHull"]
radius = 0.72
height = 3.8
[sub_resource type="StandardMaterial3D" id="HullMaterial"]
albedo_color = Color(0.64, 0.48, 0.17, 1)
metallic = 0.72
roughness = 0.34
[sub_resource type="SphereMesh" id="CanopyMesh"]
radius = 0.58
height = 1.05
[sub_resource type="StandardMaterial3D" id="CanopyMaterial"]
transparency = 1
albedo_color = Color(0.04, 0.18, 0.25, 0.72)
metallic = 0.18
roughness = 0.16
[sub_resource type="BoxMesh" id="FinMesh"]
size = Vector3(1.8, 0.12, 1.2)
[node name="SubmarineActor" type="CharacterBody3D"]
script = ExtResource("1_actor")
[node name="CollisionShape" type="CollisionShape3D" parent="."]
rotation = Vector3(1.5708, 0, 0)
shape = SubResource("CapsuleCollision")
[node name="Hull" type="MeshInstance3D" parent="."]
rotation = Vector3(1.5708, 0, 0)
mesh = SubResource("CapsuleHull")
material_override = SubResource("HullMaterial")
[node name="Canopy" type="MeshInstance3D" parent="."]
position = Vector3(0, 0.36, -0.45)
scale = Vector3(0.85, 0.55, 1)
mesh = SubResource("CanopyMesh")
material_override = SubResource("CanopyMaterial")
[node name="LeftFin" type="MeshInstance3D" parent="."]
position = Vector3(-0.92, 0, 0.85)
mesh = SubResource("FinMesh")
material_override = SubResource("HullMaterial")
[node name="RightFin" type="MeshInstance3D" parent="."]
position = Vector3(0.92, 0, 0.85)
mesh = SubResource("FinMesh")
material_override = SubResource("HullMaterial")
[node name="LeftProjector" type="SpotLight3D" parent="."]
position = Vector3(-0.42, 0.05, -2.02)
rotation_degrees = Vector3(-3, 6, 0)
light_color = Color(0.72, 0.91, 1, 1)
light_energy = 22.0
shadow_enabled = true
spot_range = 58.0
spot_angle = 24.0
[node name="RightProjector" type="SpotLight3D" parent="."]
position = Vector3(0.42, 0.05, -2.02)
rotation_degrees = Vector3(-3, -6, 0)
light_color = Color(0.72, 0.91, 1, 1)
light_energy = 22.0
shadow_enabled = true
spot_range = 58.0
spot_angle = 24.0
@@ -0,0 +1,14 @@
class_name SubmarineMotionAdapter
extends "res://game/application/interfaces/vehicle_motion_port.gd"
const SubmarineActor = preload("res://game/world/submarine/submarine_actor.gd")
var _actor: SubmarineActor
func _init(actor: SubmarineActor) -> void:
_actor = actor
func apply_command(command: VehicleCommand) -> void:
_actor.apply_vehicle_command(command)
@@ -0,0 +1,27 @@
class_name SubmarineTelemetryAdapter
extends RefCounted
const VehicleTelemetry = preload("res://game/application/dive/vehicle_telemetry.gd")
const SubmarineActor = preload("res://game/world/submarine/submarine_actor.gd")
var _actor: SubmarineActor
func _init(actor: SubmarineActor) -> void:
_actor = actor
func sample(session_id: StringName, sequence: int) -> VehicleTelemetry:
return VehicleTelemetry.new(
session_id,
sequence,
_actor.global_position,
_actor.global_transform.basis.get_rotation_quaternion(),
_actor.velocity,
Vector3(0.0, _actor.current_yaw_velocity_rps(), 0.0),
_actor.current_depth_m(),
_actor.actual_longitudinal_effort(),
_actor.actual_steering_effort(),
_actor.actual_vertical_effort(),
_actor.high_thrust_active()
)