From 30b4d1a2ebf02436a3c2a98e0d73ccf1df775edb Mon Sep 17 00:00:00 2001 From: Minimata Date: Tue, 13 Jan 2026 14:22:26 +0100 Subject: [PATCH] jumping from slides and some improvement on air gliding --- player_controller/PlayerController.tscn | 85 +++++++++++++++---- player_controller/Scripts/PlayerController.cs | 84 +++++++++++++++--- 2 files changed, 140 insertions(+), 29 deletions(-) diff --git a/player_controller/PlayerController.tscn b/player_controller/PlayerController.tscn index 8fa39ae9..c513ea18 100644 --- a/player_controller/PlayerController.tscn +++ b/player_controller/PlayerController.tscn @@ -89,9 +89,13 @@ SimpleDashTime = 0.2 AimedDashTime = 0.2 PostDashSpeed = 30.0 SlamSpeed = 80.0 -AccelerationGroundSlide = 0.2 +GroundSlideJumpMultiplier = 0.1 +GroundSlideJumpSpeedFactor = 0.1 AirGlideVSpeed = 4.0 -AccelerationAirGlide = 0.2 +AccelerationAirGlide = 0.4 +AirGlideVerticalAcceleration = 8.0 +AirGlideJumpMultiplier = 0.1 +AirGlideJumpSpeedFactor = 0.05 WallHugGravityLesseningFactor = 15.0 WallHugDownwardMaxSpeed = 4.0 WallHugHorizontalDeceleration = 1.0 @@ -540,12 +544,6 @@ delay_in_seconds = "0.0" script = ExtResource("26_infe6") initial_state = NodePath("SimpleJump") -[node name="OnSlide" type="Node" parent="StateChart/Root/Movement/Jump"] -script = ExtResource("28_n7qhm") -to = NodePath("../../Sliding/AirGlide") -event = &"slide" -delay_in_seconds = "0.0" - [node name="OnMantle" type="Node" parent="StateChart/Root/Movement/Jump"] script = ExtResource("28_n7qhm") to = NodePath("../../Mantling") @@ -561,6 +559,12 @@ to = NodePath("../../../Airborne/DoubleJumpEnabled") event = &"jump_ended" delay_in_seconds = "0.0" +[node name="OnSlide" type="Node" parent="StateChart/Root/Movement/Jump/SimpleJump"] +script = ExtResource("28_n7qhm") +to = NodePath("../../../Sliding/AirGlideDoubleJumpEnabled") +event = &"slide" +delay_in_seconds = "0.0" + [node name="DoubleJump" type="Node" parent="StateChart/Root/Movement/Jump"] script = ExtResource("27_34snm") @@ -570,6 +574,12 @@ to = NodePath("../../../Airborne/Falling") event = &"jump_ended" delay_in_seconds = "0.0" +[node name="OnSlide" type="Node" parent="StateChart/Root/Movement/Jump/DoubleJump"] +script = ExtResource("28_n7qhm") +to = NodePath("../../../Sliding/AirGlide") +event = &"slide" +delay_in_seconds = "0.0" + [node name="Dashing" type="Node" parent="StateChart/Root/Movement"] script = ExtResource("26_infe6") initial_state = NodePath("Dash") @@ -602,6 +612,12 @@ script = ExtResource("27_34snm") script = ExtResource("26_infe6") initial_state = NodePath("GroundSlide") +[node name="OnDash" type="Node" parent="StateChart/Root/Movement/Sliding"] +script = ExtResource("28_n7qhm") +to = NodePath("../../Dashing/Dash") +event = &"actually_no_dash" +delay_in_seconds = "0.0" + [node name="OnMantle" type="Node" parent="StateChart/Root/Movement/Sliding"] script = ExtResource("28_n7qhm") to = NodePath("../../Mantling") @@ -619,10 +635,37 @@ delay_in_seconds = "0.0" [node name="OnAirborne" type="Node" parent="StateChart/Root/Movement/Sliding/GroundSlide"] script = ExtResource("28_n7qhm") -to = NodePath("../../AirGlide") +to = NodePath("../../AirGlideDoubleJumpEnabled") event = &"start_falling" delay_in_seconds = "0.0" +[node name="OnJump" type="Node" parent="StateChart/Root/Movement/Sliding/GroundSlide"] +script = ExtResource("28_n7qhm") +to = NodePath("../../../Jump/SimpleJump") +event = &"jump" +delay_in_seconds = "0.0" + +[node name="AirGlideDoubleJumpEnabled" type="Node" parent="StateChart/Root/Movement/Sliding"] +script = ExtResource("27_34snm") + +[node name="OnSlideReleased" type="Node" parent="StateChart/Root/Movement/Sliding/AirGlideDoubleJumpEnabled"] +script = ExtResource("28_n7qhm") +to = NodePath("../../../Airborne/Reset") +event = &"slide_released" +delay_in_seconds = "0.0" + +[node name="OnGrounded" type="Node" parent="StateChart/Root/Movement/Sliding/AirGlideDoubleJumpEnabled"] +script = ExtResource("28_n7qhm") +to = NodePath("../../GroundSlide") +event = &"grounded" +delay_in_seconds = "0.0" + +[node name="OnJump" type="Node" parent="StateChart/Root/Movement/Sliding/AirGlideDoubleJumpEnabled"] +script = ExtResource("28_n7qhm") +to = NodePath("../../../Jump/DoubleJump") +event = &"jump" +delay_in_seconds = "0.0" + [node name="AirGlide" type="Node" parent="StateChart/Root/Movement/Sliding"] script = ExtResource("27_34snm") @@ -664,12 +707,6 @@ to = NodePath("../../Grounded") event = &"grounded" delay_in_seconds = "0.0" -[node name="OnSlide" type="Node" parent="StateChart/Root/Movement/Airborne"] -script = ExtResource("28_n7qhm") -to = NodePath("../../Sliding/AirGlide") -event = &"slide" -delay_in_seconds = "0.0" - [node name="OnSlam" type="Node" parent="StateChart/Root/Movement/Airborne"] script = ExtResource("28_n7qhm") to = NodePath("../../Slamming") @@ -679,6 +716,12 @@ delay_in_seconds = "0.0" [node name="CoyoteEnabled" type="Node" parent="StateChart/Root/Movement/Airborne"] script = ExtResource("27_34snm") +[node name="OnSlide" type="Node" parent="StateChart/Root/Movement/Airborne/CoyoteEnabled"] +script = ExtResource("28_n7qhm") +to = NodePath("../../../Sliding/AirGlideDoubleJumpEnabled") +event = &"slide" +delay_in_seconds = "0.0" + [node name="OnJump" type="Node" parent="StateChart/Root/Movement/Airborne/CoyoteEnabled"] script = ExtResource("28_n7qhm") to = NodePath("../../../Jump/SimpleJump") @@ -694,6 +737,12 @@ delay_in_seconds = "0.0" [node name="DoubleJumpEnabled" type="Node" parent="StateChart/Root/Movement/Airborne"] script = ExtResource("27_34snm") +[node name="OnSlide" type="Node" parent="StateChart/Root/Movement/Airborne/DoubleJumpEnabled"] +script = ExtResource("28_n7qhm") +to = NodePath("../../../Sliding/AirGlideDoubleJumpEnabled") +event = &"slide" +delay_in_seconds = "0.0" + [node name="OnWallHug" type="Node" parent="StateChart/Root/Movement/Airborne/DoubleJumpEnabled"] script = ExtResource("28_n7qhm") to = NodePath("../../../OnWall/Hugging") @@ -709,6 +758,12 @@ delay_in_seconds = "0.0" [node name="Falling" type="Node" parent="StateChart/Root/Movement/Airborne"] script = ExtResource("27_34snm") +[node name="OnSlide" type="Node" parent="StateChart/Root/Movement/Airborne/Falling"] +script = ExtResource("28_n7qhm") +to = NodePath("../../../Sliding/AirGlide") +event = &"slide" +delay_in_seconds = "0.0" + [node name="OnWallHug" type="Node" parent="StateChart/Root/Movement/Airborne/Falling"] script = ExtResource("28_n7qhm") to = NodePath("../../../OnWall/Hugging") diff --git a/player_controller/Scripts/PlayerController.cs b/player_controller/Scripts/PlayerController.cs index a491decb..a5549052 100644 --- a/player_controller/Scripts/PlayerController.cs +++ b/player_controller/Scripts/PlayerController.cs @@ -142,14 +142,27 @@ public partial class PlayerController : CharacterBody3D public float AccelerationGroundSlide = 1.0f; [Export(PropertyHint.Range, "0,1,0.01,or_greater")] public float DecelerationGroundSlide = 0.1f; + [Export(PropertyHint.Range, "0,10,0.1,or_greater")] + public float GroundSlideJumpMultiplier = 1.0f; + [Export(PropertyHint.Range, "0,1,0.01,or_greater")] + public float GroundSlideJumpSpeedFactor; - [ExportSubgroup("Air glide")] + [ExportSubgroup("Air glide")] + [Export] + public bool AllowForVelocityRedirection = true; + [Export(PropertyHint.Range, "0,10,0.01,or_greater")] public float AirGlideVSpeed { get; set; } = 1.0f; [Export(PropertyHint.Range, "0,1,0.01,or_greater")] public float AccelerationAirGlide = 1.0f; [Export(PropertyHint.Range, "0,1,0.01,or_greater")] public float DecelerationAirGlide = 0.1f; + [Export(PropertyHint.Range, "0,10,0.01,or_greater")] + public float AirGlideVerticalAcceleration = 1.0f; + [Export(PropertyHint.Range, "0,10,0.1,or_greater")] + public float AirGlideJumpMultiplier = 1.0f; + [Export(PropertyHint.Range, "0,1,0.01,or_greater")] + public float AirGlideJumpSpeedFactor; // Wall hug [ExportGroup("Wall hug")] @@ -260,6 +273,7 @@ public partial class PlayerController : CharacterBody3D private StateChartState _sliding; private StateChartState _groundSliding; private StateChartState _airGliding; + private StateChartState _airGlidingDoubleJump; private StateChartState _slamming; private StateChartState _onWall; private StateChartState _onWallHugging; @@ -269,6 +283,9 @@ public partial class PlayerController : CharacterBody3D private Transition _onJumpFromWall; private Transition _onJumpFromWallFalling; private Transition _onLeaveWallFromRun; + + private Transition _onGroundSlideJump; + private Transition _onAirGlideDoubleJump; public override void _Ready() { @@ -326,11 +343,14 @@ public partial class PlayerController : CharacterBody3D _aiming = StateChartState.Of(GetNode("StateChart/Root/Aim/On")); _simpleDash = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing/Dash")); _aimedDash = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing/AimedDash")); + _slamming = StateChartState.Of(GetNode("StateChart/Root/Movement/Slamming")); _sliding = StateChartState.Of(GetNode("StateChart/Root/Movement/Sliding")); _groundSliding = StateChartState.Of(GetNode("StateChart/Root/Movement/Sliding/GroundSlide")); _airGliding = StateChartState.Of(GetNode("StateChart/Root/Movement/Sliding/AirGlide")); - _slamming = StateChartState.Of(GetNode("StateChart/Root/Movement/Slamming")); + _airGlidingDoubleJump = StateChartState.Of(GetNode("StateChart/Root/Movement/Sliding/AirGlideDoubleJumpEnabled")); + _onGroundSlideJump = Transition.Of(GetNode("StateChart/Root/Movement/Sliding/GroundSlide/OnJump")); + _onAirGlideDoubleJump = Transition.Of(GetNode("StateChart/Root/Movement/Sliding/AirGlideDoubleJumpEnabled/OnJump")); // _actionHanging = StateChartState.Of(GetNode("StateChart/Root/Actions/Hanging")); _powerExpired = StateChartState.Of(GetNode("StateChart/Root/PowerReserve/Expired")); @@ -423,6 +443,10 @@ public partial class PlayerController : CharacterBody3D _sliding.StateExited += SlideEnded; _groundSliding.StatePhysicsProcessing += HandleGroundSlide; _airGliding.StatePhysicsProcessing += HandleAirGlide; + _airGlidingDoubleJump.StatePhysicsProcessing += HandleAirGlide; + + _onGroundSlideJump.Taken += JumpFromGroundSlide; + _onAirGlideDoubleJump.Taken += JumpFromAirGlide; _slamming.StateEntered += SlamStarted; _slamming.StateExited += SlamEnded; @@ -1063,11 +1087,13 @@ public partial class PlayerController : CharacterBody3D } _playerState.SendEvent("jump"); } - + + private float _jumpStrengthMultiplier = 1.0f; public void OnJumpStarted(float verticalVelocity) { _framesSinceJumpAtApex = 0; - SetVerticalVelocity(verticalVelocity); + SetVerticalVelocity(verticalVelocity*_jumpStrengthMultiplier); + _jumpStrengthMultiplier = 1.0f; } public void OnSimpleJumpStarted() { @@ -1201,7 +1227,7 @@ public partial class PlayerController : CharacterBody3D var positionDifference = GlobalPosition - _mantleStartPosition; var directionHorizontal = new Vector3(positionDifference.X, 0, positionDifference.Z); // SimpleDashInDirection(directionHorizontal.Normalized()); - SetVelocity(directionHorizontal.Normalized() * WalkSpeed); + SetVelocity(directionHorizontal.Normalized() * _velocityOnMantleStarted.Length()); } _customMantle = false; @@ -1226,27 +1252,47 @@ public partial class PlayerController : CharacterBody3D } public void SlideOnGround(float delta) { + var currentVelocity = Velocity.Length(); var horizontalVelocity = ComputeHVelocity(delta, AccelerationGroundSlide, DecelerationGroundSlide); - Velocity = new Vector3(horizontalVelocity.X, Velocity.Y, horizontalVelocity.Z); + var newVelocity = new Vector3(horizontalVelocity.X, Velocity.Y, horizontalVelocity.Z); + Velocity = newVelocity.Normalized() * currentVelocity; // prevent from losing momentum } public void HandleGroundSlide(float delta) { + // GD.Print(GetFloorAngle()); + SlideOnGround(delta); if (MantleSystem.IsMantlePossible && IsPlayerInputtingForward()) _playerState.SendEvent("mantle"); if (!isOnFloorCustom()) _playerState.SendEvent("start_falling"); } + public void GlideInAir(float delta) { - var horizontalVelocity = ComputeHVelocity(delta, AccelerationAirGlide, DecelerationAirGlide); - - float verticalSpeed; - if (Velocity.Y < -AirGlideVSpeed) verticalSpeed = -AirGlideVSpeed; - else if (Velocity.Y > 0) verticalSpeed = ComputeVerticalSpeedGravity(delta); - else verticalSpeed = Mathf.Lerp(Velocity.Y, -AirGlideVSpeed, delta); - - Velocity = new Vector3(horizontalVelocity.X, verticalSpeed, horizontalVelocity.Z); + if (AllowForVelocityRedirection) + { + // Preserve overall velocity + // Allows for tragic reorientation of the velocity vector after a fall + // Allows for bunny-hoping-like movement + var currentVelocity = Velocity.Length(); + var horizontalVelocity = ComputeHVelocity(delta, AccelerationAirGlide, DecelerationAirGlide); + var verticalSpeed = Velocity.Y > 0 ? ComputeVerticalSpeedGravity(delta) : Mathf.Lerp(Velocity.Y, -AirGlideVSpeed, delta*AirGlideVerticalAcceleration); + var newVelocity = new Vector3(horizontalVelocity.X, verticalSpeed, horizontalVelocity.Z); + Velocity = newVelocity.Normalized() * currentVelocity; + } + else + { + // Preserve horizontal velocity only + // Allows for mor stable descent when gliding because you don't zoom away after a long fall + // Removes bunny-hoping-like movement by simply holding slide and jump jump jump + var currentHVelocity = new Vector2(Velocity.X, Velocity.Z).Length(); + var horizontalVelocity = ComputeHVelocity(delta, AccelerationAirGlide, DecelerationAirGlide); + var newHVelocity = horizontalVelocity.Normalized() * currentHVelocity; + var verticalSpeed = Velocity.Y > 0 ? ComputeVerticalSpeedGravity(delta) : Mathf.Lerp(Velocity.Y, -AirGlideVSpeed, delta*AirGlideVerticalAcceleration); + var newVelocity = new Vector3(newHVelocity.X, verticalSpeed, newHVelocity.Z); + Velocity = newVelocity; + } } public void HandleAirGlide(float delta) { @@ -1260,6 +1306,16 @@ public partial class PlayerController : CharacterBody3D { _targetSpeed = WalkSpeed; } + + public void JumpFromGroundSlide() + { + _jumpStrengthMultiplier = GroundSlideJumpMultiplier + Velocity.Length()*GroundSlideJumpSpeedFactor; + } + + public void JumpFromAirGlide() + { + _jumpStrengthMultiplier = AirGlideJumpMultiplier + Velocity.Length()*AirGlideJumpSpeedFactor; + } /////////////////////////// // Slam Management ///////