diff --git a/player_controller/PlayerController.tscn b/player_controller/PlayerController.tscn index c7981b2..1f9a903 100644 --- a/player_controller/PlayerController.tscn +++ b/player_controller/PlayerController.tscn @@ -66,6 +66,7 @@ MegaJumpGravityLesseningFactor = 1.2 WallJumpStartVelocity = 8.0 SimpleDashStrength = 15.0 PoweredDashStrength = 50.0 +AimedDashTime = 0.2 WallHugGravityLesseningFactor = 15.0 WallHugDownwardMaxSpeed = 8.0 WallHugHorizontalDeceleration = 0.5 @@ -98,6 +99,7 @@ mesh = SubResource("CapsuleMesh_xc2g5") [node name="CapsuleCollider" type="CollisionShape3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.85, 0) shape = ExtResource("13_r7i3q") +debug_color = Color(0, 0.6, 0.701961, 0.341176) script = ExtResource("8_lmtjd") CapsuleDefaultHeight = 1.7 @@ -418,6 +420,12 @@ to = NodePath("../Dashing/PoweredDash") event = &"powered_dash" delay_in_seconds = "0.0" +[node name="OnAimedDash" type="Node" parent="StateChart/Root/Movement"] +script = ExtResource("28_n7qhm") +to = NodePath("../Dashing/AimedDash") +event = &"aimed_dash" +delay_in_seconds = "0.0" + [node name="Mantling" type="Node" parent="StateChart/Root/Movement"] script = ExtResource("27_34snm") @@ -492,6 +500,9 @@ script = ExtResource("27_34snm") [node name="PoweredDash" type="Node" parent="StateChart/Root/Movement/Dashing"] script = ExtResource("27_34snm") +[node name="AimedDash" type="Node" parent="StateChart/Root/Movement/Dashing"] +script = ExtResource("27_34snm") + [node name="Grounded" type="Node" parent="StateChart/Root/Movement"] script = ExtResource("27_34snm") diff --git a/player_controller/Scripts/PlayerController.cs b/player_controller/Scripts/PlayerController.cs index 2806348..94e64d3 100644 --- a/player_controller/Scripts/PlayerController.cs +++ b/player_controller/Scripts/PlayerController.cs @@ -125,6 +125,10 @@ public partial class PlayerController : CharacterBody3D public float PoweredDashTime { get; set; } = 0.3f; [Export(PropertyHint.Range, "0,100,0.1")] public float PoweredDashStrength { get; set; } = 10f; + // Aimed Dash + [ExportSubgroup("Aimed")] + [Export(PropertyHint.Range, "0,1,0.01,or_greater")] + public float AimedDashTime { get; set; } = 0.1f; // Wall hug [ExportGroup("Wall hug")] @@ -184,6 +188,7 @@ public partial class PlayerController : CharacterBody3D private StateChartState _megaJump; private StateChartState _simpleDash; private StateChartState _poweredDash; + private StateChartState _aimedDash; private StateChartState _doubleJumpEnabled; private StateChartState _onWall; private StateChartState _onWallHugCanceled; @@ -194,6 +199,9 @@ public partial class PlayerController : CharacterBody3D private Transition _onJumpFromWall; private Transition _onMegajumpFromWall; + private float _playerHeight; + private float _playerRadius; + public override void _Ready() { /////////////////////////// @@ -240,6 +248,10 @@ public partial class PlayerController : CharacterBody3D "HeadCollisionDetectors/HeadCollisionDetector" + i); } + var playerShape = CapsuleCollider.GetShape() as CapsuleShape3D; + _playerHeight = playerShape!.Height; + _playerRadius = playerShape.Radius; + // RPG Stuff Stamina = GetNode("Stamina"); HealthSystem = GetNode("HealthSystem"); @@ -252,6 +264,7 @@ public partial class PlayerController : CharacterBody3D _aiming = StateChartState.Of(GetNode("StateChart/Root/Aim/On")); _simpleDash = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing/Dash")); _poweredDash = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing/PoweredDash")); + _aimedDash = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing/AimedDash")); // _actionHanging = StateChartState.Of(GetNode("StateChart/Root/Actions/Hanging")); _empowerOn = StateChartState.Of(GetNode("StateChart/Root/Empower/On")); _empowerOff = StateChartState.Of(GetNode("StateChart/Root/Empower/Off")); @@ -320,14 +333,13 @@ public partial class PlayerController : CharacterBody3D // Signal setup /////////// /////////////////////////// _weaponInHand.StateProcessing += HandleWeaponInHand; - _aiming.StateProcessing += HandleAiming; + _aiming.StatePhysicsProcessing += HandleAiming; _aiming.StateEntered += OnAimingEntered; _aiming.StateExited += ResetTimeScale; _aiming.StateExited += OnAimingExited; _grounded.StateEntered += OnGrounded; _grounded.StatePhysicsProcessing += HandleGrounded; - _airborne.StateEntered += OnAirborne; _airborne.StatePhysicsProcessing += HandleAirborne; _coyoteEnabled.StateEntered += StartCoyoteTime; @@ -357,6 +369,10 @@ public partial class PlayerController : CharacterBody3D _poweredDash.StateEntered += OnPoweredDashStarted; _poweredDash.StatePhysicsProcessing += HandlePoweredDash; _poweredDash.StateExited += OnPoweredDashFinished; + + _aimedDash.StateEntered += OnAimedDashStarted; + _aimedDash.StatePhysicsProcessing += HandleAimedDash; + _aimedDash.StateExited += OnAimedDashFinished; _simpleDashCooldownTimer.Timeout += DashCooldownTimeout; @@ -384,9 +400,6 @@ public partial class PlayerController : CharacterBody3D _simpleDashCooldownTimer.Start(); } - public void OnAirborne() - { - } public void DashCooldownTimeout() { _canDash = true; @@ -655,7 +668,7 @@ public partial class PlayerController : CharacterBody3D public void OnInputAimCanceled() { _playerState.SendEvent("cancel"); - DashSystem.CancelDash(); + DashSystem.StopPreparingDash(); } public void OnInputHitPressed() { @@ -672,11 +685,16 @@ public partial class PlayerController : CharacterBody3D { _playerState.SendEvent("empower_released"); } - - private bool _dashAvailable = true; public void OnInputDashPressed() { + if (_aiming.Active && CanPerformEmpoweredAction()) + { + PerformEmpoweredAction(); + _playerState.SendEvent("aimed_dash"); + _playerState.SendEvent("cancel_aim"); + return; + } if (_empowerOn.Active && CanPerformEmpoweredAction()) { PerformEmpoweredAction(); @@ -693,6 +711,92 @@ public partial class PlayerController : CharacterBody3D _playerState.SendEvent("dash"); } + + public void OnAimingEntered() + { + // if (!WeaponSystem.InHandState.Active) + // { + // OnDashStarted(); + // return; + // } + if (CanPerformEmpoweredAction()) + DashSystem.StartPreparingDash(); + + if (!isOnFloorCustom() && CanPerformEmpoweredAction()) + ReduceTimeScaleWhileAiming(); + } + public void HandleAiming(float delta) + { + RotateWeaponWithPlayer(); + + if (CanPerformEmpoweredAction()) + DashSystem.PrepareDash(); + } + public void OnAimingExited() + { + DashSystem.StopPreparingDash(); + } + + public void OnAimedDashStarted() + { + // if (WeaponSystem.FlyingState.Active) + // { + // DashSystem.ShouldMantle = false; + // DashSystem.PlannedPlayerLocation = WeaponSystem.GlobalPosition; + // } + // else if (WeaponSystem.PlantedState.Active) + // { + // DashSystem.ShouldMantle = false; + // var dashLocation = WeaponSystem.PlantLocation; + // if (WeaponSystem.IsPlantedInWall()) + // { + // dashLocation += WeaponSystem.PlantNormal * 0.5f; // Player radius + // } + // + // if (WeaponSystem.IsPlantedUnderPlatform()) + // { + // dashLocation += Vector3.Down * 1f; // Player height + // } + // + // DashSystem.PlannedPlayerLocation = dashLocation; + // } + // _dashDirection = (DashSystem.PlannedPlayerLocation - GlobalPosition).Normalized(); + + // Adjusting for player height, where the middle of the capsule should get to the dash location instead of the + // feet of the capsule + // GD.Print(DashSystem.CollisionNormal); + var correction = DashSystem.CollisionNormal == Vector3.Down ? _playerHeight : DashSystem.DashCastRadius; + var correctedLocation = DashSystem.PlannedLocation + Vector3.Down * correction; + + var dashTween = GetTree().CreateTween(); + dashTween.SetParallel(); + dashTween.SetTrans(Tween.TransitionType.Cubic); + dashTween.SetEase(Tween.EaseType.InOut); + + dashTween.TweenProperty(this, "global_position", correctedLocation, AimedDashTime); + dashTween.TweenMethod(Callable.From(AimedDashTweenOngoing), 0.0f, 1.0f, AimedDashTime); + + dashTween.Finished += AimedDashTweenEnded; + } + + public void HandleAimedDash(float delta) + { + } + + public void AimedDashTweenOngoing(float progress) + { + } + + public void AimedDashTweenEnded() + { + _playerState.SendEvent("dash_finished"); + } + + public void OnAimedDashFinished() + { + if (DashSystem.ShouldMantle) + Mantle(); + } public void OnSimpleDashStarted() { @@ -760,7 +864,6 @@ public partial class PlayerController : CharacterBody3D _playerState.SendEvent(EmpoweredActionsLeft <= 0 ? "expired" : "power_used"); } - // Jumping public void StartCoyoteTime() { GetTree().CreateTimer(CoyoteTime).Timeout += CoyoteExpired; @@ -769,43 +872,6 @@ public partial class PlayerController : CharacterBody3D { _playerState.SendEvent("coyote_expired"); } - public void JumpFromWall(bool isEmpowered) - { - if (!_isWallJumpAvailable) - return; - - _isWallJumpAvailable = false; - var wallNormal = WallHugSystem.GetWallNormal().UnwrapOr(Vector3.Up); - var isLookingTowardsWall = HeadSystem.GetForwardHorizontalVector().Dot(wallNormal) > 0.5; - var jumpDirection = isLookingTowardsWall ? Vector3.Up : wallNormal; - if (isEmpowered && CanPerformEmpoweredAction()) - { - PerformEmpoweredAction(); - PerformJump(JumpTypes.JumpFromDash, jumpDirection); - return; - } - PerformJump(JumpTypes.JumpFromWall, jumpDirection); - } - private void PerformJump(JumpTypes jumpType, Vector3? jumpDirection = null) - { - var effectiveJumpDirection = jumpDirection ?? Vector3.Up; - var jumpVector = (effectiveJumpDirection.Normalized() + Vector3.Up).Normalized(); - - bool doesCapsuleHaveCrouchingHeight = CapsuleCollider.IsCrouchingHeight(); - bool isPlayerDead = HealthSystem.IsDead(); - if (!doesCapsuleHaveCrouchingHeight && !isPlayerDead) - Jump(jumpType, jumpVector); - } - - public void Jump(JumpTypes jumpType, Vector3? jumpDirection = null, float boost = 1.0f) - { - var effectiveJumpDirection = jumpDirection ?? Vector3.Up; - var jumpForce = 100.0f; - - var currentHorizontalVelocity = new Vector3(Velocity.X, 0, Velocity.Z); - var jumpVelocity = jumpForce * effectiveJumpDirection * boost; - Velocity = currentHorizontalVelocity + jumpVelocity; - } // Mantling public void Mantle() @@ -847,7 +913,7 @@ public partial class PlayerController : CharacterBody3D { _playerState.SendEvent("aim_canceled"); _playerState.SendEvent("dash_ended"); - DashSystem.CancelDash(); + DashSystem.StopPreparingDash(); return; } @@ -855,7 +921,7 @@ public partial class PlayerController : CharacterBody3D if (WeaponSystem.FlyingState.Active) { DashSystem.ShouldMantle = false; - DashSystem.PlannedPlayerLocation = WeaponSystem.GlobalPosition; + DashSystem.PlannedLocation = WeaponSystem.GlobalPosition; } else if (WeaponSystem.PlantedState.Active) { @@ -871,10 +937,9 @@ public partial class PlayerController : CharacterBody3D dashLocation += Vector3.Down * 1f; // Player height } - DashSystem.PlannedPlayerLocation = dashLocation; + DashSystem.PlannedLocation = dashLocation; } - _dashDirection = (DashSystem.PlannedPlayerLocation - GlobalPosition).Normalized(); - DashSystem.Dash(); + _dashDirection = (DashSystem.PlannedLocation - GlobalPosition).Normalized(); } public void OnDashEnded() { @@ -916,7 +981,7 @@ public partial class PlayerController : CharacterBody3D } public void OnWeaponThrown() { - DashSystem.CancelDash(); + DashSystem.StopPreparingDash(); _playerState.SendEvent("cancel_aim"); RemoveChild(WeaponRoot); @@ -930,21 +995,6 @@ public partial class PlayerController : CharacterBody3D DashSystem.CollisionPoint, DashSystem.CollisionNormal); } - public void OnAimingEntered() - { - if (!WeaponSystem.InHandState.Active) - { - OnDashStarted(); - return; - } - if (!isOnFloorCustom() && CanPerformEmpoweredAction()) - ReduceTimeScaleWhileAiming(); - } - - public void OnAimingExited() - { - DashSystem.CancelDash(); - } // Regular processes public void HandleWeaponInHand(float delta) @@ -952,13 +1002,6 @@ public partial class PlayerController : CharacterBody3D if (WeaponSystem.InHandState.Active) RotateWeaponWithPlayer(); } - public void HandleAiming(float delta) - { - RotateWeaponWithPlayer(); - - if (CanPerformEmpoweredAction()) - DashSystem.PrepareDash(); - } /////////////////////////// // Stateless logic //////// diff --git a/systems/dash/DashSystem.cs b/systems/dash/DashSystem.cs index 0d9465b..77cec55 100644 --- a/systems/dash/DashSystem.cs +++ b/systems/dash/DashSystem.cs @@ -4,7 +4,7 @@ namespace Movementtests.systems; public partial class DashSystem: Node3D { - public record DashLocation(bool HasHit, Vector3 TargetLocation); + public record DashLocation(bool HasHit, Vector3 TargetLocation, Vector3 CollisionPoint, Vector3 CollisionNormal); [Export(PropertyHint.Range, "0,0.2,0.01,or_greater")] @@ -16,7 +16,7 @@ public partial class DashSystem: Node3D public Vector3 TargetLocation { get; set; } public Vector3 CollisionPoint { get; set; } public Vector3 CollisionNormal { get; set; } - public Vector3 PlannedPlayerLocation { get; set; } + public Vector3 PlannedLocation { get; set; } public bool ShouldMantle { get; set; } public Vector3 PlannedMantleLocation { get; set; } @@ -45,10 +45,21 @@ public partial class DashSystem: Node3D private Vector3 _globalDashPosition = Vector3.Zero; + private float _playerHeight; + private float _playerRadius; + + public float DashCastRadius { get; set; } + public void Init(Node3D head, Camera3D camera, TweenQueueSystem tweenQueueSystem) { _dashCast3D = GetNode("DashCast3D"); + var dashShape = _dashCast3D.GetShape() as SphereShape3D; + DashCastRadius = dashShape!.Radius; + _playerCast3D = GetNode("PlayerShapeCast3D"); + var playerShape = _playerCast3D.GetShape() as CapsuleShape3D; + _playerHeight = playerShape!.Height; + _playerRadius = playerShape!.Radius; _head = head; _camera = camera; @@ -63,121 +74,90 @@ public partial class DashSystem: Node3D _dashIndicatorAnim = GetNode("DashIndicator/AnimationPlayer"); } + private Vector3 RecurseThroughCollisions(Vector3 previousCollisionPoint, Vector3 previousNormal, int recursionDepth) + { + if (recursionDepth == 0) + return previousCollisionPoint; + + var startPoint = previousCollisionPoint + previousNormal*_playerHeight; + _playerCast3D.SetGlobalPosition(startPoint); + _playerCast3D.SetTargetPosition(-previousNormal*_playerRadius); + + var hasHit = _playerCast3D.IsColliding(); + if (!hasHit) + return previousCollisionPoint; + + return RecurseThroughCollisions( + _playerCast3D.GetCollisionPoint(0), + _playerCast3D.GetCollisionNormal(0), + recursionDepth - 1); + } + private DashLocation ComputeDashLocation() { - var targetLocation = _dashCast3D.ToGlobal(_dashCast3D.TargetPosition); var hasHit = _dashCast3D.IsColliding(); if (!hasHit) { - return new DashLocation(false, targetLocation); + return new DashLocation(false, targetLocation, Vector3.Zero, Vector3.Zero); } - - CollisionPoint = _dashCast3D.GetCollisionPoint(0); - CollisionNormal = _dashCast3D.GetCollisionNormal(0); + + var collisionPoint = _dashCast3D.GetCollisionPoint(0); + var collisionNormal = _dashCast3D.GetCollisionNormal(0); var fraction = _dashCast3D.GetClosestCollisionSafeFraction(); - var globalSweepPath = TargetLocation - _dashCast3D.GlobalPosition; + var globalSweepPath = targetLocation - _dashCast3D.GlobalPosition; var locationAlongPath = _dashCast3D.GlobalPosition + globalSweepPath * fraction; + return new DashLocation(true, locationAlongPath, collisionPoint, collisionNormal); - // 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); - 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(); + // // 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); + // var finalLocation = locationAlongPath + // + CollisionNormal + // * maxPushDownDistance + // * Mathf.Clamp(proportion, 0, 1) + // * Mathf.Clamp(correctionProportion, 0, 1); + // + // return new DashLocation(true, finalLocation); } public void PrepareDash() { - _dashTarget.SetVisible(false); - _dashCast3D.SetRotation(new Vector3( _camera.Rotation.X, _head.Rotation.Y, _camera.Rotation.Z)); - (HasHit, PlannedPlayerLocation) = ComputeDashLocation(); + (HasHit, PlannedLocation, CollisionPoint, CollisionNormal) = ComputeDashLocation(); + ShouldMantle = false; - var mantleLocation = Vector3.Zero; - if (HasHit && Mathf.Abs(CollisionNormal.Y) < 0.5f) - { - var mantleResult = _mantleSystem.FindMantleLocationAtPoint(PlannedPlayerLocation, CollisionNormal); - ShouldMantle = mantleResult.IsSome(out mantleLocation); - } - PlannedMantleLocation = mantleLocation; + // var mantleLocation = Vector3.Zero; + // if (HasHit && Mathf.Abs(CollisionNormal.Y) < 0.5f) + // { + // var mantleResult = _mantleSystem.FindMantleLocationAtPoint(PlannedLocation, CollisionNormal); + // ShouldMantle = mantleResult.IsSome(out mantleLocation); + // } + // PlannedMantleLocation = mantleLocation; + // Setup dash target var targetColor = HasHit ? new Color(1f, 0.2f, 0.2f) : new Color(1f, 1f, 1f); targetColor = ShouldMantle ? new Color(0.2f, 0.2f, 1f) : targetColor; - var targetMaterial = (StandardMaterial3D) _dashTarget.GetSurfaceOverrideMaterial(0); targetMaterial.SetAlbedo(targetColor); _dashTarget.SetVisible(true); - _dashTarget.SetGlobalPosition(PlannedPlayerLocation); + _dashTarget.SetGlobalPosition(PlannedLocation); } - public void CancelDash() + public void StopPreparingDash() { _dashTarget.SetVisible(false); } - public void DashTweenEnded() + public void StartPreparingDash() { - EmitSignal(SignalName.DashEnded); - _dashTarget.SetVisible(false); - } - - public void Dash() - { - EmitSignal(SignalName.DashStarted); - - var dashTweenInputs = new TweenQueueSystem.TweenInputs(PlannedPlayerLocation, DashSpeed); - var dashTween = _tweenQueueSystem.TweenToLocation(dashTweenInputs); - // dashTween.SetTrans(Tween.TransitionType.Cubic); - // dashTween.SetEase(Tween.EaseType.Out); - dashTween.TweenMethod(Callable.From(Dashing), 0.0f, 1.0f, DashSpeed); - dashTween.Finished += DashTweenEnded; - if (ShouldMantle) - { - _tweenQueueSystem.QueueTween(PlannedMantleLocation, 0.2f); - return; - } - - // var dashIndicator = (CpuParticles3D) DashIndicatorScene.Instantiate(); - // GetTree().GetRoot().AddChild(dashIndicator); - // _globalDashPosition = _dashTarget.GlobalPosition + 1.5f*Vector3.Up; - // dashIndicator.GlobalPosition = _globalDashPosition; - // dashIndicator.SetEmitting(true); - } - - public void Dashing(float proportion) - { - _dashTarget.SetGlobalPosition(_globalDashPosition); - EmitSignalDashProgress(proportion); - } - - public void DashToThrownWeapon() - { - - } - - public void DashToPlantedWeapon() - { - + _dashTarget.SetVisible(true); } } diff --git a/systems/dash/dash_system.tscn b/systems/dash/dash_system.tscn index ccf86a8..fe401ec 100644 --- a/systems/dash/dash_system.tscn +++ b/systems/dash/dash_system.tscn @@ -16,13 +16,14 @@ script = ExtResource("1_hwig2") DashIndicatorScene = ExtResource("2_tqt6i") [node name="PlayerShapeCast3D" type="ShapeCast3D" parent="."] +visible = false shape = ExtResource("2_jngg2") target_position = Vector3(0, 0, 0) collision_mask = 2 debug_shape_custom_color = Color(0.863327, 0.636844, 0, 1) [node name="DashCast3D" type="ShapeCast3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.85, 0) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6, 0) shape = SubResource("SphereShape3D_jngg2") target_position = Vector3(0, 0, -12) max_results = 1