Implement production vertical slice foundation
This commit is contained in:
1 parent
9d4a89f355
commit
a18e82eb44
104 files changed
+10595
-268
No files matched your search
@@ -0,0 +1,33 @@
|
||||
class_name VehicleTestEnvironment
|
||||
extends Node3D
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var particles := GPUParticles3D.new()
|
||||
particles.name = "SuspendedParticles"
|
||||
particles.position = Vector3(0.0, -34.0, -42.0)
|
||||
particles.amount = 360
|
||||
particles.lifetime = 14.0
|
||||
particles.preprocess = 14.0
|
||||
particles.visibility_aabb = AABB(
|
||||
Vector3(-50.0, -35.0, -78.0),
|
||||
Vector3(100.0, 70.0, 156.0)
|
||||
)
|
||||
|
||||
var motion := ParticleProcessMaterial.new()
|
||||
motion.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX
|
||||
motion.emission_box_extents = Vector3(45.0, 28.0, 70.0)
|
||||
motion.direction = Vector3(0.1, 0.04, 0.0)
|
||||
motion.spread = 180.0
|
||||
motion.initial_velocity_min = 0.02
|
||||
motion.initial_velocity_max = 0.09
|
||||
motion.gravity = Vector3.ZERO
|
||||
motion.scale_min = 0.025
|
||||
motion.scale_max = 0.08
|
||||
particles.process_material = motion
|
||||
|
||||
var particle_mesh := SphereMesh.new()
|
||||
particle_mesh.radius = 0.035
|
||||
particle_mesh.height = 0.07
|
||||
particles.draw_pass_1 = particle_mesh
|
||||
add_child(particles)
|
||||
@@ -0,0 +1,132 @@
|
||||
[gd_scene load_steps=12 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://game/world/sites/vehicle_test_environment.gd" id="1_environment"]
|
||||
|
||||
[sub_resource type="Environment" id="EnvironmentUnderwater"]
|
||||
background_mode = 1
|
||||
background_color = Color(0.005, 0.045, 0.065, 1)
|
||||
ambient_light_source = 3
|
||||
ambient_light_color = Color(0.12, 0.32, 0.37, 1)
|
||||
ambient_light_energy = 0.42
|
||||
fog_enabled = true
|
||||
fog_light_color = Color(0.07, 0.25, 0.3, 1)
|
||||
fog_light_energy = 0.48
|
||||
fog_density = 0.014
|
||||
fog_height = -4.0
|
||||
fog_height_density = 0.025
|
||||
volumetric_fog_enabled = true
|
||||
volumetric_fog_density = 0.025
|
||||
volumetric_fog_length = 72.0
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="RockMaterial"]
|
||||
albedo_color = Color(0.075, 0.19, 0.19, 1)
|
||||
roughness = 0.92
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="RockMaterialLight"]
|
||||
albedo_color = Color(0.105, 0.25, 0.24, 1)
|
||||
roughness = 0.88
|
||||
|
||||
[sub_resource type="BoxMesh" id="SeafloorMesh"]
|
||||
size = Vector3(220, 8, 250)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="SeafloorShape"]
|
||||
size = Vector3(220, 8, 250)
|
||||
|
||||
[sub_resource type="BoxMesh" id="RockMeshA"]
|
||||
size = Vector3(12, 30, 14)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="RockShapeA"]
|
||||
size = Vector3(12, 30, 14)
|
||||
|
||||
[sub_resource type="BoxMesh" id="RockMeshB"]
|
||||
size = Vector3(18, 42, 16)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="RockShapeB"]
|
||||
size = Vector3(18, 42, 16)
|
||||
|
||||
[sub_resource type="SphereMesh" id="BeaconMesh"]
|
||||
radius = 0.55
|
||||
height = 1.1
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="BeaconMaterial"]
|
||||
shading_mode = 0
|
||||
albedo_color = Color(0.2, 0.78, 0.9, 1)
|
||||
emission_enabled = true
|
||||
emission = Color(0.2, 0.78, 0.9, 1)
|
||||
emission_energy_multiplier = 5.0
|
||||
|
||||
[node name="VehicleTestEnvironment" type="Node3D"]
|
||||
script = ExtResource("1_environment")
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource("EnvironmentUnderwater")
|
||||
|
||||
[node name="AmbientDirection" type="DirectionalLight3D" parent="."]
|
||||
rotation_degrees = Vector3(-52, -24, 0)
|
||||
light_color = Color(0.39, 0.65, 0.7, 1)
|
||||
light_energy = 0.38
|
||||
shadow_enabled = true
|
||||
|
||||
[node name="Seafloor" type="StaticBody3D" parent="."]
|
||||
position = Vector3(0, -84, -58)
|
||||
|
||||
[node name="Mesh" type="MeshInstance3D" parent="Seafloor"]
|
||||
mesh = SubResource("SeafloorMesh")
|
||||
material_override = SubResource("RockMaterial")
|
||||
|
||||
[node name="Collision" type="CollisionShape3D" parent="Seafloor"]
|
||||
shape = SubResource("SeafloorShape")
|
||||
|
||||
[node name="RockNearLeft" type="StaticBody3D" parent="."]
|
||||
position = Vector3(-10, -18, -18)
|
||||
rotation_degrees = Vector3(0, -14, 8)
|
||||
|
||||
[node name="Mesh" type="MeshInstance3D" parent="RockNearLeft"]
|
||||
mesh = SubResource("RockMeshA")
|
||||
material_override = SubResource("RockMaterialLight")
|
||||
|
||||
[node name="Collision" type="CollisionShape3D" parent="RockNearLeft"]
|
||||
shape = SubResource("RockShapeA")
|
||||
|
||||
[node name="RockNearRight" type="StaticBody3D" parent="."]
|
||||
position = Vector3(12, -22, -32)
|
||||
rotation_degrees = Vector3(0, 18, -5)
|
||||
|
||||
[node name="Mesh" type="MeshInstance3D" parent="RockNearRight"]
|
||||
mesh = SubResource("RockMeshB")
|
||||
material_override = SubResource("RockMaterial")
|
||||
|
||||
[node name="Collision" type="CollisionShape3D" parent="RockNearRight"]
|
||||
shape = SubResource("RockShapeB")
|
||||
|
||||
[node name="RockFarLeft" type="StaticBody3D" parent="."]
|
||||
position = Vector3(-18, -48, -68)
|
||||
rotation_degrees = Vector3(0, 9, 4)
|
||||
|
||||
[node name="Mesh" type="MeshInstance3D" parent="RockFarLeft"]
|
||||
mesh = SubResource("RockMeshA")
|
||||
material_override = SubResource("RockMaterialLight")
|
||||
|
||||
[node name="Collision" type="CollisionShape3D" parent="RockFarLeft"]
|
||||
shape = SubResource("RockShapeA")
|
||||
|
||||
[node name="RockFarRight" type="StaticBody3D" parent="."]
|
||||
position = Vector3(20, -58, -94)
|
||||
rotation_degrees = Vector3(0, -11, -7)
|
||||
|
||||
[node name="Mesh" type="MeshInstance3D" parent="RockFarRight"]
|
||||
mesh = SubResource("RockMeshB")
|
||||
material_override = SubResource("RockMaterial")
|
||||
|
||||
[node name="Collision" type="CollisionShape3D" parent="RockFarRight"]
|
||||
shape = SubResource("RockShapeB")
|
||||
|
||||
[node name="NavigationBeacon" type="MeshInstance3D" parent="."]
|
||||
position = Vector3(0, -15, -22)
|
||||
mesh = SubResource("BeaconMesh")
|
||||
material_override = SubResource("BeaconMaterial")
|
||||
|
||||
[node name="BeaconLight" type="OmniLight3D" parent="NavigationBeacon"]
|
||||
omni_range = 12.0
|
||||
light_color = Color(0.2, 0.78, 0.9, 1)
|
||||
light_energy = 4.0
|
||||
@@ -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
|
||||
@@ -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()
|
||||
)
|
||||
Reference in new issue
Block a user