162 lines
4.6 KiB
GDScript
162 lines
4.6 KiB
GDScript
class_name WaterRecoveryController
|
|
extends Node
|
|
|
|
signal recovery_starting
|
|
|
|
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
|
|
var _recovery_enabled: bool = false
|
|
|
|
|
|
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 set_recovery_enabled(enabled: bool) -> void:
|
|
_recovery_enabled = enabled
|
|
|
|
|
|
func is_recovery_active() -> bool:
|
|
return state != RecoveryState.IDLE
|
|
|
|
|
|
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 (
|
|
not _recovery_enabled
|
|
or
|
|
state != RecoveryState.IDLE
|
|
or triggered_player != _player
|
|
or not is_instance_valid(triggered_player)
|
|
):
|
|
return
|
|
recovery_starting.emit()
|
|
_generation += 1
|
|
_entry_position = _player.global_position
|
|
_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
|