immersive-home/addons/godot-xr-tools/examples/fall_damage.gd
2023-10-16 19:10:20 +02:00

93 lines
2.6 KiB
GDScript

@tool
class_name XRToolsFallDamage
extends XRToolsMovementProvider
## XR Tools Example Fall Damage Detector
##
## This example script detects the player falling to the ground and
## optionally hitting walls.
##
## It works by tracking the player body velocity to detect velocity
## changes (acceleration) exceeding a threshold.
##
## This doesn't use the usual Acceleration = dV / dT as it doesn't appear
## to work too well considering the "instantaneous" nature of the
## collision. Additionally all it would end up doing is multiplying the
## change in velocity by the physics-frame-rate making it sensitive to
## varying physics timing.
##
## Instead the threshold in terms of delta-velocity makes it easy to work
## out natural values. For example if the player falls under regular gravity
## (9.81 meters per second^2 for 1 second) then hits the ground, they will have fallen around
## 4.9 meters, and will then encounter an instantaneous velocity-change of
## 9.81 meters per second.
##
## This file can handle simple demonstrations, but games will most likely
## want to modify it, for example to ignore damage on certain surfaces.
## Signal invoked when the player takes fall damage
signal player_fall_damage(damage)
## Movement provider order
@export var order : int = 1000
## Ignore damage if player is launched up
@export var ignore_launch : bool = true
## Only take damage on ground
@export var ground_only : bool = false
## Acceleration limit
@export var damage_threshold : float = 8.0
## Previous velocity
var _previous_velocity : Vector3 = Vector3.ZERO
# Add support for is_xr_class on XRTools classes
func is_xr_class(name : String) -> bool:
return name == "XRToolsFallDamage"
func _ready():
# In Godot 4 we must now manually call our super class ready function
super()
# Set as always active
is_active = true
func physics_movement(_delta: float, player_body: XRToolsPlayerBody, disabled: bool):
# Skip if not enabled
if disabled or !enabled:
_previous_velocity = player_body.velocity
return
# Calculate the instantaneous acceleration
var accel_vec := player_body.velocity - _previous_velocity
_previous_velocity = player_body.velocity
# Ignore launching the player
if ignore_launch:
# Forgive "up" acceleration equal to our "up" speed
var forgive : float = max(0, min(accel_vec.y, player_body.velocity.y))
accel_vec.y -= forgive
# Handle ground-only collisions
if ground_only:
# Ignore if not on ground
if not player_body.on_ground:
return
# Only consider vertical acceleration
accel_vec *= Vector3.UP
# Detect fall damage
var accel := accel_vec.length()
if accel > damage_threshold:
emit_signal("player_fall_damage", accel)