feat: improvements to consistency of player behaviour

This commit is contained in:
Sara Gerretsen 2026-05-21 22:50:20 +02:00
parent fad6fc1287
commit fdfd1dc04a
5 changed files with 79 additions and 65 deletions

Binary file not shown.

View file

@ -3,7 +3,7 @@
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://t3vyihwed4ko"
uid="uid://blaoym0srw5o5"
path="res://.godot/imported/player.blend-5e710df360f43fa10fe21ae59dac189a.scn"
[deps]
@ -16524,7 +16524,7 @@ blender/nodes/punctual_lights=true
blender/nodes/cameras=true
blender/nodes/custom_properties=true
blender/nodes/modifiers=1
blender/meshes/vertex_colors=2
blender/meshes/vertex_colors=1
blender/meshes/uvs=true
blender/meshes/normals=true
blender/meshes/export_geometry_nodes_instances=false
@ -16537,5 +16537,5 @@ blender/materials/export_materials=1
blender/animation/limit_playback=true
blender/animation/always_sample=true
blender/animation/group_tracks=true
gltf/naming_version=0
gltf/naming_version=2
gltf/texture_map_mode=1

View file

@ -1,26 +1,26 @@
[gd_scene format=3 uid="uid://c1g1vy67lf550"]
[ext_resource type="PackedScene" uid="uid://t3vyihwed4ko" path="res://assets/character/player/player.blend" id="1_1oybq"]
[ext_resource type="PackedScene" uid="uid://blaoym0srw5o5" path="res://assets/character/player/player.blend" id="1_1oybq"]
[node name="PlayerModel" unique_id=1710695753 instance=ExtResource("1_1oybq")]
[node name="HumanArmature" parent="." index="0" unique_id=555809931]
[node name="HumanArmature" parent="." index="0" unique_id=1751290725]
transform = Transform3D(-1, 0, -8.742278e-08, 0, 1, 0, 8.742278e-08, 0, -1, 0, 0, 0)
[node name="BlankCharacterMesh" parent="HumanArmature/Skeleton3D" parent_id_path=PackedInt32Array(226404995) index="0" unique_id=703587246]
[node name="BlankCharacterMesh" parent="HumanArmature/Skeleton3D" parent_id_path=PackedInt32Array(1497073029) index="0" unique_id=513141126]
layers = 3
[node name="BootL" parent="HumanArmature/Skeleton3D" parent_id_path=PackedInt32Array(226404995) index="1" unique_id=979009251]
[node name="BootL" parent="HumanArmature/Skeleton3D" parent_id_path=PackedInt32Array(1497073029) index="1" unique_id=343538324]
layers = 3
[node name="BootR" parent="HumanArmature/Skeleton3D" parent_id_path=PackedInt32Array(226404995) index="2" unique_id=233633100]
[node name="BootR" parent="HumanArmature/Skeleton3D" parent_id_path=PackedInt32Array(1497073029) index="2" unique_id=1338096799]
layers = 3
[node name="Eyes" parent="HumanArmature/Skeleton3D" parent_id_path=PackedInt32Array(226404995) index="3" unique_id=394315427]
[node name="Eyes" parent="HumanArmature/Skeleton3D" parent_id_path=PackedInt32Array(1497073029) index="3" unique_id=602091173]
layers = 3
[node name="Jacket" parent="HumanArmature/Skeleton3D" parent_id_path=PackedInt32Array(226404995) index="4" unique_id=324672015]
[node name="Jacket" parent="HumanArmature/Skeleton3D" parent_id_path=PackedInt32Array(1497073029) index="4" unique_id=2011987394]
layers = 3
[node name="Mouth" parent="HumanArmature/Skeleton3D" parent_id_path=PackedInt32Array(226404995) index="5" unique_id=1964091532]
[node name="Mouth" parent="HumanArmature/Skeleton3D" parent_id_path=PackedInt32Array(1497073029) index="5" unique_id=1092763051]
layers = 3

View file

