diff --git a/player_controller/PlayerController.tscn b/player_controller/PlayerController.tscn index 7d90cf9..88edcd8 100644 --- a/player_controller/PlayerController.tscn +++ b/player_controller/PlayerController.tscn @@ -82,6 +82,7 @@ MantleEndLocationDistanceFromWall = 1.0 MantleHeightCastStart = 2.0 [node name="DashSystem" parent="." instance=ExtResource("18_q5h8a")] +PostDashSpeed = 68.0 [node name="Bobbing" type="Node3D" parent="."] script = ExtResource("10_7wk1w") @@ -175,6 +176,12 @@ to = NodePath("../../WeaponInHand") event = &"dash_ended" delay_in_seconds = "0.0" +[node name="ToHanging" type="Node" parent="StateChart/Root/Dashing"] +script = ExtResource("28_n7qhm") +to = NodePath("../../Hanging") +event = &"dash_to_planted" +delay_in_seconds = "0.0" + [node name="WeaponThrown" type="Node" parent="StateChart/Root"] script = ExtResource("27_34snm") @@ -184,11 +191,21 @@ to = NodePath("../../Dashing") event = &"aim_pressed" delay_in_seconds = "0.0" +[node name="Hanging" type="Node" parent="StateChart/Root"] +script = ExtResource("27_34snm") + +[node name="ToWeaponInHand" type="Node" parent="StateChart/Root/Hanging"] +script = ExtResource("28_n7qhm") +to = NodePath("../../WeaponInHand") +event = &"jump" +delay_in_seconds = "0.0" + [node name="WeaponRoot" type="Node3D" parent="."] [node name="WeaponSystem" parent="WeaponRoot" instance=ExtResource("29_wv70j")] transform = Transform3D(1, 0, 0, 0, 0.173648, -0.984808, 0, 0.984808, 0.173648, 0.45268, 1.44035, -0.692528) ThrowForce = 25.0 +StraightThrowDuration = 0.07 [connection signal="input_aim_canceled" from="InputController" to="." method="OnInputAimCanceled"] [connection signal="input_aim_pressed" from="InputController" to="." method="OnInputAimPressed"] diff --git a/player_controller/Scripts/PlayerController.cs b/player_controller/Scripts/PlayerController.cs index 72dce10..de7ffd6 100644 --- a/player_controller/Scripts/PlayerController.cs +++ b/player_controller/Scripts/PlayerController.cs @@ -25,8 +25,8 @@ public partial class PlayerController : CharacterBody3D private bool _movementEnabled = true; private bool _shouldMantle; - private Vector3 _dashLocation = Vector3.Zero; private Vector3 _mantleLocation = Vector3.Zero; + private Vector3 _dashDirection = Vector3.Zero; private float _lastFrameWasOnFloor = -Mathf.Inf; @@ -45,6 +45,7 @@ public partial class PlayerController : CharacterBody3D private StateChartState _aiming; private StateChartState _dashing; private StateChartState _weaponThrown; + private StateChartState _hanging; public override void _Ready() { @@ -96,6 +97,7 @@ public partial class PlayerController : CharacterBody3D _aiming = StateChartState.Of(GetNode("StateChart/Root/Aiming")); _dashing = StateChartState.Of(GetNode("StateChart/Root/Dashing")); _weaponThrown = StateChartState.Of(GetNode("StateChart/Root/WeaponThrown")); + _hanging = StateChartState.Of(GetNode("StateChart/Root/Hanging")); /////////////////////////// // Initialize components // @@ -148,6 +150,16 @@ public partial class PlayerController : CharacterBody3D public void OnDashStarted() { + if (WeaponSystem.FlyingState.Active) + { + DashSystem.DashResolve = new DashResolveRecord(false, WeaponSystem.PlayerDashLocation, Vector3.Zero); + } + else if (WeaponSystem.PlantedState.Active) + { + // Should we try to resolve with mantle? + DashSystem.DashResolve = new DashResolveRecord(false, WeaponSystem.PlayerDashLocation, Vector3.Zero); + } + _dashDirection = (DashSystem.DashResolve.DashLocation - GlobalPosition).Normalized(); DashSystem.Dash(); } @@ -166,14 +178,39 @@ public partial class PlayerController : CharacterBody3D public void OnDashEnded() { - // Generates an error when dashing normally - // This should solve itself when we handle weapon thrown dashes and regular dashes through different states + // Regular dash + if (WeaponSystem.InHandState.Active) + { + _playerState.SendEvent("dash_ended"); + return; + } + + // Store the weapon state before resetting it + var isPlantedOnWall = WeaponSystem.PlantedState.Active && WeaponSystem.GlobalRotation.Dot(Vector3.Up) < 0.1; + var isFlying = WeaponSystem.FlyingState.Active; + + // Get the weapon back GetTree().GetRoot().RemoveChild(WeaponRoot); AddChild(WeaponRoot); - WeaponRoot.SetGlobalPosition(GlobalPosition); WeaponSystem.ResetWeapon(); + if (isFlying) + { + var vel = _dashDirection * DashSystem.PostDashSpeed; + SetVelocity(vel); + _playerState.SendEvent("dash_ended"); + return; // In case states aren't exclusives + } + + if (isPlantedOnWall) + { + MoveSystem.CanDoubleJump = true; + _playerState.SendEvent("dash_to_planted"); + return; // In case states aren't exclusives + } + + // Weapon planted anywhere else _playerState.SendEvent("dash_ended"); } @@ -213,6 +250,7 @@ public partial class PlayerController : CharacterBody3D public void OnInputJumpPressed() { + _playerState.SendEvent("jump"); bool doesCapsuleHaveCrouchingHeight = CapsuleCollider.IsCrouchingHeight(); bool isPlayerDead = HealthSystem.IsDead(); @@ -237,7 +275,8 @@ public partial class PlayerController : CharacterBody3D _inputMove, isOnFloorCustom(), isPlayerDead, - isHeadTouchingCeiling); + isHeadTouchingCeiling, + _hanging.Active); MoveSystem.MoveAround(moveAroundParams); Vector2 inputLookDir = new Vector2(_inputRotateY, _inputRotateFloorplane); diff --git a/systems/dash/DashSystem.cs b/systems/dash/DashSystem.cs index 6400e5e..8750075 100644 --- a/systems/dash/DashSystem.cs +++ b/systems/dash/DashSystem.cs @@ -10,11 +10,14 @@ public partial class DashSystem: Node3D { [Export(PropertyHint.Range, "0,0.2,0.01,or_greater")] public float DashSpeed { get; set; } = 0.05f; + [Export(PropertyHint.Range, "0,1000,1,or_greater")] + public float PostDashSpeed { get; set; } = 0f; private Node3D _head; private ShapeCast3D _dashCast3D; private Camera3D _camera; private TweenQueueSystem _tweenQueueSystem; + private Vector3 _dashDirection = Vector3.Zero; private MantleSystem _mantleSystem; private MeshInstance3D _dashTarget; diff --git a/systems/move/MoveSystem.cs b/systems/move/MoveSystem.cs index 9602453..554e475 100644 --- a/systems/move/MoveSystem.cs +++ b/systems/move/MoveSystem.cs @@ -18,7 +18,8 @@ public partial class MoveSystem : Node3D Vector3 MovementDirection, bool IsOnFloor, bool IsDead, - bool IsHeadTouchingCeiling + bool IsHeadTouchingCeiling, + bool isHanging ); [Export(PropertyHint.Range, "0,20,0.1,or_greater")] @@ -30,14 +31,14 @@ public partial class MoveSystem : Node3D [Export(PropertyHint.Range, "0,100,0.1,or_greater")] public float _currentSpeed; - private const float DecelerationSpeedFactorFloor = 15.0f; - private const float DecelerationSpeedFactorAir = 7.0f; + private const float DecelerationSpeedFactorFloor = 5.0f; + private const float DecelerationSpeedFactorAir = 1.0f; public float CrouchTransitionSpeed { get; set; } = 20.0f; [Export(PropertyHint.Range, "0,5,0.1,or_greater")] public float DoubleJumpSpeedFactor { get; set; } = 2f; - private bool _canDoubleJump = true; + public bool CanDoubleJump { get; set; } = true; private float _lastFrameWasOnFloor = -Mathf.Inf; private Gravity _gravity; @@ -60,10 +61,17 @@ public partial class MoveSystem : Node3D public void MoveAround(MoveAroundParameters param) { - var (delta, movementDirection, isOnFloor, isDead, isHeadTouchingCeiling) = param; + var (delta, movementDirection, isOnFloor, isDead, isHeadTouchingCeiling, isHanging) = param; var doesCapsuleHaveCrouchingHeight = _capsuleCollider.IsCrouchingHeight(); var doesCapsuleHaveDefaultHeight = _capsuleCollider.IsDefaultHeight(); + + if (isHanging) + { + _parent.Velocity = Vector3.Zero; + _parent.MoveAndSlide(); + return; + } // Adding the gravity if (!isOnFloor) @@ -77,7 +85,7 @@ public partial class MoveSystem : Node3D if (isOnFloor) { _lastFrameWasOnFloor = Engine.GetPhysicsFrames(); - _canDoubleJump = true; + CanDoubleJump = true; } // The code below is required to quickly adjust player's position on Y-axis when there's a ceiling on the @@ -181,9 +189,9 @@ public partial class MoveSystem : Node3D y: _gravity.CalculateJumpForce(), z: _parent.Velocity.Z); } - else if (_canDoubleJump) + else if (CanDoubleJump) { - _canDoubleJump = false; + CanDoubleJump = false; _parent.Velocity = new Vector3( x: _parent.Velocity.X, y: _gravity.CalculateJumpForce() * DoubleJumpSpeedFactor, diff --git a/systems/weapon/WeaponSystem.cs b/systems/weapon/WeaponSystem.cs index 903d4a3..dd3b4f4 100644 --- a/systems/weapon/WeaponSystem.cs +++ b/systems/weapon/WeaponSystem.cs @@ -1,4 +1,5 @@ using Godot; +using GodotStateCharts; namespace Movementtests.systems; @@ -9,6 +10,11 @@ public partial class WeaponSystem : RigidBody3D [Export(PropertyHint.Range, "0,0.2,0.01,or_greater")] public float StraightThrowDuration { get; set; } = 0.1f; + private StateChart _weaponState; + public StateChartState InHandState; + public StateChartState FlyingState; + public StateChartState PlantedState; + private Node3D _head; private ShapeCast3D _dashCast3D; private Camera3D _camera; @@ -19,21 +25,31 @@ public partial class WeaponSystem : RigidBody3D private Vector3 _throwDirection; private Vector3 _plantLocation; private Vector3 _plantNormal; + public Vector3 PlayerDashLocation { get; set; } public void Init(Node3D head, Camera3D camera) { _head = head; _camera = camera; + _weaponState = StateChart.Of(GetNode("StateChart")); + InHandState = StateChartState.Of(GetNode("StateChart/Root/InHand")); + FlyingState = StateChartState.Of(GetNode("StateChart/Root/Flying")); + PlantedState = StateChartState.Of(GetNode("StateChart/Root/Planted")); + _tweenQueueSystem = GetNode("TweenQueueSystem"); _tweenQueueSystem.Init(this); _startTransform = Transform; Freeze = true; + + BodyEntered += OnThrownWeaponReachesGround; } public void ThrowWeapon(Vector3 end, bool hasHit, Vector3 collisionLocation, Vector3 collisionNormal) { + _weaponState.SendEvent("throw"); + _throwDirection = (end - GlobalPosition).Normalized(); _plantLocation = collisionLocation; _plantNormal = collisionNormal; @@ -54,6 +70,7 @@ public partial class WeaponSystem : RigidBody3D public void PlantWeaponInWall() { + _weaponState.SendEvent("plant"); Freeze = true; GlobalPosition = _plantLocation; LookAt(GlobalTransform.Origin + _plantNormal, Vector3.Up, true); @@ -61,6 +78,7 @@ public partial class WeaponSystem : RigidBody3D public void ResetWeapon() { + _weaponState.SendEvent("recover"); Transform = _startTransform; Freeze = true; } @@ -68,10 +86,12 @@ public partial class WeaponSystem : RigidBody3D public override void _IntegrateForces(PhysicsDirectBodyState3D state) { base._IntegrateForces(state); + PlayerDashLocation = GlobalPosition; if (!Freeze && state.GetContactCount() > 0) { _plantLocation = state.GetContactLocalPosition(0); _plantNormal = state.GetContactLocalNormal(0); + PlayerDashLocation = _plantLocation + _plantNormal * 0.1f; } } diff --git a/systems/weapon/weapon.tscn b/systems/weapon/weapon.tscn index f37524a..aa70ec3 100644 --- a/systems/weapon/weapon.tscn +++ b/systems/weapon/weapon.tscn @@ -1,7 +1,11 @@ -[gd_scene load_steps=5 format=3 uid="uid://ckm3d6k08a72u"] +[gd_scene load_steps=9 format=3 uid="uid://ckm3d6k08a72u"] [ext_resource type="Script" uid="uid://iii3wfto4t5b" path="res://systems/weapon/WeaponSystem.cs" id="1_csqwk"] [ext_resource type="PackedScene" uid="uid://dbe5f0p6lvqtr" path="res://systems/tween_queue/tween_queue_system.tscn" id="2_x1nha"] +[ext_resource type="Script" uid="uid://couw105c3bde4" path="res://addons/godot_state_charts/state_chart.gd" id="3_5owyf"] +[ext_resource type="Script" uid="uid://jk2jm1g6q853" path="res://addons/godot_state_charts/compound_state.gd" id="4_svc06"] +[ext_resource type="Script" uid="uid://cytafq8i1y8qm" path="res://addons/godot_state_charts/atomic_state.gd" id="5_m0v1h"] +[ext_resource type="Script" uid="uid://cf1nsco3w0mf6" path="res://addons/godot_state_charts/transition.gd" id="6_jpdh0"] [sub_resource type="CylinderShape3D" id="CylinderShape3D_avini"] height = 1.0 @@ -29,4 +33,43 @@ shape = SubResource("CylinderShape3D_avini") transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0) mesh = SubResource("CylinderMesh_x1nha") -[connection signal="body_entered" from="." to="." method="OnThrownWeaponReachesGround"] +[node name="StateChart" type="Node" parent="."] +script = ExtResource("3_5owyf") +metadata/_custom_type_script = "uid://couw105c3bde4" + +[node name="Root" type="Node" parent="StateChart"] +script = ExtResource("4_svc06") +initial_state = NodePath("InHand") + +[node name="InHand" type="Node" parent="StateChart/Root"] +script = ExtResource("5_m0v1h") + +[node name="ToFlying" type="Node" parent="StateChart/Root/InHand"] +script = ExtResource("6_jpdh0") +to = NodePath("../../Flying") +event = &"throw" +delay_in_seconds = "0.0" + +[node name="Flying" type="Node" parent="StateChart/Root"] +script = ExtResource("5_m0v1h") + +[node name="ToHand" type="Node" parent="StateChart/Root/Flying"] +script = ExtResource("6_jpdh0") +to = NodePath("../../InHand") +event = &"recover" +delay_in_seconds = "0.0" + +[node name="ToPlanted" type="Node" parent="StateChart/Root/Flying"] +script = ExtResource("6_jpdh0") +to = NodePath("../../Planted") +event = &"plant" +delay_in_seconds = "0.0" + +[node name="Planted" type="Node" parent="StateChart/Root"] +script = ExtResource("5_m0v1h") + +[node name="ToHand" type="Node" parent="StateChart/Root/Planted"] +script = ExtResource("6_jpdh0") +to = NodePath("../../InHand") +event = &"recover" +delay_in_seconds = "0.0"