From 5087cb58bccf3d049abe3ba81865a86631e48e15 Mon Sep 17 00:00:00 2001 From: Minimata Date: Mon, 18 Aug 2025 14:54:41 +0200 Subject: [PATCH] god dayum wall hugging on point man --- player_controller/PlayerController.tscn | 154 +++++---- player_controller/Scripts/PlayerController.cs | 326 ++++++++++-------- systems/dash/DashSystem.cs | 40 ++- systems/wall_hug/WallHugSystem.cs | 10 + 4 files changed, 305 insertions(+), 225 deletions(-) diff --git a/player_controller/PlayerController.tscn b/player_controller/PlayerController.tscn index 52e290a..965511e 100644 --- a/player_controller/PlayerController.tscn +++ b/player_controller/PlayerController.tscn @@ -55,19 +55,21 @@ AccelerationAir = 2.0 DecelerationAir = 0.1 Weight = 5.0 SimpleJumpStartVelocity = 8.0 -SimpleJumpHangTimeInFrames = 3 +SimpleJumpHangTimeInFrames = 1 SimpleJumpGravityLesseningFactor = 2.5 DoubleJumpStartVelocity = 15.0 -DoubleJumpGravityLesseningFactor = 1.2 +DoubleJumpHangTimeInFrames = 3 +DoubleJumpGravityLesseningFactor = 1.5 MegaJumpStartVelocity = 30.0 -MegaJumpHangTimeInFrames = 15 +MegaJumpHangTimeInFrames = 12 MegaJumpGravityLesseningFactor = 1.2 -JumpFromDashSpeedFactor = 4.0 -WallHugHorizontalDeceleration = 3.0 -MaxJumpBoostAfterDashing = 0.7 +WallJumpStartVelocity = 8.0 +SimpleDashStrength = 15.0 +PoweredDashStrength = 50.0 +WallHugGravityLesseningFactor = 15.0 +WallHugDownwardMaxSpeed = 8.0 +WallHugHorizontalDeceleration = 0.5 MaxNumberOfDashActions = 2 -PerfectlyTimedActionTimer = 0.3 -BasicDashStrength = 15.0 DashTimeDilationCurve = ExtResource("2_2q0ik") [node name="InputController" type="Node3D" parent="."] @@ -181,8 +183,8 @@ transform = Transform3D(1, 0, 0, 0, 0.173648, -0.984808, 0, 0.984808, 0.173648, ThrowForce = 15.0 StraightThrowDuration = 0.05 -[node name="CoyoteTime" type="Timer" parent="."] -wait_time = 0.2 +[node name="DashCooldown" type="Timer" parent="."] +wait_time = 0.5 one_shot = true [node name="PowerCooldown" type="Timer" parent="."] @@ -194,14 +196,6 @@ wait_time = 2.0 one_shot = true ignore_time_scale = true -[node name="TimeAfterDashing" type="Timer" parent="."] -wait_time = 0.3 -one_shot = true - -[node name="EmpowerTimeDownscale" type="Timer" parent="."] -one_shot = true -ignore_time_scale = true - [node name="StateChartDebugger" parent="." instance=ExtResource("24_q5h8a")] offset_left = 1524.0 offset_top = 1.0 @@ -318,25 +312,6 @@ to = NodePath("../../Off") event = &"empower_released" delay_in_seconds = "0.0" -[node name="Actions" type="Node" parent="StateChart/Root"] -script = ExtResource("26_infe6") -initial_state = NodePath("Default") - -[node name="Default" type="Node" parent="StateChart/Root/Actions"] -script = ExtResource("27_34snm") - -[node name="Jumping" type="Node" parent="StateChart/Root/Actions"] -script = ExtResource("27_34snm") - -[node name="Dashing" type="Node" parent="StateChart/Root/Actions"] -script = ExtResource("27_34snm") - -[node name="Hitting" type="Node" parent="StateChart/Root/Actions"] -script = ExtResource("27_34snm") - -[node name="Throwing" type="Node" parent="StateChart/Root/Actions"] -script = ExtResource("27_34snm") - [node name="PowerReserve" type="Node" parent="StateChart/Root"] script = ExtResource("26_infe6") initial_state = NodePath("Full") @@ -416,6 +391,11 @@ script = ExtResource("27_34snm") script = ExtResource("26_infe6") initial_state = NodePath("Grounded") +[node name="Reset" type="Node" parent="StateChart/Root/Movement"] +script = ExtResource("41_ruloh") +deep = true +default_state = NodePath("../Grounded") + [node name="OnFall" type="Node" parent="StateChart/Root/Movement"] script = ExtResource("28_n7qhm") to = NodePath("../Airborne/Falling") @@ -434,22 +414,41 @@ to = NodePath("../OnWall/Hanging") event = &"dash_to_planted" delay_in_seconds = "0.0" -[node name="OnDash" type="Node" parent="StateChart/Root/Movement"] +[node name="OnPoweredDash" type="Node" parent="StateChart/Root/Movement"] script = ExtResource("28_n7qhm") -to = NodePath("../Dashing") -event = &"dash" +to = NodePath("../Dashing/PoweredDash") +event = &"powered_dash" +delay_in_seconds = "0.0" + +[node name="Mantling" type="Node" parent="StateChart/Root/Movement"] +script = ExtResource("27_34snm") + +[node name="OnMantleFinished" type="Node" parent="StateChart/Root/Movement/Mantling"] +script = ExtResource("28_n7qhm") +to = NodePath("../../Grounded") +event = &"grounded" delay_in_seconds = "0.0" [node name="Dashing" type="Node" parent="StateChart/Root/Movement"] -script = ExtResource("27_34snm") +script = ExtResource("26_infe6") +initial_state = NodePath("Dash") [node name="OnDashEnded" type="Node" parent="StateChart/Root/Movement/Dashing"] script = ExtResource("28_n7qhm") to = NodePath("../../Airborne/Reset") -event = &"dash_ended" +event = &"dash_finished" delay_in_seconds = "0.0" -[node name="Mantling" type="Node" parent="StateChart/Root/Movement"] +[node name="OnMantle" type="Node" parent="StateChart/Root/Movement/Dashing"] +script = ExtResource("28_n7qhm") +to = NodePath("../../Mantling") +event = &"mantle" +delay_in_seconds = "0.0" + +[node name="Dash" type="Node" parent="StateChart/Root/Movement/Dashing"] +script = ExtResource("27_34snm") + +[node name="PoweredDash" type="Node" parent="StateChart/Root/Movement/Dashing"] script = ExtResource("27_34snm") [node name="Jump" type="Node" parent="StateChart/Root/Movement"] @@ -498,6 +497,12 @@ delay_in_seconds = "0.0" [node name="Grounded" type="Node" parent="StateChart/Root/Movement"] script = ExtResource("27_34snm") +[node name="OnDash" type="Node" parent="StateChart/Root/Movement/Grounded"] +script = ExtResource("28_n7qhm") +to = NodePath("../../Dashing/Dash") +event = &"dash" +delay_in_seconds = "0.0" + [node name="OnJump" type="Node" parent="StateChart/Root/Movement/Grounded"] script = ExtResource("28_n7qhm") to = NodePath("../../Jump/SimpleJump") @@ -524,10 +529,16 @@ initial_state = NodePath("CoyoteEnabled") script = ExtResource("41_ruloh") default_state = NodePath("../CoyoteEnabled") -[node name="OnMegajump" type="Node" parent="StateChart/Root/Movement/Airborne"] +[node name="OnWallHug" type="Node" parent="StateChart/Root/Movement/Airborne"] script = ExtResource("28_n7qhm") -to = NodePath("../../Jump/MegaJump") -event = &"megajump" +to = NodePath("../../OnWall/Hugging") +event = &"wall_hug" +delay_in_seconds = "0.0" + +[node name="OnDash" type="Node" parent="StateChart/Root/Movement/Airborne"] +script = ExtResource("28_n7qhm") +to = NodePath("../../Dashing/Dash") +event = &"dash" delay_in_seconds = "0.0" [node name="OnGrounded" type="Node" parent="StateChart/Root/Movement/Airborne"] @@ -536,27 +547,21 @@ to = NodePath("../../Grounded") event = &"grounded" delay_in_seconds = "0.0" -[node name="OnWallHug" type="Node" parent="StateChart/Root/Movement/Airborne"] -script = ExtResource("28_n7qhm") -to = NodePath("../../OnWall/Hugging") -event = &"wall_hug" -delay_in_seconds = "0.0" - [node name="CoyoteEnabled" type="Node" parent="StateChart/Root/Movement/Airborne"] script = ExtResource("27_34snm") +[node name="OnMegajump" type="Node" parent="StateChart/Root/Movement/Airborne/CoyoteEnabled"] +script = ExtResource("28_n7qhm") +to = NodePath("../../../Jump/MegaJump") +event = &"megajump" +delay_in_seconds = "0.0" + [node name="OnJump" type="Node" parent="StateChart/Root/Movement/Airborne/CoyoteEnabled"] script = ExtResource("28_n7qhm") to = NodePath("../../../Jump/SimpleJump") event = &"jump" delay_in_seconds = "0.0" -[node name="OnMegajump" type="Node" parent="StateChart/Root/Movement/Airborne/CoyoteEnabled"] -script = ExtResource("28_n7qhm") -to = NodePath("../../Falling") -event = &"megajump" -delay_in_seconds = "0.0" - [node name="OnExpiration" type="Node" parent="StateChart/Root/Movement/Airborne/CoyoteEnabled"] script = ExtResource("28_n7qhm") to = NodePath("../../DoubleJumpEnabled") @@ -566,18 +571,18 @@ delay_in_seconds = "0.0" [node name="DoubleJumpEnabled" type="Node" parent="StateChart/Root/Movement/Airborne"] script = ExtResource("27_34snm") +[node name="OnMegajump" type="Node" parent="StateChart/Root/Movement/Airborne/DoubleJumpEnabled"] +script = ExtResource("28_n7qhm") +to = NodePath("../../../Jump/MegaJump") +event = &"megajump" +delay_in_seconds = "0.0" + [node name="OnJump" type="Node" parent="StateChart/Root/Movement/Airborne/DoubleJumpEnabled"] script = ExtResource("28_n7qhm") to = NodePath("../../../Jump/DoubleJump") event = &"jump" delay_in_seconds = "0.0" -[node name="OnDash" type="Node" parent="StateChart/Root/Movement/Airborne/DoubleJumpEnabled"] -script = ExtResource("28_n7qhm") -to = NodePath("../../Falling") -event = &"dash" -delay_in_seconds = "0.0" - [node name="Falling" type="Node" parent="StateChart/Root/Movement/Airborne"] script = ExtResource("27_34snm") @@ -591,12 +596,24 @@ delay_in_seconds = "0.0" script = ExtResource("26_infe6") initial_state = NodePath("Hugging") +[node name="OnGrounded" type="Node" parent="StateChart/Root/Movement/OnWall"] +script = ExtResource("28_n7qhm") +to = NodePath("../../Grounded") +event = &"grounded" +delay_in_seconds = "0.0" + [node name="OnJump" type="Node" parent="StateChart/Root/Movement/OnWall"] script = ExtResource("28_n7qhm") -to = NodePath("../../Airborne/DoubleJumpEnabled") +to = NodePath("../../Jump/DoubleJump") event = &"jump" delay_in_seconds = "0.0" +[node name="OnMegajump" type="Node" parent="StateChart/Root/Movement/OnWall"] +script = ExtResource("28_n7qhm") +to = NodePath("../../Jump/MegaJump") +event = &"megajump" +delay_in_seconds = "0.0" + [node name="HugCanceled" type="Node" parent="StateChart/Root/Movement/OnWall"] script = ExtResource("27_34snm") @@ -609,6 +626,12 @@ delay_in_seconds = "0.0" [node name="Hugging" type="Node" parent="StateChart/Root/Movement/OnWall"] script = ExtResource("27_34snm") +[node name="OnGrounded" type="Node" parent="StateChart/Root/Movement/OnWall/Hugging"] +script = ExtResource("28_n7qhm") +to = NodePath("../../../Grounded") +event = &"grounded" +delay_in_seconds = "0.0" + [node name="OnLeaveWall" type="Node" parent="StateChart/Root/Movement/OnWall/Hugging"] script = ExtResource("28_n7qhm") to = NodePath("../../../Airborne/CoyoteEnabled") @@ -645,3 +668,4 @@ delay_in_seconds = "0.0" [connection signal="input_rotate_floorplane" from="InputController" to="." method="OnInputRotateFloorplane"] [connection signal="input_rotate_y" from="InputController" to="." method="OnInputRotateY"] [connection signal="input_throw" from="InputController" to="." method="OnInputThrowPressed"] +[connection signal="WallDetected" from="WallHugSystem" to="." method="OnWallDetected"] diff --git a/player_controller/Scripts/PlayerController.cs b/player_controller/Scripts/PlayerController.cs index cc4a446..020aa8b 100644 --- a/player_controller/Scripts/PlayerController.cs +++ b/player_controller/Scripts/PlayerController.cs @@ -1,6 +1,7 @@ using System; using Godot; using GodotStateCharts; +using Movementtests.addons.godot_state_charts.csharp; using Movementtests.systems; using Movementtests.player_controller.Scripts; using RustyOptions; @@ -49,11 +50,9 @@ public partial class PlayerController : CharacterBody3D private float _inputRotateFloorplane; // Timers - private Timer _coyoteTimer; private Timer _timeScaleAimInAirTimer; - private Timer _timeAfterDashingTimer; + private Timer _simpleDashCooldownTimer; private Timer _powerCooldownTimer; - private Timer _empowerTimeDownscale; [ExportCategory("Movement")] [ExportGroup("Ground")] @@ -72,7 +71,9 @@ public partial class PlayerController : CharacterBody3D public float Weight { get; set; } = 3.0f; // Jump - [ExportGroup("Jump")] + [ExportGroup("Jump")] + [Export(PropertyHint.Range, "0,1,0.01")] + public float CoyoteTime { get; set; } = 0.2f; // Simple jump [ExportSubgroup("Simple jump")] @@ -103,45 +104,48 @@ public partial class PlayerController : CharacterBody3D [Export(PropertyHint.Range, "1,10,0.1,or_greater")] public float MegaJumpGravityLesseningFactor { get; set; } = 3f; - // Other jump - [ExportSubgroup("Other jump")] - [Export(PropertyHint.Range, "0,2,0.01,or_greater")] - public float StartVelocity { get; set; } = 1.0f; - [Export(PropertyHint.Range, "0.1,10,0.1,or_greater")] - public float DoubleJumpSpeedFactor { get; set; } = 2f; - [Export(PropertyHint.Range, "0.1,10,0.1,or_greater")] - public float JumpFromDashSpeedFactor { get; set; } = 2f; - [Export(PropertyHint.Range, "0.1,10,0.1,or_greater")] - public float JumpFromWallSpeedFactor { get; set; } = 2f; - [ExportGroup("WallHug")] - [Export(PropertyHint.Range, "0.1,10,0.1,or_greater")] - public float WallHugDownwardSpeed { get; set; } = 2f; + // Wall jump + [ExportSubgroup("Wall jump")] + [Export(PropertyHint.Range, "0,100,1,or_greater")] + public float WallJumpStartVelocity { get; set; } = 10.0f; + [Export(PropertyHint.Range, "0,100,1,or_greater")] + public float WallMegajumpStartVelocity { get; set; } = 20.0f; + + // Dash + [ExportGroup("Dash")] + // Simple dash + [ExportSubgroup("Simple")] + [Export(PropertyHint.Range, "0,50,0.1")] + public float SimpleDashStrength { get; set; } = 10f; + // Powered Dash + [ExportSubgroup("Powered")] + [Export(PropertyHint.Range, "0,1,0.01,or_greater")] + public float PoweredDashTime { get; set; } = 0.3f; + [Export(PropertyHint.Range, "0,100,0.1")] + public float PoweredDashStrength { get; set; } = 10f; + + // Wall hug + [ExportGroup("Wall hug")] + [Export(PropertyHint.Range, "0,50,0.1,or_greater")] + public float WallHugGravityLesseningFactor { get; set; } = 2f; + [Export(PropertyHint.Range, "0.1,50,0.1,or_greater")] + public float WallHugDownwardMaxSpeed { get; set; } = 2f; [Export(PropertyHint.Range, "0.1,10,0.1,or_greater")] public float WallHugHorizontalDeceleration { get; set; } = 5f; - + private float _targetSpeed; private float _gravity; [ExportCategory("Other")] [Export(PropertyHint.Range, "0,1,0.01,or_greater")] public float TimeScaleAimInAir { get; set; } = 0.05f; - [Export(PropertyHint.Range, "0,5,0.1,or_greater")] - public float MaxJumpBoostAfterDashing { get; set; } = 1f; - [Export(PropertyHint.Range, "0,5,1,or_greater")] public int MaxNumberOfDashActions { get; set; } = 1; - [Export(PropertyHint.Range, "0,200,1,or_greater")] - public int DashIndicatorStartSize { get; set; } = 100; - [Export(PropertyHint.Range, "0,1,0.01")] - public float PerfectlyTimedActionTimer { get; set; } = 0.8f; - [Export(PropertyHint.Range, "0,50,0.1")] - public float BasicDashStrength { get; set; } = 10f; [Export] public Curve DashTimeDilationCurve { get; set; } private bool _canDash = true; - private bool _isDashOnCooldown = false; private int _empoweredActionsLeft; public int EmpoweredActionsLeft { @@ -160,7 +164,6 @@ public partial class PlayerController : CharacterBody3D private StateChartState _weaponInHand; private StateChartState _aiming; - private StateChartState _dashing; private StateChartState _weaponThrown; private StateChartState _actionHanging; private StateChartState _empowerOn; @@ -177,6 +180,8 @@ public partial class PlayerController : CharacterBody3D private StateChartState _simpleJump; private StateChartState _doubleJump; private StateChartState _megaJump; + private StateChartState _simpleDash; + private StateChartState _poweredDash; private StateChartState _doubleJumpEnabled; private StateChartState _onWall; private StateChartState _onWallHugCanceled; @@ -184,6 +189,9 @@ public partial class PlayerController : CharacterBody3D private StateChartState _onWallHanging; private StateChartState _falling; + private Transition _onJumpFromWall; + private Transition _onMegajumpFromWall; + public override void _Ready() { /////////////////////////// @@ -240,7 +248,8 @@ public partial class PlayerController : CharacterBody3D _weaponInHand = StateChartState.Of(GetNode("StateChart/Root/WeaponState/InHand")); _weaponThrown = StateChartState.Of(GetNode("StateChart/Root/WeaponState/Flying")); _aiming = StateChartState.Of(GetNode("StateChart/Root/Aim/On")); - _dashing = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing")); + _simpleDash = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing/Dash")); + _poweredDash = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing/PoweredDash")); // _actionHanging = StateChartState.Of(GetNode("StateChart/Root/Actions/Hanging")); _empowerOn = StateChartState.Of(GetNode("StateChart/Root/Empower/On")); _empowerOff = StateChartState.Of(GetNode("StateChart/Root/Empower/Off")); @@ -257,17 +266,17 @@ public partial class PlayerController : CharacterBody3D _doubleJump = StateChartState.Of(GetNode("StateChart/Root/Movement/Jump/DoubleJump")); _megaJump = StateChartState.Of(GetNode("StateChart/Root/Movement/Jump/MegaJump")); _doubleJumpEnabled = StateChartState.Of(GetNode("StateChart/Root/Movement/Airborne/DoubleJumpEnabled")); + _falling = StateChartState.Of(GetNode("StateChart/Root/Movement/Airborne/Falling")); _onWall = StateChartState.Of(GetNode("StateChart/Root/Movement/OnWall")); + _onJumpFromWall = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/OnJump")); + _onMegajumpFromWall = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/OnMegajump")); _onWallHugging = StateChartState.Of(GetNode("StateChart/Root/Movement/OnWall/Hugging")); _onWallHugCanceled = StateChartState.Of(GetNode("StateChart/Root/Movement/OnWall/HugCanceled")); _onWallHanging = StateChartState.Of(GetNode("StateChart/Root/Movement/OnWall/Hanging")); - _falling = StateChartState.Of(GetNode("StateChart/Root/Movement/Airborne/Falling")); // State timers - _coyoteTimer = GetNode("CoyoteTime"); _powerCooldownTimer = GetNode("PowerCooldown"); _timeScaleAimInAirTimer = GetNode("TimeScaleAimInAir"); - _timeAfterDashingTimer = GetNode("TimeAfterDashing"); - _empowerTimeDownscale = GetNode("EmpowerTimeDownscale"); + _simpleDashCooldownTimer = GetNode("DashCooldown"); /////////////////////////// // Initialize components // @@ -308,10 +317,6 @@ public partial class PlayerController : CharacterBody3D /////////////////////////// // Signal setup /////////// /////////////////////////// - - DashSystem.DashEnded += OnDashEnded; - DashSystem.DashProgress += OnDashProgress; - _weaponInHand.StateProcessing += HandleWeaponInHand; _aiming.StateProcessing += HandleAiming; _aiming.StateEntered += OnAimingEntered; @@ -321,22 +326,12 @@ public partial class PlayerController : CharacterBody3D _grounded.StateEntered += OnGrounded; _grounded.StatePhysicsProcessing += HandleGrounded; _airborne.StatePhysicsProcessing += HandleAirborne; - _onWallHugCanceled.StatePhysicsProcessing += HandleAirborne; - _onWallHugging.StatePhysicsProcessing += HandleWallHugging; - _onWallHanging.StatePhysicsProcessing += HandleWallHanging; _coyoteEnabled.StateEntered += StartCoyoteTime; - _coyoteTimer.Timeout += CoyoteExpired; _timeScaleAimInAirTimer.Timeout += ResetTimeScale; - _dashing.StatePhysicsProcessing += Dashing; // _weaponThrown.StateEntered += OnWeaponThrown; - // _empowerOn.StateEntered += OnEmpowerStarted; - // _empowerOn.StateProcessing += HandleEmpower; - // _empowerOff.StateEntered += EmpowerStopped; - // _empowerTimeDownscale.Timeout += EmpowerTimerTimeout; - _powerFull.StateEntered += StopPowerCooldown; _powerFull.StateExited += StartPowerCooldown; _powerRecharging.StateEntered += StartPowerCooldown; @@ -352,13 +347,43 @@ public partial class PlayerController : CharacterBody3D _megaJump.StateEntered += OnMegaJumpStarted; _megaJump.StatePhysicsProcessing += HandleMegaJump; + + _simpleDash.StateEntered += OnSimpleDashStarted; + _simpleDash.StatePhysicsProcessing += HandleSimpleDash; + + _poweredDash.StateEntered += OnPoweredDashStarted; + _poweredDash.StatePhysicsProcessing += HandlePoweredDash; + _poweredDash.StateExited += OnPoweredDashFinished; + + _simpleDashCooldownTimer.Timeout += DashCooldownTimeout; + + _onWallHugCanceled.StatePhysicsProcessing += HandleAirborne; + _onWallHugging.StatePhysicsProcessing += HandleWallHugging; + _onWallHanging.StatePhysicsProcessing += HandleWallHanging; + + _onJumpFromWall.Taken += OnJumpFromWall; + _onMegajumpFromWall.Taken += OnMegajumpFromWall; + } + + public void OnWallDetected() + { + FinishPoweredDash(); + } + + public void OnGrounded() + { + _isWallJumpAvailable = true; + if (_simpleDashCooldownTimer.IsStopped()) + _simpleDashCooldownTimer.Start(); + } + public void DashCooldownTimeout() + { + _canDash = true; } - // Physics processes public void HandleGrounded(float delta) { MoveOnGround(delta); - _canDash = true; if (!isOnFloorCustom()) _playerState.SendEvent("start_falling"); } @@ -378,7 +403,6 @@ public partial class PlayerController : CharacterBody3D if (!WallHugSystem.IsWallHugging()) _playerState.SendEvent("start_falling"); } - public void HandleWallHanging(float delta) { WallHang(delta); @@ -448,21 +472,57 @@ public partial class PlayerController : CharacterBody3D } public void OnMegaJumpStarted() { + PerformEmpoweredAction(); OnJumpStarted(MegaJumpStartVelocity); } - - public Vector3 ComputeHVelocity(float delta, float accelerationFactor, float decelerationFactor) + + public void WallHug(float delta) { - Vector3 direction = HeadSystem.Transform.Basis * _inputMove; - var acceleration = direction.Length() > 0 ? accelerationFactor : decelerationFactor; + var hvel = ComputeHVelocity(delta, WallHugHorizontalDeceleration, WallHugHorizontalDeceleration); + var vvel = Velocity.Y - (CalculateGravityForce() * delta / WallHugGravityLesseningFactor); + vvel = Math.Abs(vvel) > WallHugDownwardMaxSpeed ? -WallHugDownwardMaxSpeed : vvel; + Velocity = hvel + vvel*Vector3.Up; + } + + public void WallHang(float delta) + { + Velocity = Vector3.Zero; + MoveAndSlide(); + } + + public void ComputeJumpFromWallHSpeed(float jumpStrength) + { + // if (!_isWallJumpAvailable) + // return; + // _isWallJumpAvailable = false; + // var isLookingTowardsWall = HeadSystem.GetForwardHorizontalVector().Dot(wallNormal) > 0.5; + // var jumpDirection = isLookingTowardsWall ? Vector3.Up : wallNormal; + var wallNormal = WallHugSystem.GetWallNormal().UnwrapOr(Vector3.Up); + var jumpVector = wallNormal * jumpStrength; + + SetHorizontalVelocity(new Vector2(jumpVector.X, jumpVector.Z)); + } + public void OnJumpFromWall() + { + ComputeJumpFromWallHSpeed(WallJumpStartVelocity); + } + public void OnMegajumpFromWall() + { + ComputeJumpFromWallHSpeed(WallMegajumpStartVelocity); + } + + public Vector3 ComputeHVelocity(float delta, float accelerationFactor, float decelerationFactor, Vector3? direction = null) + { + var dir = direction ?? HeadSystem.Transform.Basis * _inputMove; + + var acceleration = dir.Length() > 0 ? accelerationFactor : decelerationFactor; - float xAcceleration = Mathf.Lerp(Velocity.X, direction.X * _targetSpeed, delta * acceleration); - float zAcceleration = Mathf.Lerp(Velocity.Z, direction.Z * _targetSpeed, delta * acceleration); + float xAcceleration = Mathf.Lerp(Velocity.X, dir.X * _targetSpeed, delta * acceleration); + float zAcceleration = Mathf.Lerp(Velocity.Z, dir.Z * _targetSpeed, delta * acceleration); return new Vector3(xAcceleration, 0, zAcceleration); } public Vector3 ComputeHVelocityGround(float delta) { - return ComputeHVelocity(delta, AccelerationFloor, DecelerationFloor); } public Vector3 ComputeHVelocityAir(float delta) @@ -477,6 +537,13 @@ public partial class PlayerController : CharacterBody3D y: verticalVelocity, z: Velocity.Z); } + public void SetHorizontalVelocity(Vector2 velocity) + { + Velocity = new Vector3( + x: velocity.X, + y: Velocity.Y, + z: velocity.Y); + } public void HandleJump(float delta, float gravityFactor, int hangFrames) { @@ -528,19 +595,16 @@ public partial class PlayerController : CharacterBody3D var progress = (float) (_powerCooldownTimer.TimeLeft / _powerCooldownTimer.WaitTime); PowerCooldownIndicator.SetSize(new Vector2(100 * progress, 10)); } - public void StartPowerCooldown() { _powerCooldownTimer.Start(); PowerCooldownIndicator.Visible = true; } - public void StopPowerCooldown() { _powerCooldownTimer.Stop(); PowerCooldownIndicator.Visible = false; } - public void PowerCooldownExpired() { EmpoweredActionsLeft += 1; @@ -563,7 +627,6 @@ public partial class PlayerController : CharacterBody3D { _inputRotateFloorplane = value; } - public void OnInputAimPressed() { _playerState.SendEvent("aim_pressed"); @@ -592,11 +655,6 @@ public partial class PlayerController : CharacterBody3D OnWeaponThrown(); } } - public void OnInputDashPressed() - { - _playerState.SendEvent("dash"); - PerformDash(_empowerOn.Active); - } public void OnInputEmpowerDown() { _playerState.SendEvent("empower_down"); @@ -606,43 +664,69 @@ public partial class PlayerController : CharacterBody3D _playerState.SendEvent("empower_released"); } - public void PerformDash(bool isEmpowered) + public void OnInputDashPressed() { - if (_aiming.Active) - { - OnDashStarted(); - return; - } - - if (!_canDash) - return; - - _canDash = false; - var dashStrength = BasicDashStrength; - if (isEmpowered && CanPerformEmpoweredAction()) + if (_empowerOn.Active && CanPerformEmpoweredAction()) { PerformEmpoweredAction(); - dashStrength *= 2.5f; + _playerState.SendEvent("powered_dash"); + return; } + _playerState.SendEvent("dash"); + } + + public void OnSimpleDashStarted() + { + if (!_canDash) + return; + _canDash = false; + var dashStrength = SimpleDashStrength; + + var direction = GetInputGlobalHDirection(); + SetVelocity(direction * dashStrength); + } + + public void HandleSimpleDash(float delta) + { + _playerState.SendEvent("dash_finished"); + } + + public Vector3 GetInputGlobalHDirection() + { var direction = HeadSystem.Transform.Basis * _inputMove; - var planarDirection = new Vector3(direction.X, 0, direction.Z).Normalized(); - SetVelocity(planarDirection * dashStrength); + return new Vector3(direction.X, 0, direction.Z).Normalized(); } - public void Dashing(float delta) + public Vector3 GetInputLocalHDirection() { - _playerState.SendEvent("dash_ended"); + var direction = _inputMove; + return new Vector3(direction.X, 0, direction.Z).Normalized(); } - - /////////////////////////// - // Stateful logic ///////// - /////////////////////////// - - public void OnGrounded() + public void OnPoweredDashStarted() { - _isWallJumpAvailable = true; + Velocity = GetInputGlobalHDirection() * PoweredDashStrength; + GetTree().CreateTimer(PoweredDashTime).Timeout += FinishPoweredDash; + } + + public void OnPoweredDashFinished() + { + // Try mantling here + } + + public void FinishPoweredDash() + { + _playerState.SendEvent("dash_finished"); + } + + public void HandlePoweredDash(float delta) + { + var collision = MoveAndCollide(Velocity * delta, maxCollisions: 10); + if (collision != null) + { + FinishPoweredDash(); + } } public bool CanPerformEmpoweredAction() @@ -660,7 +744,7 @@ public partial class PlayerController : CharacterBody3D // Jumping public void StartCoyoteTime() { - _coyoteTimer.Start(); + GetTree().CreateTimer(CoyoteTime).Timeout += CoyoteExpired; } public void CoyoteExpired() { @@ -699,25 +783,7 @@ public partial class PlayerController : CharacterBody3D public void Jump(JumpTypes jumpType, Vector3? jumpDirection = null, float boost = 1.0f) { var effectiveJumpDirection = jumpDirection ?? Vector3.Up; - var jumpForce = 0.0f; - switch (jumpType) - { - case JumpTypes.DoubleJump: - jumpForce = CalculateDoubleJumpForce(); - break; - case JumpTypes.SimpleJump: - jumpForce = CalculateJumpForce(); - break; - case JumpTypes.JumpFromDash: - jumpForce = CalculateJumpFromDashForce(); - break; - case JumpTypes.JumpFromWall: - jumpForce = CalculateJumpFromWallForce(); - break; - default: - jumpForce = CalculateJumpForce(); - break; - } + var jumpForce = 100.0f; var currentHorizontalVelocity = new Vector3(Velocity.X, 0, Velocity.Z); var jumpVelocity = jumpForce * effectiveJumpDirection * boost; @@ -769,7 +835,6 @@ public partial class PlayerController : CharacterBody3D } PerformEmpoweredAction(); - _timeAfterDashingTimer.Start(); if (WeaponSystem.FlyingState.Active) { DashSystem.ShouldMantle = false; @@ -794,17 +859,6 @@ public partial class PlayerController : CharacterBody3D _dashDirection = (DashSystem.PlannedPlayerLocation - GlobalPosition).Normalized(); DashSystem.Dash(); } - - public void OnDashProgress(float progress) - { - return; - - Engine.SetTimeScale(DashTimeDilationCurve.Sample(progress)); - - DashIndicator.SetCustomMinimumSize(Vector2.One * DashIndicatorStartSize * (1 - progress)); - var indicatorColor = progress < PerfectlyTimedActionTimer ? new Color(1, 1, 1) : new Color(0, 1, 0); - DashIndicator.SetModulate(indicatorColor); - } public void OnDashEnded() { // Regular dash @@ -911,25 +965,7 @@ public partial class PlayerController : CharacterBody3D var verticalVelocity = Velocity.Y - (CalculateGravityForce() * (float)delta); Velocity = new Vector3(horizontalVelocity.X, verticalVelocity, horizontalVelocity.Z); } - - public void WallHug(float delta) - { - float xAcceleration = Mathf.Lerp(Velocity.X, 0, - (float)delta * WallHugHorizontalDeceleration); - float zAcceleration = Mathf.Lerp(Velocity.Z, 0, - (float)delta * WallHugHorizontalDeceleration); - Velocity = new Vector3( - x: xAcceleration, - y: -WallHugDownwardSpeed, - z: zAcceleration); - } - - public void WallHang(float delta) - { - Velocity = Vector3.Zero; - MoveAndSlide(); - } - + private void HandleStairs(float delta) { StairsSystem.UpStairsCheckParams upStairsCheckParams = new StairsSystem.UpStairsCheckParams @@ -1011,10 +1047,6 @@ public partial class PlayerController : CharacterBody3D // Helpers //////////////// /////////////////////////// - public float CalculateJumpForce() => _gravity * StartVelocity; - public float CalculateJumpFromDashForce() => CalculateJumpForce() * JumpFromDashSpeedFactor; - public float CalculateJumpFromWallForce() => CalculateJumpForce() * JumpFromWallSpeedFactor; - public float CalculateDoubleJumpForce() => CalculateJumpForce() * DoubleJumpSpeedFactor; public float CalculateGravityForce() => _gravity * Weight; public void ReduceTimeScaleWhileAiming() diff --git a/systems/dash/DashSystem.cs b/systems/dash/DashSystem.cs index 59934cc..0d9465b 100644 --- a/systems/dash/DashSystem.cs +++ b/systems/dash/DashSystem.cs @@ -4,6 +4,9 @@ namespace Movementtests.systems; public partial class DashSystem: Node3D { + public record DashLocation(bool HasHit, Vector3 TargetLocation); + + [Export(PropertyHint.Range, "0,0.2,0.01,or_greater")] public float DashSpeed { get; set; } = 0.1f; [Export(PropertyHint.Range, "0,1000,1,or_greater")] @@ -60,14 +63,14 @@ public partial class DashSystem: Node3D _dashIndicatorAnim = GetNode("DashIndicator/AnimationPlayer"); } - private void ComputeDashLocation() + private DashLocation ComputeDashLocation() { - TargetLocation = _dashCast3D.ToGlobal(_dashCast3D.TargetPosition); - HasHit = _dashCast3D.IsColliding(); - if (!HasHit) + + var targetLocation = _dashCast3D.ToGlobal(_dashCast3D.TargetPosition); + var hasHit = _dashCast3D.IsColliding(); + if (!hasHit) { - PlannedPlayerLocation = TargetLocation; - return; + return new DashLocation(false, targetLocation); } CollisionPoint = _dashCast3D.GetCollisionPoint(0); @@ -80,12 +83,23 @@ public partial class DashSystem: Node3D // Pushes the point down when dashing to under a platform so head doesn't clip var maxPushDownDistance = 0.9f; var correctionProportion = (float) Mathf.Remap(CollisionNormal.Y, -0.5, -1, 0, 1); - var proportion = (float) Mathf.Remap(_dashCast3D.GlobalRotation.X, 0, 1.57, 0, 1); - PlannedPlayerLocation = locationAlongPath - + CollisionNormal - * maxPushDownDistance - * Mathf.Clamp(proportion, 0, 1) - * Mathf.Clamp(correctionProportion, 0, 1); + var proportion = (float)Mathf.Remap(_dashCast3D.GlobalRotation.X, 0, 1.57, 0, 1); + var finalLocation = locationAlongPath + + CollisionNormal + * maxPushDownDistance + * Mathf.Clamp(proportion, 0, 1) + * Mathf.Clamp(correctionProportion, 0, 1); + + return new DashLocation(true, finalLocation); + } + + public DashLocation GetDashLocationInDirection(Vector3 direction) + { + var angle = Mathf.Atan2(direction.X, direction.Z); + GD.Print(angle); + var rotation = _head.Rotation.Y + angle*2.0f; + _dashCast3D.SetRotation(new Vector3(0, rotation, 0)); + return ComputeDashLocation(); } public void PrepareDash() @@ -97,7 +111,7 @@ public partial class DashSystem: Node3D _head.Rotation.Y, _camera.Rotation.Z)); - ComputeDashLocation(); + (HasHit, PlannedPlayerLocation) = ComputeDashLocation(); ShouldMantle = false; var mantleLocation = Vector3.Zero; diff --git a/systems/wall_hug/WallHugSystem.cs b/systems/wall_hug/WallHugSystem.cs index bfc3817..1320b9c 100644 --- a/systems/wall_hug/WallHugSystem.cs +++ b/systems/wall_hug/WallHugSystem.cs @@ -5,8 +5,11 @@ using RustyOptions; namespace Movementtests.systems; + public partial class WallHugSystem : Node3D { + [Signal] + public delegate void WallDetectedEventHandler(); private List _raycasts; @@ -19,6 +22,13 @@ public partial class WallHugSystem : Node3D _raycasts.Add(GetNode("right")); } + public override void _PhysicsProcess(double delta) + { + base._PhysicsProcess(delta); + if (IsWallHugging()) + EmitSignal(SignalName.WallDetected); + } + public bool IsWallHugging() { foreach (RayCast3D raycast in _raycasts)