megalith/src/player/camera/fall_kick_effect.gd
Rob Kelly 52e70f8c14
All checks were successful
linting & formatting / build (push) Successful in 12s
Removed debug text
2025-09-29 17:00:07 -06:00

60 lines
1.5 KiB
GDScript

extends Node3D
## Give the camera a little kick when the player falls, proportional to landing velocity
@export var enabled := true
@export var character: CharacterBody3D
## Minimum landing speed before kick is applied, in m/s
@export var min_landing_speed := 4.0
## How far the camera gets pitched on kick in degrees per m/s of landing velocity
@export var angle_curve: Curve
## How far down the camera gets kicked in meters per m/s of landing velocity
@export var offset_curve: Curve
## How long the rebound takes in seconds per m/s of landing velocity
@export var rebound_time_curve: Curve
var _last_speed := 0.0
var _in_air := false
var _tween: Tween
func _get_tween() -> Tween:
if _tween and _tween.is_valid():
_tween.kill()
_tween = create_tween()
return _tween
func do_kick(landing_speed: float) -> void:
if landing_speed < min_landing_speed:
return
# Initial kick
rotation.x = -deg_to_rad(angle_curve.sample(landing_speed))
position.y = -offset_curve.sample(landing_speed)
# Rebound
var rebound_time := rebound_time_curve.sample(landing_speed)
var tween := _get_tween()
tween.set_parallel(true)
tween.tween_property(self, "rotation:x", 0, rebound_time).set_trans(Tween.TRANS_CUBIC).set_ease(
Tween.EASE_OUT
)
tween.tween_property(self, "position:y", 0, rebound_time).set_trans(Tween.TRANS_CUBIC).set_ease(
Tween.EASE_OUT
)
func _process(_delta: float) -> void:
if character.is_on_floor():
if _in_air:
# First frame after land
do_kick(absf(_last_speed))
_in_air = false
else:
_in_air = true
_last_speed = character.velocity.y