feat: implemented ledge hang

This commit is contained in:
Sara Gerretsen 2026-05-05 17:08:09 +02:00
parent aa579d0118
commit bd082ccb95
6 changed files with 126 additions and 33 deletions

View file

@ -20,6 +20,11 @@ animation = &"RESET"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_3nfmf"]
animation = &"jump"
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_i825w"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_42cpl"]
animation = &"hang"
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_uxov2"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_i825w"]
@ -69,8 +74,7 @@ animation = &"wallrun_right"
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_eqqp1"]
[sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_uxov2"]
graph_offset = Vector2(-708.59985, 313.57794)
nodes/output/position = Vector2(520, 140)
nodes/output/position = Vector2(720, 140)
nodes/RunStates/node = SubResource("AnimationNodeStateMachine_3nfmf")
nodes/RunStates/position = Vector2(-800, 320)
nodes/Decelerating/node = SubResource("AnimationNodeBlend2_ykyjo")
@ -103,7 +107,11 @@ nodes/Jumping/node = SubResource("AnimationNodeAnimation_3nfmf")
nodes/Jumping/position = Vector2(-340, 580)
nodes/Falling/node = SubResource("AnimationNodeAnimation_4vq5b")
nodes/Falling/position = Vector2(-340, 760)
node_connections = [&"output", 0, &"Wall", &"Decelerating", 0, &"Speed", &"Decelerating", 1, &"SkidStopLoop", &"Air", 0, &"Moving", &"Air", 1, &"AirTime", &"Speed", 0, &"RunStates", &"Wall", 0, &"Air", &"Wall", 1, &"WallAction", &"WallAction", 0, &"WallGripLoop", &"WallAction", 1, &"WallRunSide", &"WallRunSide", 0, &"WallRunLeftLoop", &"WallRunSide", 1, &"WallRunRightLoop", &"Moving", 0, &"IdleLoop", &"Moving", 1, &"Decelerating", &"AirTime", 0, &"Jumping", &"AirTime", 1, &"Falling"]
nodes/Ledge/node = SubResource("AnimationNodeBlend2_i825w")
nodes/Ledge/position = Vector2(540, 140)
nodes/LedgeLoop/node = SubResource("AnimationNodeAnimation_42cpl")
nodes/LedgeLoop/position = Vector2(300, 400)
node_connections = [&"output", 0, &"Ledge", &"Decelerating", 0, &"Speed", &"Decelerating", 1, &"SkidStopLoop", &"Air", 0, &"Moving", &"Air", 1, &"AirTime", &"Speed", 0, &"RunStates", &"Wall", 0, &"Air", &"Wall", 1, &"WallAction", &"WallAction", 0, &"WallGripLoop", &"WallAction", 1, &"WallRunSide", &"WallRunSide", 0, &"WallRunLeftLoop", &"WallRunSide", 1, &"WallRunRightLoop", &"Moving", 0, &"IdleLoop", &"Moving", 1, &"Decelerating", &"AirTime", 0, &"Jumping", &"AirTime", 1, &"Falling", &"Ledge", 0, &"Wall", &"Ledge", 1, &"LedgeLoop"]
[sub_resource type="GDScript" id="GDScript_i825w"]
resource_name = "PlayerAnimationPlayer"
@ -147,6 +155,72 @@ func _process(delta: float) -> void:
set(\"parameters/Wall/blend_amount\", 0.0)
"
[sub_resource type="GDScript" id="GDScript_f46kd"]
resource_name = "HangRay"
script/source = "@tool extends RayCast3D
@onready var body : PlayerBody = get_owner() as Node3D
@export var dist_mul : float
var last_direction : Vector3 = Vector3.BACK
func _ready() -> void:
add_exception(body)
func _process(_delta : float):
if Engine.is_editor_hint() and body:
global_position = body.global_position + Vector3.UP + Vector3.BACK * dist_mul
elif body:
var direction : Vector3 = -body.velocity
if body.is_on_wall():
direction = body.get_wall_normal()
if not direction.is_zero_approx():
last_direction = Vector3(direction.x, 0, direction.z).normalized()
global_position = body.global_position + Vector3.UP + last_direction * dist_mul
"
[sub_resource type="GDScript" id="GDScript_3rerk"]
resource_name = "BelowLedgePrerequisite"
script/source = "extends PlayerAction
var timeout : bool = false
func _ready():
$\"../Timer\".timeout.connect(set.bind(\"timeout\", false))
func _enter() -> int:
if not timeout and not body.is_on_floor() and blackboard.hang_ray.is_colliding() and blackboard.hang_ray.get_collision_normal().y > 0.9 and body.is_on_wall():
print(blackboard.hang_ray.get_collider().get_path())
timeout = true
return Success
else:
return Fail
"
[sub_resource type="GDScript" id="GDScript_uxov2"]
resource_name = "PlayerLedgeHangAction"
script/source = "extends PlayerAction
func _enter() -> int:
return Running
func _execute() -> int:
blackboard.anim.set(\"parameters/Ledge/blend_amount\", 1.0)
var diff : Vector3 = blackboard.hang_ray.get_collision_point() - blackboard.hang_ray.global_position
var direction : Vector3 = -blackboard.character.global_basis.z
if body.is_on_wall():
direction = -body.get_wall_normal()
blackboard.character.look_at(blackboard.character.global_position + Vector3(direction.x, 0, direction.z))
body.velocity = Vector3(body.velocity.x * 0.7, diff.y * 15., body.velocity.z * 0.7)
if Input.is_action_just_pressed(\"jump\"):
body.velocity += Vector3(0, 6, 0)
return Success
return Running
func _exit():
blackboard.anim.set(\"parameters/Ledge/blend_amount\", 0.0)
$\"../Timer\".start()
"
[sub_resource type="GDScript" id="GDScript_nmc1l"]
resource_name = "WallGripAction"
script/source = "extends PlayerAction
@ -275,6 +349,7 @@ parameters/WallAction/blend_amount = 0.0
parameters/WallRunSide/blend_amount = 0.0
parameters/Moving/blend_amount = 0.0
parameters/AirTime/blend_amount = 0.0
parameters/Ledge/blend_amount = 0.0
script = SubResource("GDScript_i825w")
default_blend_time = 30.0
full_speed = 7.0
@ -284,10 +359,11 @@ jump_to_fall_speed = 3.0
air_blend_speed = 6.0
[node name="HangRay" type="RayCast3D" parent="PlayerModel" unique_id=183285060]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.0015578, -0.4715811)
target_position = Vector3(0, -0.2, 0)
hit_from_inside = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, -0.508)
target_position = Vector3(0, -1.792, 0)
hit_back_faces = false
script = SubResource("GDScript_f46kd")
dist_mul = -0.508
[node name="Camera3D" type="PlayerCamera" parent="." unique_id=709217818]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.3841858e-07, 0.81082594, 1.2089427)
@ -301,6 +377,17 @@ character = NodePath("../PlayerModel")
[node name="ActionSelector" type="BehaviourSelector" parent="PlayerBehaviourTree/BehaviourRepeater" unique_id=433229675]
[node name="LedgeHangSequence" type="BehaviourSequence" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector" unique_id=285489367]
[node name="Timer" type="Timer" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector/LedgeHangSequence" unique_id=465275658]
process_mode = 1
[node name="CanLedgeHang" type="PlayerAction" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector/LedgeHangSequence" unique_id=1704888964]
script = SubResource("GDScript_3rerk")
[node name="LedgeHang" type="PlayerAction" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector/LedgeHangSequence" unique_id=189327718]
script = SubResource("GDScript_uxov2")
[node name="WallGrip" type="PlayerAction" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector" unique_id=85039173]
script = SubResource("GDScript_nmc1l")
wall_drag = 15.0