From 032e05982685e175826233989245c1dd0ebcfdb8 Mon Sep 17 00:00:00 2001 From: Minimata Date: Fri, 13 Feb 2026 10:24:25 +0100 Subject: [PATCH] wall run is easier to control and triggers more consistently --- maps/levels/tuto_enemies.tscn | 11 +- maps/levels/tuto_sword_parry.tscn | 31 +++-- .../scripts/PlayerController.cs | 117 +++++++++++++----- 3 files changed, 112 insertions(+), 47 deletions(-) diff --git a/maps/levels/tuto_enemies.tscn b/maps/levels/tuto_enemies.tscn index 094661fb..43f94cbf 100644 --- a/maps/levels/tuto_enemies.tscn +++ b/maps/levels/tuto_enemies.tscn @@ -24,9 +24,6 @@ use_collision = true size = Vector3(1, 17.5, 9.5) material = ExtResource("3_1qo78") -[node name="Player" parent="." index="7" unique_id=1309399929] -transform = Transform3D(0.99999994, 0, 0, 0, 1, 0, 0, 0, 0.99999994, 3, 0, 0) - [node name="GroundedSpawner" parent="." index="8" unique_id=580981173 node_paths=PackedStringArray("Target") instance=ExtResource("4_jaqjx")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.5, 1, -42.5) EnemyToSpawn = ExtResource("5_iq67o") @@ -35,6 +32,7 @@ HealthInputs = ExtResource("7_ucbss") DamageInputs = ExtResource("8_2brdd") Target = NodePath("../Player") SpawnInterval = 5.0 +IsActiveOnStart = false [node name="GroundedSpawner2" parent="." index="9" unique_id=1026317919 node_paths=PackedStringArray("Target") instance=ExtResource("4_jaqjx")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 46.5, 11.5, -34.5) @@ -44,6 +42,7 @@ HealthInputs = ExtResource("7_ucbss") DamageInputs = ExtResource("8_2brdd") Target = NodePath("../Player") SpawnInterval = 5.0 +IsActiveOnStart = false [node name="GroundedSpawner3" parent="." index="10" unique_id=241829575 node_paths=PackedStringArray("Target") instance=ExtResource("4_jaqjx")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 44.5, 0, -3) @@ -53,6 +52,7 @@ HealthInputs = ExtResource("7_ucbss") DamageInputs = ExtResource("8_2brdd") Target = NodePath("../Player") SpawnInterval = 5.0 +IsActiveOnStart = false [node name="FlyingSpawner" parent="." index="11" unique_id=962840208 node_paths=PackedStringArray("Target") instance=ExtResource("4_jaqjx")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 16.5, 19, -19.5) @@ -62,6 +62,7 @@ HealthInputs = ExtResource("11_5jlg7") DamageInputs = ExtResource("12_pjgox") Target = NodePath("../Player") SpawnInterval = 5.0 +IsActiveOnStart = false [node name="FlyingSpawner2" parent="." index="12" unique_id=365997644 node_paths=PackedStringArray("Target") instance=ExtResource("4_jaqjx")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 45.5, 25.5, -42.5) @@ -71,6 +72,7 @@ HealthInputs = ExtResource("11_5jlg7") DamageInputs = ExtResource("12_pjgox") Target = NodePath("../Player") SpawnInterval = 5.0 +IsActiveOnStart = false [node name="Targets" type="Node3D" parent="." index="13" unique_id=1620747784] @@ -103,3 +105,6 @@ transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 27, 13.5, -9) [node name="FixedDashthroughTarget3" parent="Targets" index="9" unique_id=1106453232 instance=ExtResource("13_iq67o")] transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 43, 6, -8.5) + +[node name="Player" parent="." index="14" unique_id=1309399929] +transform = Transform3D(0.99999994, 0, 0, 0, 1, 0, 0, 0, 0.99999994, 3, 0, 0) diff --git a/maps/levels/tuto_sword_parry.tscn b/maps/levels/tuto_sword_parry.tscn index 3c296475..a36ee767 100644 --- a/maps/levels/tuto_sword_parry.tscn +++ b/maps/levels/tuto_sword_parry.tscn @@ -61,16 +61,13 @@ size = Vector3(5, 2.25, 3.75) size = Vector3(5.5, 4.5, 2) [sub_resource type="BoxShape3D" id="BoxShape3D_prjj8"] -size = Vector3(2, 3.25, 1.25) +size = Vector3(2, 3.25, 5.25) [sub_resource type="BoxShape3D" id="BoxShape3D_1opdv"] size = Vector3(8.25, 3.25, 2.75) [node name="Main" unique_id=955321579 instance=ExtResource("1_8n6bu")] -[node name="Player" parent="." index="6" unique_id=1309399929] -transform = Transform3D(0.99999994, 0, 0, 0, 1, 0, 0, 0, 0.99999994, -0.5, 0, 0) - [node name="Playground" type="Node3D" parent="." index="7" unique_id=2099606598] transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, -8.25, 13, 58.5) @@ -429,7 +426,7 @@ second_input_texture = ExtResource("13_nwk5u") tuto_text = "throw weapon" [node name="CollisionShape3D" type="CollisionShape3D" parent="Tutorial/Triggers/TutoTrigger7" index="1" unique_id=1932556219] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.875, 3.75) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.875, 4) shape = SubResource("BoxShape3D_prjj8") [node name="TutoTrigger8" parent="Tutorial/Triggers" index="7" unique_id=36196488 instance=ExtResource("10_dkfm7")] @@ -620,9 +617,9 @@ size = Vector3(5, 1, 11) material = ExtResource("3_wsc2c") [node name="CSGBox3D141" type="CSGBox3D" parent="Tutorial/DashWithMantle" index="29" unique_id=1207463075] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 21.487345, 68.625) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 21.487345, 70.125) use_collision = true -size = Vector3(5, 1, 3.25) +size = Vector3(5, 1, 6.25) material = ExtResource("3_wsc2c") [node name="CSGBox3D121" type="CSGBox3D" parent="Tutorial/DashWithMantle" index="30" unique_id=302433684] @@ -721,26 +718,38 @@ use_collision = true size = Vector3(9, 5.5, 2) material = ExtResource("3_wsc2c") -[node name="CSGBox3D118" type="CSGBox3D" parent="Tutorial" index="20" unique_id=1950738925] +[node name="CSGBox3D123" type="CSGBox3D" parent="Tutorial" index="20" unique_id=765166179] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.625, 6) +use_collision = true +size = Vector3(9, 2.25, 2) +material = ExtResource("3_wsc2c") + +[node name="CSGBox3D118" type="CSGBox3D" parent="Tutorial" index="21" unique_id=1950738925] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, -7.75, -10) use_collision = true size = Vector3(9, 2.5, 2) material = ExtResource("3_wsc2c") -[node name="CSGBox3D120" type="CSGBox3D" parent="Tutorial" index="21" unique_id=1024529143] +[node name="CSGBox3D120" type="CSGBox3D" parent="Tutorial" index="22" unique_id=1024529143] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, -21.75, -11.75) use_collision = true size = Vector3(9, 25.5, 37.5) material = ExtResource("3_wsc2c") -[node name="CSGBox3D122" type="CSGBox3D" parent="Tutorial" index="22" unique_id=1261455320] +[node name="CSGBox3D122" type="CSGBox3D" parent="Tutorial" index="23" unique_id=1261455320] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -15.5, 16.5, -28.5) use_collision = true size = Vector3(3, 1, 4) material = ExtResource("3_wsc2c") -[node name="CSGBox3D143" type="CSGBox3D" parent="Tutorial" index="23" unique_id=1090375546] +[node name="CSGBox3D143" type="CSGBox3D" parent="Tutorial" index="24" unique_id=1090375546] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5, 27.625, 34) use_collision = true size = Vector3(2, 3.25, 1) material = ExtResource("3_wsc2c") + +[node name="Player" parent="." index="9" unique_id=1309399929] +transform = Transform3D(0.99999994, 0, 0, 0, 1, 0, 0, 0, 0.99999994, -0.5, 0, 0) + +[node name="PlayerFellRespawn" parent="." index="10" unique_id=479136076] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 1.5, 0) diff --git a/scenes/player_controller/scripts/PlayerController.cs b/scenes/player_controller/scripts/PlayerController.cs index 25ede056..1ae5c800 100644 --- a/scenes/player_controller/scripts/PlayerController.cs +++ b/scenes/player_controller/scripts/PlayerController.cs @@ -869,16 +869,16 @@ public partial class PlayerController : CharacterBody3D, _playerState.SendEvent("grounded"); if (IsTryingToMantle()) _playerState.SendEvent("mantle"); - + if (!WallHugSystem.IsWallHugging()) { _isWallJumpAvailable = true; // reset wall jump if we left the wall return; } - // Going upwards, we stay simply airborne - if (Velocity.AngleTo(Vector3.Up) < Math.PI / 4) - return; + // // Going upwards, we stay simply airborne + // if (Velocity.AngleTo(Vector3.Up) < Math.PI / 4) + // return; // Should we start a wall run if (ShouldStartWallRun()) @@ -1188,8 +1188,8 @@ public partial class PlayerController : CharacterBody3D, } public void OnWallDetected() { - if (!_onWall.Active) - return; + // if (!_onWall.Active) + // return; var newWallNormal = WallHugSystem.WallHugNormal.UnwrapOr(Vector3.Up); if (newWallNormal.AngleTo(_wallHugStartNormal) > Mathf.Pi/4) return; @@ -1223,11 +1223,11 @@ public partial class PlayerController : CharacterBody3D, // _canDashAirborne = true; WallHug(delta); - if (ShouldStartWallRun()) - { - _playerState.SendEvent("wall_run"); - return; - } + // if (ShouldStartWallRun()) + // { + // _playerState.SendEvent("wall_run"); + // return; + // } if (isOnFloorCustom()) _playerState.SendEvent("grounded"); if (!WallHugSystem.IsWallHugging() || !IsInputTowardsWall(_wallHugStartNormal)) @@ -1263,7 +1263,7 @@ public partial class PlayerController : CharacterBody3D, // Adapt vertical speed var verticalSpeed = Velocity.Y - WallRunAltitudeLossSpeed * delta; Velocity = finalHVel + Vector3.Up*verticalSpeed; - // Velocity *= 0.999f; + Velocity *= 0.999f; _currentWallContactPoint = WallHugSystem.WallHugLocation.UnwrapOr(Vector3.Zero); @@ -1273,7 +1273,7 @@ public partial class PlayerController : CharacterBody3D, _playerState.SendEvent("grounded"); if (!WallHugSystem.IsWallHugging()) _playerState.SendEvent("start_falling"); - if (Velocity.Length() < WallRunSpeedThreshold / 2f) + if (!CanKeepWallRun()) _playerState.SendEvent("wall_hug"); } @@ -1286,27 +1286,78 @@ public partial class PlayerController : CharacterBody3D, public bool ShouldStartWallRun() { - var wallNormal = WallHugSystem.WallHugNormal.UnwrapOr(Vector3.Zero); - var isIndeedWall = wallNormal.Y < 0.1; - var isThereInput = GetMoveInput().Length() > Mathf.Epsilon; - var hvel = new Vector3(Velocity.X, 0, Velocity.Z); - var hvelProjected = Velocity.Slide(_wallHugStartNormal); - var haveEnoughSpeed = hvelProjected.Length() > WallRunSpeedThreshold; - var isCoplanarEnough = Math.Abs(Velocity.Dot(wallNormal)) < 0.3; - var isGoingDownwards = Velocity.Dot(Vector3.Down) > 0.9; - var isLookingInDirectionOfRun = true; // hvelProjected.Dot(-HeadSystem.GetForwardHorizontalVector()) > 0.5; - var shouldStart = haveEnoughSpeed && isThereInput && !isGoingDownwards && isIndeedWall && isCoplanarEnough && isLookingInDirectionOfRun; - - var debugText = "--------------\n"; - debugText += shouldStart ? "WALL RUN STARTED\n" : "NO WALL RUN\n"; - debugText += $"Enough speed? {haveEnoughSpeed}\n"; - debugText += $"Coplanar enough? {isCoplanarEnough}\n"; - debugText += $"Going downwards? {isGoingDownwards}\n"; - debugText += $"Is looking in direction of run? {isLookingInDirectionOfRun}\n"; - debugText += "--------------\n"; - GD.Print(debugText); + if (_wallHugStartNormal.Length() < Mathf.Epsilon) + { + // GD.Print("No wall normal"); + return false; + } - return shouldStart; + var isIndeedWall = _wallHugStartNormal.Y < 0.1; + if (!isIndeedWall) + { + // GD.Print("Not a wall"); + return false; + } + + var isThereInput = GetMoveInput().Length() > Mathf.Epsilon; + if (!isThereInput) + { + // GD.Print("Not a wall"); + return false; + } + + var canUseVelocity = Velocity.Length() > WallRunSpeedThreshold; + if (!canUseVelocity) + { + // GD.Print("Not enough speed"); + return false; + } + + var hvel = new Vector3(Velocity.X, 0, Velocity.Z); + var hvelProjected = hvel.Slide(_wallHugStartNormal); + var haveEnoughSpeed = hvelProjected.Length() > WallRunSpeedThreshold; + if (!haveEnoughSpeed) + { + // GD.Print("Not enough projected speed"); + return false; + } + + var isCoplanarEnough = Math.Abs(Velocity.Normalized().Dot(_wallHugStartNormal)) < 0.5; + if (!isCoplanarEnough) + { + // GD.Print("Not coplanar enough"); + return false; + } + + var isGoingDownwards = Velocity.Normalized().Dot(Vector3.Down) > 0.5; + if (isGoingDownwards) + { + // GD.Print("Going down"); + return false; + } + + var isLookingInDirectionOfRun = hvelProjected.Normalized().Dot(-HeadSystem.GetForwardHorizontalVector()) > 0.5; + if (!isLookingInDirectionOfRun) + { + // GD.Print("Not looking in direction of run"); + return false; + } + + return true; + } + + public bool CanKeepWallRun() + { + var isThereInput = GetMoveInput().Length() > Mathf.Epsilon; + if (!isThereInput) return false; + + var isInputForward = GetInputLocalHDirection().Z < 0; + if (!isInputForward) return false; + + var haveEnoughSpeed = Velocity.Length() > WallRunSpeedThreshold; + if (!haveEnoughSpeed) return false; + + return true; } public void WallHug(float delta)