Files
Ransom-s-wake/src/poc_a.gd
T

395 lines
12 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Node3D
const MISSION_POINTS := [
{
"title": "Rejoignez la balise de navigation",
"position": Vector3(0.0, -22.0, -58.0),
"color": Color("5ddcff"),
"radius": 8.0,
},
{
"title": "Descendez au-delà de 60 m et inspectez la balise",
"position": Vector3(38.0, -66.0, -128.0),
"color": Color("ffbd59"),
"radius": 4.0,
},
{
"title": "Revenez dans la zone de récupération",
"position": Vector3(0.0, -12.0, 12.0),
"color": Color("7af0a5"),
"radius": 8.0,
},
]
var _submarine: SubmarineController
var _hud: PocHud
var _alarm_player: AlarmPlayer
var _mission_index := 0
var _mission_markers: Array[Node3D] = []
var _mission_guide_groups: Array[Node3D] = []
var _terminal := false
var _elapsed_time := 0.0
func _ready() -> void:
_ensure_input_actions()
_build_environment()
_build_course()
_hud = PocHud.new()
add_child(_hud)
_alarm_player = AlarmPlayer.new()
add_child(_alarm_player)
_submarine = SubmarineController.new()
_submarine.name = "Submarine"
_submarine.position = Vector3(0.0, -12.0, 12.0)
_submarine.mission_origin = _submarine.position
_submarine.telemetry_updated.connect(_on_telemetry_updated)
_submarine.loss_triggered.connect(_on_loss_triggered)
_submarine.abandon_progress_changed.connect(_hud.set_ejection_progress)
add_child(_submarine)
_update_mission_marker_visibility()
_hud.set_objective(MISSION_POINTS[0]["title"])
func _process(delta: float) -> void:
if _terminal:
return
_elapsed_time += delta
var target: Vector3 = MISSION_POINTS[_mission_index]["position"]
var distance := _submarine.global_position.distance_to(target)
_hud.set_objective(MISSION_POINTS[_mission_index]["title"], distance)
if distance <= float(MISSION_POINTS[_mission_index]["radius"]):
_mission_index += 1
if _mission_index >= MISSION_POINTS.size():
_complete_course()
else:
_update_mission_marker_visibility()
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("debug_critical") and not _terminal:
_submarine.force_critical_state()
if _terminal and event.is_action_pressed("restart_poc"):
get_tree().reload_current_scene()
func _on_telemetry_updated(snapshot: Dictionary) -> void:
if _hud == null:
return
_hud.update_telemetry(snapshot)
_alarm_player.update_alerts(
get_process_delta_time(),
[
int(snapshot["oxygen_alert"]),
int(snapshot["battery_alert"]),
int(snapshot["hull_alert"]),
int(snapshot["depth_alert"]),
]
)
func _on_loss_triggered(reason: StringName) -> void:
_terminal = true
_alarm_player.reset()
var message: String = {
&"hull_failure": "La coque a cédé sous la pression ou après un impact.",
&"oxygen_depleted": "L’oxygène est épuisé. La capsule a été récupérée.",
&"manual_ejection": "Vous avez abandonné volontairement le véhicule.",
}.get(reason, "Le véhicule a été perdu.")
_hud.show_terminal("SOUS-MARIN PERDU", message)
func _complete_course() -> void:
_terminal = true
_submarine.controls_enabled = false
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
_alarm_player.reset()
_hud.show_terminal(
"PARCOURS TERMINÉ",
"Temps : %02d:%02d\nOxygène, propulsion, pression et retour ont été exercés."
% [int(_elapsed_time) / 60, int(_elapsed_time) % 60]
)
func _update_mission_marker_visibility() -> void:
for marker_index in _mission_markers.size():
_mission_markers[marker_index].visible = marker_index == _mission_index
for guide_index in _mission_guide_groups.size():
_mission_guide_groups[guide_index].visible = guide_index == _mission_index
func _build_environment() -> void:
var world_environment := WorldEnvironment.new()
var environment := Environment.new()
environment.background_mode = Environment.BG_COLOR
environment.background_color = Color("031823")
environment.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
environment.ambient_light_color = Color("2b6575")
environment.ambient_light_energy = 0.46
environment.fog_enabled = true
environment.fog_light_color = Color("174553")
environment.fog_light_energy = 0.52
environment.fog_density = 0.013
environment.fog_height = -5.0
environment.fog_height_density = 0.03
world_environment.environment = environment
add_child(world_environment)
var sun := DirectionalLight3D.new()
sun.rotation_degrees = Vector3(-55.0, -28.0, 0.0)
sun.light_color = Color("82bdc9")
sun.light_energy = 0.35
sun.shadow_enabled = true
add_child(sun)
var surface := MeshInstance3D.new()
var surface_mesh := PlaneMesh.new()
surface_mesh.size = Vector2(320.0, 420.0)
surface.mesh = surface_mesh
surface.position = Vector3(0.0, 0.0, -80.0)
var surface_material := StandardMaterial3D.new()
surface_material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
surface_material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
surface_material.cull_mode = BaseMaterial3D.CULL_DISABLED
surface_material.albedo_color = Color(0.13, 0.55, 0.65, 0.13)
surface.material_override = surface_material
add_child(surface)
_add_water_particles()
func _build_course() -> void:
_add_static_box(
"Seafloor",
Vector3(0.0, -96.0, -80.0),
Vector3(300.0, 10.0, 360.0),
Color("183a3c")
)
_add_static_box(
"LeftWall",
Vector3(-75.0, -50.0, -90.0),
Vector3(22.0, 95.0, 260.0),
Color("24494b")
)
# Nearby formations make speed, distance and heading readable from the
# cockpit before the player reaches the first mission beacon.
var navigation_rock_specs := [
[Vector3(-10.0, -24.0, -12.0), Vector3(10.0, 24.0, 10.0), -14.0],
[Vector3(12.0, -30.0, -28.0), Vector3(11.0, 34.0, 12.0), 18.0],
[Vector3(-12.0, -38.0, -42.0), Vector3(9.0, 46.0, 10.0), 8.0],
[Vector3(11.0, -44.0, -50.0), Vector3(8.0, 52.0, 10.0), -10.0],
[Vector3(7.0, -55.0, -73.0), Vector3(10.0, 38.0, 12.0), -16.0],
[Vector3(25.0, -69.0, -96.0), Vector3(12.0, 45.0, 14.0), 13.0],
[Vector3(45.0, -72.0, -112.0), Vector3(13.0, 50.0, 15.0), -9.0],
]
for rock_index in navigation_rock_specs.size():
var spec: Array = navigation_rock_specs[rock_index]
var navigation_rock := _add_static_box(
"NavigationRock%02d" % rock_index,
spec[0],
spec[1],
Color("315553") if rock_index % 2 == 0 else Color("294947")
)
navigation_rock.rotation_degrees.y = spec[2]
_add_static_box(
"RightWall",
Vector3(75.0, -50.0, -90.0),
Vector3(22.0, 95.0, 260.0),
Color("24494b")
)
var rock_specs := [
[Vector3(-25.0, -70.0, -78.0), Vector3(24.0, 44.0, 28.0), -18.0],
[Vector3(28.0, -76.0, -92.0), Vector3(18.0, 34.0, 20.0), 16.0],
[Vector3(-12.0, -83.0, -145.0), Vector3(42.0, 22.0, 30.0), 8.0],
[Vector3(54.0, -63.0, -150.0), Vector3(20.0, 58.0, 24.0), -12.0],
]
for rock_index in rock_specs.size():
var spec: Array = rock_specs[rock_index]
var rock := _add_static_box(
"Rock%02d" % rock_index,
spec[0],
spec[1],
Color("2d5452")
)
rock.rotation_degrees.y = spec[2]
for mission_data in MISSION_POINTS:
_mission_markers.append(
_add_beacon(mission_data["position"], mission_data["color"])
)
# Intermediate lights reveal the direction of the next leg without drawing
# a HUD arrow. Each chain only appears when its objective becomes active.
_mission_guide_groups.append(_add_guide_chain([], Color("5ddcff")))
_mission_guide_groups.append(
_add_guide_chain(
[
Vector3(8.0, -28.0, -75.0),
Vector3(18.0, -38.0, -94.0),
Vector3(29.0, -51.0, -112.0),
],
Color("ffbd59")
)
)
_mission_guide_groups.append(
_add_guide_chain(
[
Vector3(30.0, -55.0, -100.0),
Vector3(23.0, -44.0, -72.0),
Vector3(15.0, -34.0, -44.0),
Vector3(8.0, -23.0, -16.0),
],
Color("7af0a5")
)
)
func _add_water_particles() -> void:
var particles := GPUParticles3D.new()
particles.name = "SuspendedWaterParticles"
particles.position = Vector3(0.0, -45.0, -65.0)
particles.amount = 520
particles.lifetime = 14.0
particles.preprocess = 14.0
particles.fixed_fps = 30
particles.visibility_aabb = AABB(
Vector3(-85.0, -55.0, -125.0),
Vector3(170.0, 110.0, 250.0)
)
var particle_motion := ParticleProcessMaterial.new()
particle_motion.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX
particle_motion.emission_box_extents = Vector3(78.0, 48.0, 118.0)
particle_motion.direction = Vector3(0.25, 0.12, 0.08)
particle_motion.spread = 35.0
particle_motion.initial_velocity_min = 0.025
particle_motion.initial_velocity_max = 0.11
particle_motion.gravity = Vector3.ZERO
particle_motion.scale_min = 0.035
particle_motion.scale_max = 0.11
particles.process_material = particle_motion
var mote_mesh := QuadMesh.new()
mote_mesh.size = Vector2(0.075, 0.075)
var mote_material := StandardMaterial3D.new()
mote_material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
mote_material.billboard_mode = BaseMaterial3D.BILLBOARD_ENABLED
mote_material.albedo_color = Color(0.62, 0.88, 0.92, 0.42)
mote_material.roughness = 0.15
mote_mesh.material = mote_material
particles.draw_pass_1 = mote_mesh
add_child(particles)
func _add_static_box(node_name: String, box_position: Vector3, box_size: Vector3, color: Color) -> StaticBody3D:
var body := StaticBody3D.new()
body.name = node_name
body.position = box_position
add_child(body)
var mesh_instance := MeshInstance3D.new()
var mesh := BoxMesh.new()
mesh.size = box_size
mesh_instance.mesh = mesh
var material := StandardMaterial3D.new()
material.albedo_color = color
material.roughness = 0.9
mesh_instance.material_override = material
body.add_child(mesh_instance)
var collision_shape := CollisionShape3D.new()
var shape := BoxShape3D.new()
shape.size = box_size
collision_shape.shape = shape
body.add_child(collision_shape)
return body
func _add_beacon(beacon_position: Vector3, color: Color) -> Node3D:
var marker := Node3D.new()
marker.position = beacon_position
add_child(marker)
var sphere_instance := MeshInstance3D.new()
var sphere := SphereMesh.new()
sphere.radius = 2.2
sphere.height = 4.4
sphere_instance.mesh = sphere
var material := StandardMaterial3D.new()
material.albedo_color = color
material.emission_enabled = true
material.emission = color
material.emission_energy_multiplier = 4.0
sphere_instance.material_override = material
marker.add_child(sphere_instance)
var light := OmniLight3D.new()
light.omni_range = 18.0
light.light_energy = 5.0
light.light_color = color
marker.add_child(light)
return marker
func _add_guide_chain(guide_positions: Array, color: Color) -> Node3D:
var group := Node3D.new()
group.name = "MissionGuideChain"
add_child(group)
for guide_position in guide_positions:
var guide := Node3D.new()
guide.position = guide_position
group.add_child(guide)
var guide_mesh_instance := MeshInstance3D.new()
var guide_mesh := SphereMesh.new()
guide_mesh.radius = 0.38
guide_mesh.height = 0.76
guide_mesh_instance.mesh = guide_mesh
var guide_material := StandardMaterial3D.new()
guide_material.albedo_color = color
guide_material.emission_enabled = true
guide_material.emission = color
guide_material.emission_energy_multiplier = 1.5
guide_mesh_instance.material_override = guide_material
guide.add_child(guide_mesh_instance)
var guide_light := OmniLight3D.new()
guide_light.omni_range = 7.0
guide_light.light_energy = 1.8
guide_light.light_color = color
guide.add_child(guide_light)
return group
func _ensure_input_actions() -> void:
_register_key_action("move_forward", KEY_W)
_register_key_action("move_backward", KEY_S)
_register_key_action("move_left", KEY_A)
_register_key_action("move_right", KEY_D)
_register_key_action("ascend", KEY_SPACE)
_register_key_action("descend", KEY_CTRL)
_register_key_action("boost", KEY_SHIFT)
_register_key_action("abandon_vehicle", KEY_X)
_register_key_action("debug_critical", KEY_F9)
_register_key_action("restart_poc", KEY_ENTER)
_register_key_action("toggle_mouse_capture", KEY_ESCAPE)
func _register_key_action(action_name: StringName, physical_keycode: Key) -> void:
if not InputMap.has_action(action_name):
InputMap.add_action(action_name)
if InputMap.action_get_events(action_name).is_empty():
var key_event := InputEventKey.new()
key_event.physical_keycode = physical_keycode
InputMap.action_add_event(action_name, key_event)