@ -16,6 +16,7 @@ fadeout_time = 0.02
animation = &"hang-clamber"
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_ykyjo"]
sync = true
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_4vq5b"]
animation = &"fall"
@ -35,37 +36,21 @@ animation = &"hang"
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_uxov2"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_i825w"]
animation = &"run-start"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_3rfka"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_eqqp1"]
animation = &"run"
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_i8sra"]
switch_mode = 2
advance_mode = 2
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_4vq5b"]
advance_mode = 2
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_eqqp1"]
advance_mode = 2
advance_expression = "(abs(body.velocity.x) + abs(body.velocity.z)) < 1.0"
[sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_3nfmf"]
state_machine_type = 1
states/run/node = SubResource("AnimationNodeAnimation_3rfka")
states/run/position = Vector2(603.5664, 100)
states/run-start/node = SubResource("AnimationNodeAnimation_i825w")
states/run-start/position = Vector2(439.96094, 100)
transitions = ["run-start", "run", SubResource("AnimationNodeStateMachineTransition_i8sra"), "Start", "run-start", SubResource("AnimationNodeStateMachineTransition_4vq5b"), "run", "run-start", SubResource("AnimationNodeStateMachineTransition_eqqp1")]
graph_offset = Vector2(-64.40625, 19.996094)
[sub_resource type="AnimationNodeTimeSeek" id="AnimationNodeTimeSeek_eqqp1"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_i8sra"]
animation = &"skid"
[sub_resource type="AnimationNodeTimeScale" id="AnimationNodeTimeScale_jbsc3"]
[sub_resource type="AnimationNodeOneShot" id="AnimationNodeOneShot_uxov2"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_i825w"]
animation = &"run-start"
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_3rerk"]
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_nmc1l"]
@ -82,15 +67,16 @@ animation = &"wallrun_right"
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_eqqp1"]
[sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_uxov2"]
graph_offset = Vector2(-1099.0525, -697.3944)
nodes/output/position = Vector2(1140, 140)
nodes/RunStates/node = SubResource("AnimationNodeStateMachine_3nfmf")
nodes/RunStates/position = Vector2(-400, -560)
nodes/ClimbUpClip/node = SubResource("AnimationNodeAnimation_vqq2l")
nodes/ClimbUpClip/position = Vector2(480, 480)
nodes/Decelerating/node = SubResource("AnimationNodeBlend2_ykyjo")
nodes/Decelerating/position = Vector2(60, -560)
nodes/Decelerating/position = Vector2(-340, -600)
nodes/Air/node = SubResource("AnimationNodeBlend2_1oybq")
nodes/Air/position = Vector2(480, -280)
nodes/Speed/node = SubResource("AnimationNodeTimeScale_jbsc3")
nodes/Speed/position = Vector2(-160, -560)
nodes/Speed/position = Vector2(60, -540)
nodes/Wall/node = SubResource("AnimationNodeBlend2_3rerk")
nodes/Wall/position = Vector2(700, -60)
nodes/WallAction/node = SubResource("AnimationNodeBlend2_nmc1l")
@ -104,7 +90,7 @@ nodes/WallRunSide/position = Vector2(260, 200)
nodes/WallRunRightLoop/node = SubResource("AnimationNodeAnimation_nmc1l")
nodes/WallRunRightLoop/position = Vector2(40, 380)
nodes/SkidStopLoop/node = SubResource("AnimationNodeAnimation_i8sra")
nodes/SkidStopLoop/position = Vector2(-160, -380)
nodes/SkidStopLoop/position = Vector2(-620, -420)
nodes/IdleLoop/node = SubResource("AnimationNodeAnimation_3rerk")
nodes/IdleLoop/position = Vector2(60, -740)
nodes/Moving/node = SubResource("AnimationNodeBlend2_uxov2")
@ -121,9 +107,15 @@ nodes/LedgeLoop/node = SubResource("AnimationNodeAnimation_42cpl")
nodes/LedgeLoop/position = Vector2(480, 300)
nodes/ClimbUp/node = SubResource("AnimationNodeOneShot_ykyjo")
nodes/ClimbUp/position = Vector2(700, 260)
nodes/ClimbUpClip/node = SubResource("AnimationNodeAnimation_vqq2l")
nodes/ClimbUpClip/position = Vector2(480, 480)
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, &"ClimbUp", &"ClimbUp", 0, &"LedgeLoop", &"ClimbUp", 1, &"ClimbUpClip"]
nodes/StartRunning/node = SubResource("AnimationNodeOneShot_uxov2")
nodes/StartRunning/position = Vector2(-120, -600)
nodes/StartRunningAnimation/node = SubResource("AnimationNodeAnimation_i825w")
nodes/StartRunningAnimation/position = Vector2(-440, -300)
nodes/RunLoop/node = SubResource("AnimationNodeAnimation_eqqp1")
nodes/RunLoop/position = Vector2(-740, -620)
nodes/RunSeek/node = SubResource("AnimationNodeTimeSeek_eqqp1")
nodes/RunSeek/position = Vector2(-540, -620)
node_connections = [&"output", 0, &"Ledge", &"Decelerating", 0, &"RunSeek", &"Decelerating", 1, &"SkidStopLoop", &"Air", 0, &"Moving", &"Air", 1, &"AirTime", &"Speed", 0, &"StartRunning", &"Wall", 0, &"Air", &"Wall", 1, &"WallAction", &"WallAction", 0, &"WallGripLoop", &"WallAction", 1, &"WallRunSide", &"WallRunSide", 0, &"WallRunLeftLoop", &"WallRunSide", 1, &"WallRunRightLoop", &"Moving", 0, &"IdleLoop", &"Moving", 1, &"Speed", &"AirTime", 0, &"Jumping", &"AirTime", 1, &"Falling", &"Ledge", 0, &"Wall", &"Ledge", 1, &"ClimbUp", &"ClimbUp", 0, &"LedgeLoop", &"ClimbUp", 1, &"ClimbUpClip", &"StartRunning", 0, &"Decelerating", &"StartRunning", 1, &"StartRunningAnimation", &"RunSeek", 0, &"RunLoop"]
[sub_resource type="GDScript" id="GDScript_i825w"]
resource_name = "PlayerAnimationPlayer"
@ -140,6 +132,8 @@ script/source = "extends AnimationTree
@export var jump_to_fall_speed : float
@export var air_blend_speed : float
var previous_speed : float = 0.0
func property_move_toward(property : String, target, speed) -> float:
var current = get(property)
var diff = target - current
@ -158,13 +152,17 @@ func property_move_toward(property : String, target, speed) -> float:
func process_skid_blend(delta : float, speed : float):
var current_deceleration_blend = get(\"parameters/Decelerating/blend_amount\")
var deceleration_distance : float = 0.0 if behaviour_tree.get_world_move_input().dot(body.velocity) > 0.5 else clamp(speed / min_skid_speed, 0.0, 1.0)
var deceleration_distance : float = 0.0 if behaviour_tree.get_world_move_input().dot(body.velocity) > 0.1 else clamp(speed / min_skid_speed, 0.0, 1.0)
var skid_blend_speed : float = skid_blend_speed_in if deceleration_distance >= current_deceleration_blend else skid_blend_speed_out
property_move_toward(\"parameters/Decelerating/blend_amount\", deceleration_distance, delta * skid_blend_speed)
func _physics_process(delta: float) -> void:
var speed : float = Vector2(body.velocity.x, body.velocity.z).length()
set(\"parameters/Speed/scale\", clamp(speed / full_speed, 0.0, 2.0))
if previous_speed == 0.0 and speed > 0.0 and not get(\"parameters/StartRunning/active\"):
set(\"parameters/RunSeek/seek_request\", 0.0)
set(\"parameters/StartRunning/request\", AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE)
set(\"parameters/Speed/scale\", clamp(speed / full_speed, 0.2, 1.0))
previous_speed = speed
process_skid_blend(delta, speed)
property_move_toward(\"parameters/Moving/blend_amount\", 1.0 if speed > 0.05 else 0.0, delta * default_blend_time)
var in_air : bool = 1.0 == property_move_toward(\"parameters/Air/blend_amount\", 0.0 if body.is_on_floor() else 1.0, delta * air_blend_speed)
@ -178,18 +176,18 @@ func _physics_process(delta: float) -> void:
resource_name = "HangRay"
script/source = "@tool extends RayCast3D
@onready var body : PlayerBody = get_owner() as Node3D
@export var dist_mul : float
@export var height : float = 1.0
var last_direction : Vector3 = Vector3.BACK
@onready var body : PlayerBody = get_owner() as Node3D
func _ready() -> void:
add_exception(body)
func _process(_delta : float):
_physics_process(_delta)
func _physics_process(_delta : float):
_process(_delta)
func _process(_delta : float):
if Engine.is_editor_hint() and body:
global_position = body.global_position + Vector3.UP * height + Vector3.BACK * dist_mul
elif body:
@ -200,12 +198,18 @@ func _physics_process(_delta : float):
if not direction.is_zero_approx():
last_direction = direction
global_position = body.global_position + Vector3.UP * height + last_direction * dist_mul
force_raycast_update()
"
[sub_resource type="GDScript" id="GDScript_4vq5b"]
resource_name = "PlayerHighWallRay"
script/source = "extends RayCast3D
@onready var body : PlayerBody = get_owner() as Node3D
func _ready() -> void:
add_exception(body)
func _physics_process(_delta : float):
_process(_delta)
@ -213,6 +217,7 @@ func _process(_delta : float):
target_position = $\"../HangRay\".global_position - global_position
global_rotation = Vector3.ZERO
global_position = get_parent_node_3d().global_position + Vector3.UP * 2.0
force_raycast_update()
"
[sub_resource type="GDScript" id="GDScript_3rerk"]
@ -225,13 +230,11 @@ func _ready():
%LedgeHangTimer.timeout.connect(set.bind(\"timeout\", false))
func _enter() -> int:
blackboard.hang_ray.force_raycast_update()
blackboard.high_wall_ray.force_raycast_update()
if not timeout and not body.is_on_floor() and blackboard.hang_ray.is_colliding() and not blackboard.high_wall_ray.is_colliding():
if not timeout and not body.is_on_floor() and body.is_on_wall() and blackboard.hang_ray.is_colliding() and not blackboard.high_wall_ray.is_colliding():
blackboard.ground_ray.force_raycast_update()
var wall_normal_y : float = blackboard.hang_ray.get_collision_normal().y
var edge_distance : float = blackboard.hang_ray.get_collision_point().distance_to(blackboard.hang_ray.global_position)
if wall_normal_y > 0.9 and body.is_on_wall() and blackboard.get_ground_distance() > (1.0 + edge_distance):
if wall_normal_y > 0.9 and blackboard.get_ground_distance() > edge_distance + 1:
timeout = true
return Success
return Fail
@ -379,8 +382,7 @@ func _execute() -> int:
var look_direction := Vector3(blackboard.character.global_basis.z.x, 0, blackboard.character.global_basis.z.z)
blackboard.character.look_at(blackboard.character.global_position - look_direction)
blackboard.anim.property_move_toward(\"parameters/Wall/blend_amount\", 0.0, get_process_delta_time() * 15)
if not body.is_on_wall():
return Running
return Success
return Fail
"
@ -391,7 +393,7 @@ script/source = "extends PlayerAction
@export var vertical_jump_velocity : float
func _enter() -> int:
if Input.is_action_just_pressed(\"jump\"):
if Input.is_action_just_pressed(\"jump\") and body.is_on_floor():
body.velocity.y = vertical_jump_velocity
blackboard.anim.set(\"parameters/AirTime/blend_amount\", 0.0)
return Success
@ -416,6 +418,9 @@ floor_snap_length = 0.2
shape = SubResource("CapsuleShape3D_bxedw")
[node name="GroundRay" type="RayCast3D" parent="." unique_id=1763928231]
process_mode = 3
process_priority = 1
process_physics_priority = 1
target_position = Vector3(0, -500, 0)
hit_back_faces = false
@ -440,28 +445,37 @@ parameters/Ledge/request = 0
parameters/ClimbUp/active = false
parameters/ClimbUp/internal_active = false
parameters/ClimbUp/request = 0
parameters/StartRunning/active = false
parameters/StartRunning/internal_active = false
parameters/StartRunning/request = 0
parameters/RunSeek/seek_request = -1.0
script = SubResource("GDScript_i825w")
default_blend_time = 30.0
full_speed = 10.0
min_skid_speed = 8.0
full_speed = 5.0
min_skid_speed = 10.0
skid_blend_speed_in = 10.0
skid_blend_speed_out = 1.5
skid_blend_speed_out = 5.0
jump_to_fall_speed = 2.0
air_blend_speed = 50.0
[node name="HangRay" type="RayCast3D" parent="PlayerModel" unique_id=183285060]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, -0.624)
top_level = true
enabled = false
process_mode = 3
process_priority = 1
process_physics_priority = 1
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, -0.624)
target_position = Vector3(0, -2, 0)
hit_back_faces = false
script = SubResource("GDScript_f46kd")
dist_mul = -0.624
[node name="HighWallRay" type="RayCast3D" parent="PlayerModel" unique_id=2283840]
process_mode = 3
process_priority = 1
process_physics_priority = 1
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
enabled = false
target_position = Vector3(0, 0, -0.5)
collision_mask = 15
hit_back_faces = false
script = SubResource("GDScript_4vq5b")
[node name="Camera3D" type="PlayerCamera" parent="." unique_id=709217818]
@ -513,7 +527,7 @@ min_run_time = 0.05
script = SubResource("GDScript_nmc1l")
wall_drag = 15.0
max_y_velocity = 4.0
jump_normal_force = 5.0
jump_normal_force = 2.5
jump_vertical_force = 6.0
[node name="Fall" type="PlayerAction" parent="PlayerBehaviourTree/BehaviourRepeater/ActionSelector" unique_id=570179125]