gd: game feel improvement, dash limit, improved jump while aiming for dash

This commit is contained in:
2025-06-16 16:13:29 +02:00
parent b214441b45
commit 107c7622d5
8 changed files with 669 additions and 101 deletions

View File

@ -3,6 +3,7 @@ using Godot;
using GodotStateCharts;
using Movementtests.systems;
using Movementtests.player_controller.Scripts;
using RustyOptions;
public partial class PlayerController : CharacterBody3D
{
@ -38,17 +39,19 @@ public partial class PlayerController : CharacterBody3D
private float _inputRotateY;
private float _inputRotateFloorplane;
private bool _isAiming;
private bool _dashCanceled;
private Timer _coyoteTimer;
private Timer _timeScaleAimInAirTimer;
private Timer _timeAfterDashingTimer;
[Export(PropertyHint.Range, "0,1,0.01,or_greater")]
public float TimeScaleAimInAir { get; set; } = 0.2f;
[Export(PropertyHint.Range, "1,5,0.1,or_greater")]
public float MaxJumpBoostAfterDashing { get; set; } = 2f;
[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;
public int DashActionsLeft { get; set; }
private StateChart _playerState;
// Actions state
private StateChartState _weaponInHand;
@ -177,6 +180,8 @@ public partial class PlayerController : CharacterBody3D
};
HealthSystem.Init(healthSystemParams);
Stamina.SetSpeeds(MoveSystem.WalkSpeed, MoveSystem.SprintSpeed);
DashActionsLeft = MaxNumberOfDashActions;
///////////////////////////
// Signal setup ///////////
@ -188,7 +193,8 @@ public partial class PlayerController : CharacterBody3D
_aiming.StateProcessing += HandleAiming;
_aiming.StateEntered += OnAimingEntered;
_aiming.StateExited += ResetTimeScale;
_grounded.StateEntered += OnGrounded;
_grounded.StatePhysicsProcessing += HandleGrounded;
_airborne.StatePhysicsProcessing += HandleAirborne;
_wallHugging.StatePhysicsProcessing += HandleWallHugging;
@ -256,6 +262,24 @@ public partial class PlayerController : CharacterBody3D
///////////////////////////
// Stateful logic /////////
///////////////////////////
// Simple states
public void OnGrounded()
{
DashActionsLeft = MaxNumberOfDashActions;
GD.Print(DashActionsLeft);
}
public bool CanPerformDashAction()
{
return DashActionsLeft > 0;
}
public void PerformDashAction()
{
DashActionsLeft--;
GD.Print(DashActionsLeft);
}
// Jumping
public void StartCoyoteTime()
@ -268,36 +292,56 @@ public partial class PlayerController : CharacterBody3D
}
public void Jump()
{
if (_aiming.Active && CanPerformDashAction())
{
_playerState.SendEvent("jump_from_dash");
PerformDashAction();
PerformJump(MoveSystem.JumpTypes.JUMP_FROM_DASH);
return;
}
_playerState.SendEvent("to_double_jump");
PerformJump(false);
PerformJump(MoveSystem.JumpTypes.SIMPLE_JUMP);
}
public void JumpFromWall()
{
var wallNormal = WallHugSystem.GetWallNormal().UnwrapOr(Vector3.Up);
if (_aiming.Active && CanPerformDashAction())
{
_playerState.SendEvent("jump_from_dash");
PerformDashAction();
PerformJump(MoveSystem.JumpTypes.JUMP_FROM_DASH, wallNormal);
return;
}
_playerState.SendEvent("to_double_jump");
var wallNormal = WallHugSystem.GetWallNormal();
if (wallNormal.IsSome(out var normal))
PerformJump(false, normal);
PerformJump(false);
PerformJump(MoveSystem.JumpTypes.SIMPLE_JUMP, wallNormal);
}
public void DoubleJump()
{
_playerState.SendEvent("to_falling");
PerformJump(true);
if (_aiming.Active && CanPerformDashAction())
{
PerformDashAction();
PerformJump(MoveSystem.JumpTypes.JUMP_FROM_DASH);
return;
}
PerformJump(MoveSystem.JumpTypes.DOUBLE_JUMP);
}
private void PerformJump(bool isDoubleJump, Vector3? jumpDirection = null)
private void PerformJump(MoveSystem.JumpTypes jumpType, Vector3? jumpDirection = null)
{
var effectiveJumpDirection = jumpDirection ?? Vector3.Up;
var jumpVector = (effectiveJumpDirection.Normalized() + Vector3.Up).Normalized();
var proportionOfTimeGone = _timeAfterDashingTimer.TimeLeft / _timeAfterDashingTimer.WaitTime;
GD.Print(proportionOfTimeGone);
var actualBoost = 1 + MaxJumpBoostAfterDashing * proportionOfTimeGone;
var makeItDouble = actualBoost > 1;
if (makeItDouble && jumpType == MoveSystem.JumpTypes.SIMPLE_JUMP)
jumpType = MoveSystem.JumpTypes.DOUBLE_JUMP; // convert simple jump to double if done right after a dash
_timeAfterDashingTimer.Stop();
bool doesCapsuleHaveCrouchingHeight = CapsuleCollider.IsCrouchingHeight();
bool isPlayerDead = HealthSystem.IsDead();
if (!doesCapsuleHaveCrouchingHeight && !isPlayerDead)
MoveSystem.Jump(isDoubleJump, jumpVector, (float) actualBoost);
MoveSystem.Jump(jumpType, jumpVector, (float) actualBoost);
}
// Mantling
@ -315,6 +359,15 @@ public partial class PlayerController : CharacterBody3D
// Dashing and weapon throwing
public void OnDashStarted()
{
if (!CanPerformDashAction())
{
_playerState.SendEvent("aim_canceled");
_playerState.SendEvent("dash_ended");
DashSystem.CancelDash();
return;
}
PerformDashAction();
_timeAfterDashingTimer.Start();
if (WeaponSystem.FlyingState.Active)
{
@ -330,6 +383,7 @@ public partial class PlayerController : CharacterBody3D
}
public void OnDashEnded()
{
// _playerState.SendEvent("enable_double_jump"); // Allow for double jump after dash -- OP ?
// Regular dash
if (WeaponSystem.InHandState.Active)
{
@ -379,7 +433,7 @@ public partial class PlayerController : CharacterBody3D
}
public void OnAimingEntered()
{
if (!isOnFloorCustom())
if (!isOnFloorCustom() && CanPerformDashAction())
ReduceTimeScaleWhileAiming();
}
@ -391,10 +445,15 @@ public partial class PlayerController : CharacterBody3D
public void HandleAiming(float delta)
{
RotateWeaponWithPlayer();
DashSystem.PrepareDash();
if (isOnFloorCustom())
ResetTimeScale();
if (CanPerformDashAction())
DashSystem.PrepareDash();
else
{
_playerState.SendEvent("aim_canceled");
DashSystem.CancelDash();
}
}
// Physics processes