92 lines
2.6 KiB
GDScript3
Raw Normal View History

2024-02-16 14:30:29 +00:00
class_name FootstepsComponent
2024-02-19 22:23:12 +00:00
extends Node3D
2024-02-14 17:05:57 +00:00
2024-02-14 19:29:52 +00:00
@export var skeleton: Skeleton3D
2024-02-14 17:05:57 +00:00
@export var movement: MovementComponent
2024-02-16 13:46:26 +00:00
@export var footsteps: AudioStreamRandomizer
2024-02-14 23:20:26 +00:00
@export var step_threshold := 0.1
2024-02-19 22:23:12 +00:00
@export var ik_step_threshold := 0.2
@export var ik_speed := 5.0
2024-02-14 17:05:57 +00:00
2024-02-14 23:20:26 +00:00
const feet_names := ["LeftFoot", "RightFoot"]
var feet: Array[Foot] = []
2024-02-19 22:23:12 +00:00
var ik_time: float
2024-02-14 17:05:57 +00:00
func _ready():
2024-02-14 19:29:52 +00:00
for foot_name in feet_names:
2024-02-14 23:20:26 +00:00
var foot = Foot.new()
foot.bone_name = foot_name
foot.bone_id = skeleton.find_bone(foot_name)
foot.audio = get_node(foot_name)
foot.position = skeleton.to_global(skeleton.get_bone_global_pose(foot.bone_id).origin)
2024-02-19 22:23:12 +00:00
foot.floor_distance = INF
foot.normal = Vector3.UP
2024-02-14 23:20:26 +00:00
foot.attachment = BoneAttachment3D.new()
foot.attachment.bone_name = foot_name
foot.attachment.bone_idx = foot.bone_id
foot.audio.reparent(foot.attachment)
skeleton.add_child(foot.attachment)
feet.append(foot)
func _process(delta: float):
for foot in feet:
var old_position := foot.position
2024-02-20 22:58:44 +00:00
var global_pose := skeleton.get_bone_global_pose(foot.bone_id)
var world_pose := skeleton.global_transform * global_pose
foot.position = world_pose.origin
2024-02-19 22:23:12 +00:00
if foot.floor_distance < ik_step_threshold:
ik_time = minf(ik_time + ik_speed * delta, 1.0)
2024-02-20 22:58:44 +00:00
align_surface_normal(foot, world_pose)
2024-02-19 22:23:12 +00:00
else:
ik_time = 0
2024-02-14 23:20:26 +00:00
2024-02-19 22:23:12 +00:00
if foot.floor_distance > step_threshold:
2024-02-14 23:20:26 +00:00
continue
2024-02-19 22:23:12 +00:00
foot.velocity = (foot.position - old_position) / delta
2024-02-14 23:20:26 +00:00
if foot.velocity.y > 0:
continue
if foot.velocity.length_squared() < 1.0:
continue
if foot.audio.playing && foot.audio.get_playback_position() < 0.3:
continue
play(foot.audio)
2024-02-14 17:05:57 +00:00
2024-02-19 22:23:12 +00:00
func _physics_process(_delta):
var space_state = get_world_3d().direct_space_state
for foot in feet:
var from := foot.position
var to := foot.position + Vector3(0, -10, 0)
var query = PhysicsRayQueryParameters3D.create(from, to, 1)
var result = space_state.intersect_ray(query)
if result:
foot.floor_distance = (foot.position - result.position).length()
foot.normal = result.normal
else:
foot.floor_distance = INF
foot.normal = Vector3.UP
2024-02-14 19:29:52 +00:00
func play(audio_player: AudioStreamPlayer3D):
2024-02-16 13:46:26 +00:00
audio_player.stream = footsteps
2024-02-14 23:20:26 +00:00
audio_player.play()
2024-02-19 22:23:12 +00:00
2024-02-20 22:58:44 +00:00
func align_surface_normal(foot: Foot, world_pose: Transform3D):
var pose := skeleton.get_bone_pose(foot.bone_id)
var local_normal := world_pose.basis.transposed() * foot.normal
var new_basis := get_foot_rotation(pose.basis, local_normal)
skeleton.set_bone_pose_rotation(foot.bone_id, pose.basis.slerp(new_basis, ik_time))
func get_foot_rotation(old: Basis, normal: Vector3) -> Basis:
var new := Basis(-old.x, normal, old.z)
new = new.orthonormalized()
new = new.rotated(Vector3.UP, PI)
return new