Refine movement, water recovery, and UI baseline
This commit is contained in:
parent
d2fe367891
commit
e2067e3bf4
23 changed files with 905 additions and 146 deletions
46
world/player_water_trigger.gd
Normal file
46
world/player_water_trigger.gd
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
class_name PlayerWaterTrigger
|
||||
extends Area3D
|
||||
|
||||
signal recovery_requested(player: Player, surface_height: float)
|
||||
|
||||
@export var surface_height: float = 0.2
|
||||
@export_range(0.0, 2.0, 0.05) var entry_depth_threshold: float = 0.35
|
||||
|
||||
var _tracked_players: Array[Player] = []
|
||||
var _triggered_players: Dictionary[StringName, bool] = {}
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
body_entered.connect(_on_body_entered)
|
||||
body_exited.connect(_on_body_exited)
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
for player: Player in _tracked_players.duplicate():
|
||||
if not is_instance_valid(player):
|
||||
_tracked_players.erase(player)
|
||||
continue
|
||||
var player_key: StringName = StringName(str(player.get_instance_id()))
|
||||
if _triggered_players.has(player_key):
|
||||
continue
|
||||
if (
|
||||
player.get_body_center_position().y
|
||||
<= surface_height - entry_depth_threshold
|
||||
):
|
||||
_triggered_players[player_key] = true
|
||||
recovery_requested.emit(player, surface_height)
|
||||
|
||||
|
||||
func _on_body_entered(body: Node3D) -> void:
|
||||
var player: Player = body as Player
|
||||
if player == null or player in _tracked_players:
|
||||
return
|
||||
_tracked_players.append(player)
|
||||
|
||||
|
||||
func _on_body_exited(body: Node3D) -> void:
|
||||
var player: Player = body as Player
|
||||
if player == null:
|
||||
return
|
||||
_tracked_players.erase(player)
|
||||
_triggered_players.erase(StringName(str(player.get_instance_id())))
|
||||
1
world/player_water_trigger.gd.uid
Normal file
1
world/player_water_trigger.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dnlbnlimgxoc2
|
||||
9
world/safe_respawn_point.gd
Normal file
9
world/safe_respawn_point.gd
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
class_name SafeRespawnPoint
|
||||
extends Marker3D
|
||||
|
||||
@export var enabled: bool = true
|
||||
|
||||
|
||||
func get_horizontal_distance_squared(world_position: Vector3) -> float:
|
||||
var offset: Vector3 = global_position - world_position
|
||||
return Vector2(offset.x, offset.z).length_squared()
|
||||
1
world/safe_respawn_point.gd.uid
Normal file
1
world/safe_respawn_point.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://df2lsduguegxh
|
||||
18
world/test_world.gd
Normal file
18
world/test_world.gd
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
class_name TestWorld
|
||||
extends Node3D
|
||||
|
||||
@onready var _water_trigger: PlayerWaterTrigger = %PlayerWaterTrigger
|
||||
@onready var _safe_respawn_points: Node3D = %SafeRespawnPoints
|
||||
|
||||
|
||||
func get_player_water_trigger() -> PlayerWaterTrigger:
|
||||
return _water_trigger
|
||||
|
||||
|
||||
func get_safe_respawn_points() -> Array[SafeRespawnPoint]:
|
||||
var points: Array[SafeRespawnPoint] = []
|
||||
for child: Node in _safe_respawn_points.get_children():
|
||||
var point: SafeRespawnPoint = child as SafeRespawnPoint
|
||||
if point != null:
|
||||
points.append(point)
|
||||
return points
|
||||
1
world/test_world.gd.uid
Normal file
1
world/test_world.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bclc786v5xw8c
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
[gd_scene load_steps=14 format=3]
|
||||
[gd_scene load_steps=18 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="1_water_region"]
|
||||
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="2_fish_pool"]
|
||||
[ext_resource type="Script" path="res://world/test_world.gd" id="3_world"]
|
||||
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="4_water_trigger"]
|
||||
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="5_safe_point"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="GroundShape"]
|
||||
size = Vector3(30, 1, 30)
|
||||
|
|
@ -30,6 +33,12 @@ size = Vector3(40, 0.16, 19.5)
|
|||
[sub_resource type="BoxShape3D" id="FishableShoreShape"]
|
||||
size = Vector3(17.5, 0.16, 5.5)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="PlayerWaterShape"]
|
||||
size = Vector3(40, 5, 19.5)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="PlayerWaterShoreShape"]
|
||||
size = Vector3(17.5, 5, 5.5)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
|
||||
transparency = 1
|
||||
albedo_color = Color(0.1, 0.45, 0.7, 0.72)
|
||||
|
|
@ -43,6 +52,7 @@ ambient_light_color = Color(0.65, 0.72, 0.8, 1)
|
|||
ambient_light_energy = 0.65
|
||||
|
||||
[node name="TestWorld" type="Node3D"]
|
||||
script = ExtResource("3_world")
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource("Environment")
|
||||
|
|
@ -94,3 +104,41 @@ shape = SubResource("FishableShoreShape")
|
|||
[node name="ShoreRight" type="CollisionShape3D" parent="FishableWater"]
|
||||
position = Vector3(11.25, 0, 12.5)
|
||||
shape = SubResource("FishableShoreShape")
|
||||
|
||||
[node name="PlayerWaterTrigger" type="Area3D" parent="."]
|
||||
unique_name_in_owner = true
|
||||
position = Vector3(0, -2.3, -29.75)
|
||||
collision_layer = 8
|
||||
collision_mask = 2
|
||||
script = ExtResource("4_water_trigger")
|
||||
surface_height = 0.2
|
||||
|
||||
[node name="DeepWater" type="CollisionShape3D" parent="PlayerWaterTrigger"]
|
||||
shape = SubResource("PlayerWaterShape")
|
||||
|
||||
[node name="ShoreLeft" type="CollisionShape3D" parent="PlayerWaterTrigger"]
|
||||
position = Vector3(-11.25, 0, 12.5)
|
||||
shape = SubResource("PlayerWaterShoreShape")
|
||||
|
||||
[node name="ShoreRight" type="CollisionShape3D" parent="PlayerWaterTrigger"]
|
||||
position = Vector3(11.25, 0, 12.5)
|
||||
shape = SubResource("PlayerWaterShoreShape")
|
||||
|
||||
[node name="SafeRespawnPoints" type="Node3D" parent="."]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="DockApproach" type="Marker3D" parent="SafeRespawnPoints"]
|
||||
position = Vector3(0, 0.58, -9)
|
||||
script = ExtResource("5_safe_point")
|
||||
|
||||
[node name="WestShore" type="Marker3D" parent="SafeRespawnPoints"]
|
||||
position = Vector3(-11.5, 0.58, -11.5)
|
||||
script = ExtResource("5_safe_point")
|
||||
|
||||
[node name="EastShore" type="Marker3D" parent="SafeRespawnPoints"]
|
||||
position = Vector3(11.5, 0.58, -11.5)
|
||||
script = ExtResource("5_safe_point")
|
||||
|
||||
[node name="DockEnd" type="Marker3D" parent="SafeRespawnPoints"]
|
||||
position = Vector3(0, 1.08, -17)
|
||||
script = ExtResource("5_safe_point")
|
||||
|
|
|
|||
149
world/water_recovery_controller.gd
Normal file
149
world/water_recovery_controller.gd
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
class_name WaterRecoveryController
|
||||
extends Node
|
||||
|
||||
enum RecoveryState {
|
||||
IDLE,
|
||||
BOBBING,
|
||||
FADING_OUT,
|
||||
FADING_IN,
|
||||
}
|
||||
|
||||
@export_range(-1.0, 1.0, 0.01) var water_center_offset: float = 0.0
|
||||
@export_range(0.0, 0.5, 0.005) var bob_amplitude: float = 0.08
|
||||
@export_range(0.1, 10.0, 0.1) var bob_speed: float = 2.4
|
||||
@export_range(0.0, 5.0, 0.05) var pre_fade_bob_duration: float = 1.0
|
||||
@export_range(0.0, 1.0, 0.01) var respawn_height_offset: float = 0.08
|
||||
|
||||
var state: RecoveryState = RecoveryState.IDLE
|
||||
var _player: Player
|
||||
var _fishing_spot: FishingSpot
|
||||
var _game_ui: GameUI
|
||||
var _screen_fade: ScreenFade
|
||||
var _water_trigger: PlayerWaterTrigger
|
||||
var _safe_points: Array[SafeRespawnPoint] = []
|
||||
var _initial_spawn_transform: Transform3D
|
||||
var _entry_position: Vector3
|
||||
var _bob_base_position: Vector3
|
||||
var _bob_elapsed: float = 0.0
|
||||
var _prior_movement_enabled: bool = true
|
||||
var _prior_camera_input_enabled: bool = true
|
||||
var _generation: int = 0
|
||||
|
||||
|
||||
func setup(
|
||||
player: Player,
|
||||
fishing_spot: FishingSpot,
|
||||
game_ui: GameUI,
|
||||
screen_fade: ScreenFade,
|
||||
water_trigger: PlayerWaterTrigger,
|
||||
safe_points: Array[SafeRespawnPoint],
|
||||
) -> void:
|
||||
_player = player
|
||||
_fishing_spot = fishing_spot
|
||||
_game_ui = game_ui
|
||||
_screen_fade = screen_fade
|
||||
_water_trigger = water_trigger
|
||||
_safe_points = safe_points
|
||||
_initial_spawn_transform = player.global_transform
|
||||
if not _water_trigger.recovery_requested.is_connected(
|
||||
_on_recovery_requested
|
||||
):
|
||||
_water_trigger.recovery_requested.connect(_on_recovery_requested)
|
||||
if not _screen_fade.transition_completed.is_connected(
|
||||
_on_fade_transition_completed
|
||||
):
|
||||
_screen_fade.transition_completed.connect(
|
||||
_on_fade_transition_completed
|
||||
)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if state != RecoveryState.BOBBING or _player == null:
|
||||
return
|
||||
_bob_elapsed += delta
|
||||
var bob_offset: float = sin(_bob_elapsed * bob_speed * TAU) * bob_amplitude
|
||||
_player.global_position = _bob_base_position + Vector3.UP * bob_offset
|
||||
if _bob_elapsed >= pre_fade_bob_duration:
|
||||
state = RecoveryState.FADING_OUT
|
||||
_screen_fade.fade_to_black(_generation)
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
_generation += 1
|
||||
if _screen_fade != null and is_instance_valid(_screen_fade):
|
||||
_screen_fade.reset_immediately()
|
||||
if _player != null and is_instance_valid(_player):
|
||||
_player.set_water_recovery_active(false)
|
||||
_player.set_movement_enabled(_prior_movement_enabled)
|
||||
_player.set_camera_input_enabled(_prior_camera_input_enabled)
|
||||
state = RecoveryState.IDLE
|
||||
|
||||
|
||||
func _on_recovery_requested(
|
||||
triggered_player: Player,
|
||||
surface_height: float,
|
||||
) -> void:
|
||||
if (
|
||||
state != RecoveryState.IDLE
|
||||
or triggered_player != _player
|
||||
or not is_instance_valid(triggered_player)
|
||||
):
|
||||
return
|
||||
_generation += 1
|
||||
_entry_position = _player.global_position
|
||||
_game_ui.close_player_menu()
|
||||
_fishing_spot.begin_water_recovery()
|
||||
_prior_movement_enabled = _player.is_movement_enabled()
|
||||
_prior_camera_input_enabled = _player.is_camera_input_enabled()
|
||||
_player.set_movement_enabled(false)
|
||||
_player.set_camera_input_enabled(false)
|
||||
_player.set_water_recovery_active(true)
|
||||
_bob_base_position = _player.global_position
|
||||
_bob_base_position.y = (
|
||||
surface_height
|
||||
+ water_center_offset
|
||||
- _player.get_body_center_height()
|
||||
)
|
||||
_player.global_position = _bob_base_position
|
||||
_bob_elapsed = 0.0
|
||||
state = RecoveryState.BOBBING
|
||||
|
||||
|
||||
func _on_fade_transition_completed(
|
||||
generation: int,
|
||||
faded_to_black: bool,
|
||||
) -> void:
|
||||
if generation != _generation:
|
||||
return
|
||||
if faded_to_black and state == RecoveryState.FADING_OUT:
|
||||
_respawn_player()
|
||||
state = RecoveryState.FADING_IN
|
||||
_screen_fade.fade_from_black(_generation)
|
||||
elif not faded_to_black and state == RecoveryState.FADING_IN:
|
||||
_finish_recovery()
|
||||
|
||||
|
||||
func _respawn_player() -> void:
|
||||
var target_transform: Transform3D = _initial_spawn_transform
|
||||
var nearest_distance: float = INF
|
||||
for point: SafeRespawnPoint in _safe_points:
|
||||
if point == null or not is_instance_valid(point) or not point.enabled:
|
||||
continue
|
||||
var distance: float = point.get_horizontal_distance_squared(
|
||||
_entry_position
|
||||
)
|
||||
if distance < nearest_distance:
|
||||
nearest_distance = distance
|
||||
target_transform = point.global_transform
|
||||
target_transform.origin.y += respawn_height_offset
|
||||
_player.global_transform = target_transform
|
||||
_player.velocity = Vector3.ZERO
|
||||
|
||||
|
||||
func _finish_recovery() -> void:
|
||||
_player.set_water_recovery_active(false)
|
||||
_player.set_movement_enabled(_prior_movement_enabled)
|
||||
_player.set_camera_input_enabled(_prior_camera_input_enabled)
|
||||
_fishing_spot.end_water_recovery()
|
||||
state = RecoveryState.IDLE
|
||||
_bob_elapsed = 0.0
|
||||
1
world/water_recovery_controller.gd.uid
Normal file
1
world/water_recovery_controller.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dvv0ublaoj4gr
|
||||
Loading…
Add table
Add a link
Reference in a new issue