Added ground-like movement (i.e. air control when close to ground) and wall jumping away from the wall is always possible even when facing it

This commit is contained in:
2026-01-12 11:52:35 +01:00
parent 66be7838bb
commit 04054cfeae
3 changed files with 45 additions and 15 deletions

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=48 format=3 uid="uid://bei4nhkf8lwdo"] [gd_scene load_steps=49 format=3 uid="uid://bei4nhkf8lwdo"]
[ext_resource type="Script" uid="uid://bbbrf5ckydfna" path="res://player_controller/Scripts/PlayerController.cs" id="1_poq2x"] [ext_resource type="Script" uid="uid://bbbrf5ckydfna" path="res://player_controller/Scripts/PlayerController.cs" id="1_poq2x"]
[ext_resource type="PackedScene" uid="uid://cf3rrgr1imvv4" path="res://scenes/path/path.tscn" id="2_6lejt"] [ext_resource type="PackedScene" uid="uid://cf3rrgr1imvv4" path="res://scenes/path/path.tscn" id="2_6lejt"]
@@ -57,6 +57,10 @@ top_radius = 0.2
bottom_radius = 0.2 bottom_radius = 0.2
height = 1.0 height = 1.0
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_6lejt"]
radius = 1.0
height = 3.0
[sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_2q0ik"] [sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_2q0ik"]
blend_mode = 1 blend_mode = 1
@@ -179,7 +183,6 @@ target_position = Vector3(0, 1, 0)
[node name="TweenQueueSystem" parent="." instance=ExtResource("22_rpwev")] [node name="TweenQueueSystem" parent="." instance=ExtResource("22_rpwev")]
[node name="WallHugSystem" type="Node3D" parent="."] [node name="WallHugSystem" type="Node3D" parent="."]
visible = false
script = ExtResource("27_n7qhm") script = ExtResource("27_n7qhm")
[node name="back" type="RayCast3D" parent="WallHugSystem"] [node name="back" type="RayCast3D" parent="WallHugSystem"]
@@ -236,6 +239,11 @@ visible = false
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0, 0, -1) transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0, 0, -1)
mesh = SubResource("CylinderMesh_nodcl") mesh = SubResource("CylinderMesh_nodcl")
[node name="GroundDetector" type="ShapeCast3D" parent="."]
shape = SubResource("CapsuleShape3D_6lejt")
target_position = Vector3(0, -0.5, 0)
collision_mask = 2
[node name="DashCooldown" type="Timer" parent="."] [node name="DashCooldown" type="Timer" parent="."]
wait_time = 0.8 wait_time = 0.8
one_shot = true one_shot = true
@@ -698,12 +706,6 @@ delay_in_seconds = "0.0"
script = ExtResource("26_infe6") script = ExtResource("26_infe6")
initial_state = NodePath("Hugging") initial_state = NodePath("Hugging")
[node name="OnDash" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("28_n7qhm")
to = NodePath("../../Dashing/Dash")
event = &"dash"
delay_in_seconds = "0.0"
[node name="OnGrounded" type="Node" parent="StateChart/Root/Movement/OnWall"] [node name="OnGrounded" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("28_n7qhm") script = ExtResource("28_n7qhm")
to = NodePath("../../Grounded") to = NodePath("../../Grounded")
@@ -746,6 +748,12 @@ delay_in_seconds = "0.0"
[node name="Hugging" type="Node" parent="StateChart/Root/Movement/OnWall"] [node name="Hugging" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("27_34snm") script = ExtResource("27_34snm")
[node name="OnDash" type="Node" parent="StateChart/Root/Movement/OnWall/Hugging"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../Dashing/Dash")
event = &"dash"
delay_in_seconds = "0.0"
[node name="OnJump" type="Node" parent="StateChart/Root/Movement/OnWall/Hugging"] [node name="OnJump" type="Node" parent="StateChart/Root/Movement/OnWall/Hugging"]
script = ExtResource("28_n7qhm") script = ExtResource("28_n7qhm")
to = NodePath("../../../Jump/DoubleJump") to = NodePath("../../../Jump/DoubleJump")
@@ -755,6 +763,12 @@ delay_in_seconds = "0.0"
[node name="Hanging" type="Node" parent="StateChart/Root/Movement/OnWall"] [node name="Hanging" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("27_34snm") script = ExtResource("27_34snm")
[node name="OnDash" type="Node" parent="StateChart/Root/Movement/OnWall/Hanging"]
script = ExtResource("28_n7qhm")
to = NodePath("../../../Dashing/Dash")
event = &"dash"
delay_in_seconds = "0.0"
[node name="OnJump" type="Node" parent="StateChart/Root/Movement/OnWall/Hanging"] [node name="OnJump" type="Node" parent="StateChart/Root/Movement/OnWall/Hanging"]
script = ExtResource("28_n7qhm") script = ExtResource("28_n7qhm")
to = NodePath("../../../Jump/DoubleJump") to = NodePath("../../../Jump/DoubleJump")

View File

@@ -44,6 +44,7 @@ public partial class PlayerController : CharacterBody3D
public MeshInstance3D DashIndicatorMesh; public MeshInstance3D DashIndicatorMesh;
public CylinderMesh DashIndicatorMeshCylinder; public CylinderMesh DashIndicatorMeshCylinder;
public RayCast3D WallRunSnapper; public RayCast3D WallRunSnapper;
public ShapeCast3D GroundDetector;
private bool _movementEnabled = true; private bool _movementEnabled = true;
@@ -296,6 +297,7 @@ public partial class PlayerController : CharacterBody3D
StairsSystem = GetNode<StairsSystem>("StairsSystem"); StairsSystem = GetNode<StairsSystem>("StairsSystem");
WallHugSystem = GetNode<WallHugSystem>("WallHugSystem"); WallHugSystem = GetNode<WallHugSystem>("WallHugSystem");
WallRunSnapper = GetNode<RayCast3D>("%WallRunSnapper"); WallRunSnapper = GetNode<RayCast3D>("%WallRunSnapper");
GroundDetector = GetNode<ShapeCast3D>("GroundDetector");
RayCast3D stairsBelowRayCast3D = GetNode<RayCast3D>("StairsBelowRayCast3D"); RayCast3D stairsBelowRayCast3D = GetNode<RayCast3D>("StairsBelowRayCast3D");
RayCast3D stairsAheadRayCast3D = GetNode<RayCast3D>("StairsAheadRayCast3D"); RayCast3D stairsAheadRayCast3D = GetNode<RayCast3D>("StairsAheadRayCast3D");
_headCollisionDetectors = new RayCast3D[NUM_OF_HEAD_COLLISION_DETECTORS]; _headCollisionDetectors = new RayCast3D[NUM_OF_HEAD_COLLISION_DETECTORS];
@@ -442,6 +444,15 @@ public partial class PlayerController : CharacterBody3D
_onLeaveWallFromRunCoyote.Taken += OnLeaveWallFromRun; _onLeaveWallFromRunCoyote.Taken += OnLeaveWallFromRun;
} }
public void OnGroundDetected(Node3D _)
{
GD.Print("Ground-like");
}
public void OnGroundLost(Node3D _)
{
GD.Print("Ground-less");
}
public void SetAllowedInputsAll() public void SetAllowedInputsAll()
{ {
CurrentlyAllowedInputs = AllowedInputs.All; CurrentlyAllowedInputs = AllowedInputs.All;
@@ -540,7 +551,8 @@ public partial class PlayerController : CharacterBody3D
public void HandleAirborne(float delta) public void HandleAirborne(float delta)
{ {
MoveInAir(delta); var isGroundLike = GroundDetector.GetCollisionResult().Count > 0;
MoveInAir(delta, isGroundLike);
if (isOnFloorCustom()) if (isOnFloorCustom())
_playerState.SendEvent("grounded"); _playerState.SendEvent("grounded");
@@ -627,6 +639,9 @@ public partial class PlayerController : CharacterBody3D
public void HandleWallHugging(float delta) public void HandleWallHugging(float delta)
{ {
_canDash = true;
_canDashAirborne = true;
WallHug(delta); WallHug(delta);
if (isOnFloorCustom()) if (isOnFloorCustom())
_playerState.SendEvent("grounded"); _playerState.SendEvent("grounded");
@@ -642,6 +657,9 @@ public partial class PlayerController : CharacterBody3D
public void HandleWallRunning(float delta) public void HandleWallRunning(float delta)
{ {
_canDash = false;
_canDashAirborne = false;
// Find horizontal velocity projected on the current wall // Find horizontal velocity projected on the current wall
var hvel = new Vector3(Velocity.X, 0, Velocity.Z); var hvel = new Vector3(Velocity.X, 0, Velocity.Z);
var hvelProjected = hvel.Slide(_wallHugStartNormal); var hvelProjected = hvel.Slide(_wallHugStartNormal);
@@ -703,7 +721,6 @@ public partial class PlayerController : CharacterBody3D
return; return;
} }
if (_onWall.Active && !_isWallJumpAvailable && IsFacingWall()) return;
_playerState.SendEvent("jump"); _playerState.SendEvent("jump");
} }
@@ -766,7 +783,7 @@ public partial class PlayerController : CharacterBody3D
public void OnJumpFromWall() public void OnJumpFromWall()
{ {
if (!IsFacingWall()) if (!IsFacingWall() || (!_isWallJumpAvailable && IsFacingWall()))
{ {
ComputeJumpFromWallHSpeed(WallJumpStartVelocity); ComputeJumpFromWallHSpeed(WallJumpStartVelocity);
} }
@@ -1330,9 +1347,9 @@ public partial class PlayerController : CharacterBody3D
Velocity = new Vector3(horizontalVelocity.X, Velocity.Y, horizontalVelocity.Z); Velocity = new Vector3(horizontalVelocity.X, Velocity.Y, horizontalVelocity.Z);
} }
public void MoveInAir(double delta) public void MoveInAir(double delta, bool isGroundLike = false)
{ {
var horizontalVelocity = ComputeHVelocityAir((float) delta); var horizontalVelocity = isGroundLike ? ComputeHVelocityGround((float) delta) : ComputeHVelocityAir((float) delta);
var verticalVelocity = Velocity.Y - (CalculateGravityForce() * (float)delta); var verticalVelocity = Velocity.Y - (CalculateGravityForce() * (float)delta);
Velocity = new Vector3(horizontalVelocity.X, verticalVelocity, horizontalVelocity.Z); Velocity = new Vector3(horizontalVelocity.X, verticalVelocity, horizontalVelocity.Z);
} }
@@ -1471,7 +1488,6 @@ public partial class PlayerController : CharacterBody3D
CameraModifications((float) delta); CameraModifications((float) delta);
HandleStairs((float) delta); HandleStairs((float) delta);
MantleSystem.ProcessMantle(_grounded.Active); MantleSystem.ProcessMantle(_grounded.Active);
if (WeaponSystem.InHandState.Active) if (WeaponSystem.InHandState.Active)
RotateWeaponWithPlayer(); RotateWeaponWithPlayer();

View File

@@ -20,6 +20,6 @@ public partial class Path : Path3D
public void Teardown() public void Teardown()
{ {
QueueFree(); if (!IsQueuedForDeletion()) QueueFree();
} }
} }