From 178553956d87cebe6cfe3faba8be79fbfe6b1335 Mon Sep 17 00:00:00 2001 From: Minimata Date: Mon, 2 Jun 2025 17:58:40 +0200 Subject: [PATCH] refacto: moved systems from player controller physics process to their own signal based systems --- player_controller/PlayerController.tscn | 35 ++- player_controller/Scripts/Gravity.cs | 4 +- player_controller/Scripts/PlayerController.cs | 263 +++--------------- systems/inputs/input_system.gd | 6 + systems/inputs/walk_mode/base_mode.tres | 39 ++- systems/inputs/walk_mode/jump.tres | 14 + systems/mantle/MantleSystem.cs | 18 +- systems/mantle/mantle_system.tscn | 2 +- systems/move/MoveSystem.cs | 184 ++++++++++++ systems/move/MoveSystem.cs.uid | 1 + systems/tween_queue/TweenQueueSystem.cs | 52 ++++ systems/tween_queue/TweenQueueSystem.cs.uid | 1 + systems/tween_queue/tween_queue_system.tscn | 6 + 13 files changed, 377 insertions(+), 248 deletions(-) create mode 100644 systems/inputs/walk_mode/jump.tres create mode 100644 systems/move/MoveSystem.cs create mode 100644 systems/move/MoveSystem.cs.uid create mode 100644 systems/tween_queue/TweenQueueSystem.cs create mode 100644 systems/tween_queue/TweenQueueSystem.cs.uid create mode 100644 systems/tween_queue/tween_queue_system.tscn diff --git a/player_controller/PlayerController.tscn b/player_controller/PlayerController.tscn index 35642ee..478d081 100644 --- a/player_controller/PlayerController.tscn +++ b/player_controller/PlayerController.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=26 format=3 uid="uid://bei4nhkf8lwdo"] +[gd_scene load_steps=28 format=3 uid="uid://bei4nhkf8lwdo"] [ext_resource type="Script" uid="uid://bbbrf5ckydfna" path="res://player_controller/Scripts/PlayerController.cs" id="1_poq2x"] [ext_resource type="Resource" uid="uid://bl5crtu1gkrtr" path="res://systems/inputs/walk_mode/base_mode.tres" id="3_cresl"] @@ -14,12 +14,14 @@ [ext_resource type="Resource" uid="uid://7wm8ywvujwf" path="res://systems/inputs/walk_mode/aim_cancel.tres" id="9_5p2qc"] [ext_resource type="Script" uid="uid://bt0xv2q8iv1vn" path="res://player_controller/Scripts/Gravity.cs" id="9_lsueh"] [ext_resource type="Script" uid="uid://dwoppk8j5fxeg" path="res://player_controller/Scripts/DashSystem.cs" id="9_qu4wy"] +[ext_resource type="Resource" uid="uid://bdit2jy5gbpts" path="res://systems/inputs/walk_mode/jump.tres" id="10_4u7i3"] [ext_resource type="Script" uid="uid://g8idirw62qe0" path="res://player_controller/Scripts/Bobbing.cs" id="10_7wk1w"] -[ext_resource type="Script" uid="uid://c6bx47wr7fbdm" path="res://player_controller/Scripts/Mouse.cs" id="11_huhen"] [ext_resource type="PackedScene" uid="uid://0ysqmqphq6mq" path="res://systems/head/head_system.tscn" id="11_rxwoh"] [ext_resource type="Script" uid="uid://b6k73aj5povgv" path="res://player_controller/Scripts/FieldOfView.cs" id="12_m2mxi"] [ext_resource type="Script" uid="uid://b5nk6ntlps3x0" path="res://systems/inputs/input_system.gd" id="16_v31n3"] [ext_resource type="Resource" uid="uid://htqvokm8mufq" path="res://systems/inputs/walk_mode/move.tres" id="17_h6vvl"] +[ext_resource type="Script" uid="uid://dyy5njw6pxoh4" path="res://systems/move/MoveSystem.cs" id="20_rxwoh"] +[ext_resource type="PackedScene" uid="uid://dbe5f0p6lvqtr" path="res://systems/tween_queue/tween_queue_system.tscn" id="22_rpwev"] [sub_resource type="CapsuleMesh" id="CapsuleMesh_xc2g5"] @@ -33,8 +35,6 @@ [node name="Player" type="CharacterBody3D"] script = ExtResource("1_poq2x") -WalkSpeed = 10.0 -SprintSpeed = 15.0 [node name="InputController" type="Node3D" parent="."] script = ExtResource("16_v31n3") @@ -45,6 +45,7 @@ rotate_floorplane = ExtResource("5_4u7i3") aim_pressed = ExtResource("7_cresl") aim_released = ExtResource("8_lhb11") aim_canceled = ExtResource("9_5p2qc") +jump = ExtResource("10_4u7i3") [node name="MeshInstance3D" type="MeshInstance3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) @@ -64,6 +65,9 @@ script = ExtResource("5_umw0l") [node name="Stamina" type="Node3D" parent="."] script = ExtResource("6_lxtc4") +[node name="StairsSystem" type="Node3D" parent="."] +script = ExtResource("7_bmt5a") + [node name="StairsAheadRayCast3D" type="RayCast3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, -0.828) target_position = Vector3(0, -0.55, 0) @@ -94,19 +98,9 @@ surface_material_override/0 = SubResource("StandardMaterial3D_v31n3") MantleEndLocationDistanceFromWall = 1.0 MantleHeightCastStart = 2.0 -[node name="StairsSystem" type="Node3D" parent="."] -script = ExtResource("7_bmt5a") - -[node name="Gravity" type="Node3D" parent="."] -script = ExtResource("9_lsueh") -AdditionalGravityPower = 5.0 - [node name="Bobbing" type="Node3D" parent="."] script = ExtResource("10_7wk1w") -[node name="Mouse" type="Node3D" parent="."] -script = ExtResource("11_huhen") - [node name="FieldOfView" type="Node3D" parent="."] script = ExtResource("12_m2mxi") @@ -128,9 +122,22 @@ target_position = Vector3(0, 1, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.296, 1.4, 0) target_position = Vector3(0, 1, 0) +[node name="MoveSystem" type="Node3D" parent="."] +script = ExtResource("20_rxwoh") +WalkSpeed = 10.0 +SprintSpeed = 15.0 + +[node name="Gravity" type="Node3D" parent="."] +script = ExtResource("9_lsueh") +Weight = 10.0 +StartVelocity = 4.0 + +[node name="TweenQueueSystem" parent="." instance=ExtResource("22_rpwev")] + [connection signal="input_aim_canceled" from="InputController" to="." method="OnInputAimCanceled"] [connection signal="input_aim_pressed" from="InputController" to="." method="OnInputAimPressed"] [connection signal="input_aim_released" from="InputController" to="." method="OnInputAimReleased"] +[connection signal="input_jump" from="InputController" to="." method="OnInputJumpPressed"] [connection signal="input_move" from="InputController" to="." method="OnInputMove"] [connection signal="input_rotate_floorplane" from="InputController" to="." method="OnInputRotateFloorplane"] [connection signal="input_rotate_y" from="InputController" to="." method="OnInputRotateY"] diff --git a/player_controller/Scripts/Gravity.cs b/player_controller/Scripts/Gravity.cs index ff3f030..6952b17 100644 --- a/player_controller/Scripts/Gravity.cs +++ b/player_controller/Scripts/Gravity.cs @@ -18,6 +18,6 @@ public partial class Gravity: Node3D _gravity = gravitySetting; } - public float CalculateJumpForce() => Weight * (_gravity * (StartVelocity / AdditionalGravityPower)); - public float CalculateGravityForce() => _gravity * Weight / 30.0f; + public float CalculateJumpForce() => _gravity * (StartVelocity / AdditionalGravityPower); + public float CalculateGravityForce() => _gravity * Weight; } diff --git a/player_controller/Scripts/PlayerController.cs b/player_controller/Scripts/PlayerController.cs index 951ef3a..e244766 100644 --- a/player_controller/Scripts/PlayerController.cs +++ b/player_controller/Scripts/PlayerController.cs @@ -18,37 +18,15 @@ public partial class PlayerController : CharacterBody3D public CapsuleCollider CapsuleCollider; public Gravity Gravity; public HealthSystem HealthSystem; - + public MoveSystem MoveSystem; + public TweenQueueSystem TweenQueueSystem; - [Export(PropertyHint.Range, "0,20,0.1,or_greater")] - public float WalkSpeed { get; set; } = 5.0f; - [Export(PropertyHint.Range, "0,20,0.1,or_greater")] - public float SprintSpeed { get; set; } = 7.2f; - [Export(PropertyHint.Range, "0,10,0.1,or_greater")] - public float CrouchSpeed { get; set; } = 2.5f; - [Export(PropertyHint.Range, "0,100,0.1,or_greater")] - 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; private bool _movementEnabled = true; - private bool _isTweening = false; - private record TweenInputs(Vector3 Location, float Duration); - - private Queue _tweenInputs = new Queue(); - private bool _shouldMantle = false; private Vector3 _dashLocation = Vector3.Zero; private Vector3 _mantleLocation = Vector3.Zero; - private float _currentSpeed; - - private const float DecelerationSpeedFactorFloor = 15.0f; - private const float DecelerationSpeedFactorAir = 7.0f; - private float _lastFrameWasOnFloor = -Mathf.Inf; private const int NumOfHeadCollisionDetectors = 4; @@ -91,12 +69,18 @@ public partial class PlayerController : CharacterBody3D GD.Print("Aim canceled"); } + public void OnInputJumpPressed() + { + bool doesCapsuleHaveCrouchingHeight = CapsuleCollider.IsCrouchingHeight(); + bool isPlayerDead = HealthSystem.IsDead(); + + if (!doesCapsuleHaveCrouchingHeight && !isPlayerDead) + MoveSystem.Jump(IsOnFloor()); + } public override void _Ready() { - _currentSpeed = WalkSpeed; - HeadSystem = GetNode("HeadSystem"); HeadSystem.Init(); @@ -137,23 +121,31 @@ public partial class PlayerController : CharacterBody3D FieldOfView = GetNode("FieldOfView"); FieldOfView.Init(camera); - Stamina = GetNode("Stamina"); - Stamina.SetSpeeds(WalkSpeed, SprintSpeed); - - StairsSystem = GetNode("StairsSystem"); - StairsSystem.Init(stairsBelowRayCast3D, stairsAheadRayCast3D, cameraSmooth); - - MantleSystem = GetNode("MantleSystem"); - MantleSystem.Init(HeadSystem); - - DashSystem = GetNode("DashSystem"); - DashSystem.Init(HeadSystem, camera); - CapsuleCollider = GetNode("CapsuleCollider"); Gravity = GetNode("Gravity"); Gravity.Init(gravitySetting); + MantleSystem = GetNode("MantleSystem"); + MantleSystem.Init(HeadSystem); + + TweenQueueSystem = GetNode("TweenQueueSystem"); + TweenQueueSystem.Init(this); + + MoveSystem = GetNode("MoveSystem"); + var moveSystemParams = new MoveSystem.MoveSystemParameters(this, Gravity, MantleSystem, TweenQueueSystem, + HeadSystem, CapsuleCollider); + MoveSystem.Init(moveSystemParams); + + Stamina = GetNode("Stamina"); + Stamina.SetSpeeds(MoveSystem.WalkSpeed, MoveSystem.SprintSpeed); + + StairsSystem = GetNode("StairsSystem"); + StairsSystem.Init(stairsBelowRayCast3D, stairsAheadRayCast3D, cameraSmooth); + + DashSystem = GetNode("DashSystem"); + DashSystem.Init(HeadSystem, camera); + HealthSystem = GetNode("HealthSystem"); HealthSystem.HealthSystemInitParams healthSystemParams = new HealthSystem.HealthSystemInitParams() @@ -170,50 +162,9 @@ public partial class PlayerController : CharacterBody3D HealthSystem.Init(healthSystemParams); } - private void DisableMovement() - { - _movementEnabled = false; - } - public void EnableMovement() - { - _movementEnabled = true; - } - - public void EndTween() - { - EnableMovement(); - _isTweening = false; - } - - private void TweenToLocation(TweenInputs inputs) - { - var (location, duration) = inputs; - - var tween = GetTree().CreateTween(); - var callback = new Callable(this, MethodName.EndTween); - - tween.TweenProperty(this, "position", location, duration); - tween.TweenCallback(callback); - - DisableMovement(); - _isTweening = true; - tween.Play(); - } - - private void QueueTween(TweenInputs inputs) - { - _tweenInputs.Enqueue(inputs); - } - - private void QueueTween(Vector3 location, float duration) - { - QueueTween(new TweenInputs(location, duration)); - } - public override void _PhysicsProcess(double delta) { - if (_tweenInputs.Count > 0 && !_isTweening) - TweenToLocation(_tweenInputs.Dequeue()); + TweenQueueSystem.ProcessTweens(); if (Input.IsActionPressed("aim_dash")) { @@ -223,154 +174,20 @@ public partial class PlayerController : CharacterBody3D if (Input.IsActionJustReleased("aim_dash")) { DashSystem.Dash(); - QueueTween(_dashLocation, 0.1f); + TweenQueueSystem.QueueTween(_dashLocation, 0.1f); if (_shouldMantle) { - QueueTween(_mantleLocation, 0.1f); - } - } - - var mantleLocationResult = MantleSystem.FindMantleInFrontOfPlayer(); - if (isOnFloorCustom()) - { - _lastFrameWasOnFloor = Engine.GetPhysicsFrames(); - _canDoubleJump = true; - } - - // Adding the gravity - if (!isOnFloorCustom()) - { - Velocity = new Vector3( - x: Velocity.X, - y: Velocity.Y - (Gravity.CalculateGravityForce() * (float)delta), - z: Velocity.Z); - } - - bool doesCapsuleHaveCrouchingHeight = CapsuleCollider.IsCrouchingHeight(); - - bool isPlayerDead = HealthSystem.IsDead(); - - // Handle Jump input - if (Input.IsActionJustPressed("jump") - && !doesCapsuleHaveCrouchingHeight - && !isPlayerDead) - { - if (mantleLocationResult.IsSome(out var mantleLocation)) - { - var duration = 0.1f * mantleLocation.DistanceTo(Position); - QueueTween(mantleLocation, duration); - } - else if (isOnFloorCustom()) - { - Velocity = new Vector3( - x: Velocity.X, - y: Gravity.CalculateJumpForce() * (float)delta, - z: Velocity.Z); - } - else if (!isOnFloorCustom() - && _canDoubleJump) - { - _canDoubleJump = false; - Velocity = new Vector3( - x: Velocity.X, - y: Gravity.CalculateJumpForce() * (float)delta * DoubleJumpSpeedFactor, - z: Velocity.Z); - } - } - - bool isHeadTouchingCeiling = IsHeadTouchingCeiling(); - bool doesCapsuleHaveDefaultHeight = CapsuleCollider.IsDefaultHeight(); - - // The code below is required to quickly adjust player's position on Y-axis when there's a ceiling on the - // trajectory of player's jump and player is standing - if (isHeadTouchingCeiling && doesCapsuleHaveDefaultHeight) - { - Velocity = new Vector3( - x: Velocity.X, - y: Velocity.Y - 2.0f, - z: Velocity.Z); - } - - if (!isPlayerDead) - { - - // Used both for detecting the moment when we enter into crouching mode and the moment when we're already - // in the crouching mode - if (Input.IsActionPressed("crouch") || - (doesCapsuleHaveCrouchingHeight && isHeadTouchingCeiling)) - { - CapsuleCollider.Crouch((float)delta, CrouchTransitionSpeed); - _currentSpeed = CrouchSpeed; - } - // Used both for the moment when we exit the crouching mode and for the moment when we just walk - else - { - CapsuleCollider.UndoCrouching((float)delta, CrouchTransitionSpeed); - _currentSpeed = WalkSpeed; + TweenQueueSystem.QueueTween(_mantleLocation, 0.1f); } } - // Each component of the boolean statement for sprinting is required - if (Input.IsActionPressed("sprint") && !isHeadTouchingCeiling && - !doesCapsuleHaveCrouchingHeight && !isPlayerDead) - { - _currentSpeed = SprintSpeed; - } - + var isPlayerDead = HealthSystem.IsDead(); + var isHeadTouchingCeiling = IsHeadTouchingCeiling(); + + MoveSystem.MoveAround(delta, _inputMove, isOnFloorCustom(), isPlayerDead, isHeadTouchingCeiling); Vector2 inputLookDir = new Vector2(_inputRotateY, _inputRotateFloorplane); HeadSystem.LookAround(inputLookDir); - // Basis is a 3x4 matrix. It contains information about scaling and rotation of head. - // By multiplying our Vector3 by this matrix we're doing multiple things: - // a) We start to operate in global space; - // b) We're applying to Vector3 the current rotation of "head" object; - // c) We're applying to Vector3 the current scaling of "head" object; - Vector3 direction = HeadSystem.Transform.Basis * _inputMove; - - if (isPlayerDead) - { - direction = Vector3.Zero; - } - - if (isOnFloorCustom()) - { - // Set velocity based on input direction when on the floor - if (direction.Length() > 0) - { - float availableSpeed = Stamina.AccountStamina(delta, _currentSpeed); - - float newX = direction.X * availableSpeed; - float newZ = direction.Z * availableSpeed; - - Velocity = new Vector3(newX, Velocity.Y, newZ); - } - // If there is no input, smoothly decelerate the character on the floor - else - { - float xDeceleration = Mathf.Lerp(Velocity.X, direction.X * _currentSpeed, - (float)delta * DecelerationSpeedFactorFloor); - float zDeceleration = Mathf.Lerp(Velocity.Z, direction.Z * _currentSpeed, - (float)delta * DecelerationSpeedFactorFloor); - - Velocity = new Vector3(xDeceleration, Velocity.Y, zDeceleration); - } - } - else - { - float xDeceleration = Mathf.Lerp(Velocity.X, direction.X * _currentSpeed, - (float)delta * DecelerationSpeedFactorAir); - float zDeceleration = Mathf.Lerp(Velocity.Z, direction.Z * _currentSpeed, - (float)delta * DecelerationSpeedFactorAir); - - Velocity = new Vector3(xDeceleration, Velocity.Y, zDeceleration); - } - - if (isPlayerDead) - { - MoveAndSlide(); - return; - } - Bobbing.CameraBobbingParams cameraBobbingParams = new Bobbing.CameraBobbingParams { Delta = (float)delta, @@ -384,7 +201,7 @@ public partial class PlayerController : CharacterBody3D { IsCrouchingHeight = CapsuleCollider.IsCrouchingHeight(), Delta = (float)delta, - SprintSpeed = SprintSpeed, + SprintSpeed = MoveSystem.SprintSpeed, Velocity = Velocity }; @@ -394,7 +211,7 @@ public partial class PlayerController : CharacterBody3D { IsOnFloorCustom = isOnFloorCustom(), IsCapsuleHeightLessThanNormal = CapsuleCollider.IsCapsuleHeightLessThanNormal(), - CurrentSpeedGreaterThanWalkSpeed = _currentSpeed > WalkSpeed, + CurrentSpeedGreaterThanWalkSpeed = MoveSystem._currentSpeed > MoveSystem.WalkSpeed, IsCrouchingHeight = CapsuleCollider.IsCrouchingHeight(), Delta = (float)delta, FloorMaxAngle = FloorMaxAngle, @@ -443,7 +260,7 @@ public partial class PlayerController : CharacterBody3D StairsSystem.SlideCameraParams slideCameraParams = new StairsSystem.SlideCameraParams { IsCapsuleHeightLessThanNormal = CapsuleCollider.IsCapsuleHeightLessThanNormal(), - CurrentSpeedGreaterThanWalkSpeed = _currentSpeed > WalkSpeed, + CurrentSpeedGreaterThanWalkSpeed = MoveSystem._currentSpeed > MoveSystem.WalkSpeed, BetweenCrouchingAndNormalHeight = CapsuleCollider.IsBetweenCrouchingAndNormalHeight(), Delta = (float)delta }; diff --git a/systems/inputs/input_system.gd b/systems/inputs/input_system.gd index 3575515..58f12d7 100644 --- a/systems/inputs/input_system.gd +++ b/systems/inputs/input_system.gd @@ -12,6 +12,7 @@ extends Node3D @export var aim_pressed:GUIDEAction @export var aim_released:GUIDEAction @export var aim_canceled:GUIDEAction +@export var jump:GUIDEAction signal input_move(value: Vector3) signal input_rotate_y(value: float) @@ -20,6 +21,7 @@ signal input_rotate_floorplane(value: float) signal input_aim_pressed signal input_aim_released signal input_aim_canceled +signal input_jump func _ready() -> void: GUIDE.enable_mapping_context(base_mode) @@ -27,8 +29,12 @@ func _ready() -> void: aim_pressed.triggered.connect(on_input_aim_pressed) aim_released.triggered.connect(on_input_aim_released) aim_canceled.triggered.connect(on_input_aim_canceled) + jump.triggered.connect(on_input_jump) +func on_input_jump(): + input_jump.emit() + func on_input_aim_pressed(): input_aim_pressed.emit() diff --git a/systems/inputs/walk_mode/base_mode.tres b/systems/inputs/walk_mode/base_mode.tres index ba60197..55aae55 100644 --- a/systems/inputs/walk_mode/base_mode.tres +++ b/systems/inputs/walk_mode/base_mode.tres @@ -1,4 +1,4 @@ -[gd_resource type="Resource" script_class="GUIDEMappingContext" load_steps=53 format=3 uid="uid://bl5crtu1gkrtr"] +[gd_resource type="Resource" script_class="GUIDEMappingContext" load_steps=58 format=3 uid="uid://bl5crtu1gkrtr"] [ext_resource type="Script" uid="uid://cpplm41b5bt6m" path="res://addons/guide/guide_action_mapping.gd" id="1_0pi3k"] [ext_resource type="Script" uid="uid://dsa1dnifd6w32" path="res://addons/guide/guide_mapping_context.gd" id="2_ho3ad"] @@ -22,6 +22,7 @@ [ext_resource type="Script" uid="uid://rvttn472ix6v" path="res://addons/guide/inputs/guide_input_joy_button.gd" id="19_2murt"] [ext_resource type="Script" uid="uid://brsxcrai2te83" path="res://addons/guide/triggers/guide_trigger_chorded_action.gd" id="20_xcfo4"] [ext_resource type="Script" uid="uid://b52rqq28tuqpg" path="res://addons/guide/triggers/guide_trigger_pressed.gd" id="21_k8ji4"] +[ext_resource type="Resource" uid="uid://bdit2jy5gbpts" path="res://systems/inputs/walk_mode/jump.tres" id="22_ufouq"] [sub_resource type="Resource" id="Resource_vkvga"] script = ExtResource("4_oapce") @@ -52,6 +53,7 @@ triggers = Array[ExtResource("8_nf3uo")]([]) script = ExtResource("1_0pi3k") action = ExtResource("2_p4e1v") input_mappings = Array[ExtResource("3_ufouq")]([SubResource("Resource_1igva")]) +metadata/_guide_input_mappings_collapsed = false [sub_resource type="Resource" id="Resource_05q5j"] script = ExtResource("10_500v3") @@ -88,6 +90,7 @@ triggers = Array[ExtResource("8_nf3uo")]([]) script = ExtResource("1_0pi3k") action = ExtResource("9_paxxe") input_mappings = Array[ExtResource("3_ufouq")]([SubResource("Resource_dew8i")]) +metadata/_guide_input_mappings_collapsed = true [sub_resource type="Resource" id="Resource_pf0ii"] script = ExtResource("10_500v3") @@ -124,8 +127,9 @@ triggers = Array[ExtResource("8_nf3uo")]([]) script = ExtResource("1_0pi3k") action = ExtResource("13_3y0c4") input_mappings = Array[ExtResource("3_ufouq")]([SubResource("Resource_qu2wi")]) +metadata/_guide_input_mappings_collapsed = true -[sub_resource type="Resource" id="Resource_lg6ir"] +[sub_resource type="Resource" id="Resource_ufouq"] script = ExtResource("10_500v3") axis = 4 joy_index = -1 @@ -140,7 +144,7 @@ override_action_settings = false is_remappable = false display_name = "" display_category = "" -input = SubResource("Resource_lg6ir") +input = SubResource("Resource_ufouq") modifiers = Array[ExtResource("5_j3mg7")]([]) triggers = Array[ExtResource("8_nf3uo")]([SubResource("Resource_n42ky")]) @@ -148,6 +152,7 @@ triggers = Array[ExtResource("8_nf3uo")]([SubResource("Resource_n42ky")]) script = ExtResource("1_0pi3k") action = ExtResource("14_bi271") input_mappings = Array[ExtResource("3_ufouq")]([SubResource("Resource_qbthx")]) +metadata/_guide_input_mappings_collapsed = false [sub_resource type="Resource" id="Resource_cqc4k"] script = ExtResource("10_500v3") @@ -172,6 +177,7 @@ triggers = Array[ExtResource("8_nf3uo")]([SubResource("Resource_vanwy")]) script = ExtResource("1_0pi3k") action = ExtResource("16_34gm1") input_mappings = Array[ExtResource("3_ufouq")]([SubResource("Resource_bkx7d")]) +metadata/_guide_input_mappings_collapsed = true [sub_resource type="Resource" id="Resource_lfx76"] script = ExtResource("19_2murt") @@ -202,8 +208,33 @@ script = ExtResource("1_0pi3k") action = ExtResource("18_4dlli") input_mappings = Array[ExtResource("3_ufouq")]([SubResource("Resource_4ee3d")]) +[sub_resource type="Resource" id="Resource_oapce"] +script = ExtResource("19_2murt") +button = 0 +joy_index = -1 + +[sub_resource type="Resource" id="Resource_j3mg7"] +script = ExtResource("21_k8ji4") +actuation_threshold = 0.5 + +[sub_resource type="Resource" id="Resource_8w5gu"] +script = ExtResource("3_ufouq") +override_action_settings = false +is_remappable = false +display_name = "" +display_category = "" +input = SubResource("Resource_oapce") +modifiers = Array[ExtResource("5_j3mg7")]([]) +triggers = Array[ExtResource("8_nf3uo")]([SubResource("Resource_j3mg7")]) +metadata/_guide_triggers_collapsed = false + +[sub_resource type="Resource" id="Resource_xt1x5"] +script = ExtResource("1_0pi3k") +action = ExtResource("22_ufouq") +input_mappings = Array[ExtResource("3_ufouq")]([SubResource("Resource_8w5gu")]) + [resource] script = ExtResource("2_ho3ad") display_name = "" -mappings = Array[ExtResource("1_0pi3k")]([SubResource("Resource_88x08"), SubResource("Resource_tgr2g"), SubResource("Resource_iarn8"), SubResource("Resource_0hmrk"), SubResource("Resource_iihs4"), SubResource("Resource_0s4kt")]) +mappings = Array[ExtResource("1_0pi3k")]([SubResource("Resource_88x08"), SubResource("Resource_tgr2g"), SubResource("Resource_iarn8"), SubResource("Resource_0hmrk"), SubResource("Resource_iihs4"), SubResource("Resource_0s4kt"), SubResource("Resource_xt1x5")]) metadata/_custom_type_script = "uid://dsa1dnifd6w32" diff --git a/systems/inputs/walk_mode/jump.tres b/systems/inputs/walk_mode/jump.tres new file mode 100644 index 0000000..6c231be --- /dev/null +++ b/systems/inputs/walk_mode/jump.tres @@ -0,0 +1,14 @@ +[gd_resource type="Resource" script_class="GUIDEAction" load_steps=2 format=3 uid="uid://bdit2jy5gbpts"] + +[ext_resource type="Script" uid="uid://cluhc11vixkf1" path="res://addons/guide/guide_action.gd" id="1_pxv2l"] + +[resource] +script = ExtResource("1_pxv2l") +name = &"" +action_value_type = 0 +block_lower_priority_actions = true +emit_as_godot_actions = false +is_remappable = false +display_name = "" +display_category = "" +metadata/_custom_type_script = "uid://cluhc11vixkf1" diff --git a/systems/mantle/MantleSystem.cs b/systems/mantle/MantleSystem.cs index 8a171c6..49bf518 100644 --- a/systems/mantle/MantleSystem.cs +++ b/systems/mantle/MantleSystem.cs @@ -17,6 +17,8 @@ public partial class MantleSystem: Node3D private ShapeCast3D _wallInFrontCast3D; private ShapeCast3D _mantleCast3D; private RayCast3D _mantleCheckCast3D; + + private Option _mantleLocation; public void Init(Node3D head) { @@ -25,21 +27,29 @@ public partial class MantleSystem: Node3D _mantleCast3D = GetNode("MantleCast3D"); } - public Option FindMantleInFrontOfPlayer() + public override void _PhysicsProcess(double delta) { + base._PhysicsProcess(delta); + _wallInFrontCast3D.SetRotation(new Vector3( _wallInFrontCast3D.Rotation.X, _head.Rotation.Y, _wallInFrontCast3D.Rotation.Z)); - + if (!_wallInFrontCast3D.IsColliding()) { - return Option.None; + _mantleLocation = Option.None; + return; } var collisionPoint = _wallInFrontCast3D.GetCollisionPoint(0); var collisionNormal = _wallInFrontCast3D.GetCollisionNormal(0); - return FindMantleLocationAtPoint(collisionPoint, collisionNormal); + _mantleLocation = FindMantleLocationAtPoint(collisionPoint, collisionNormal); + } + + public Option FindMantleInFrontOfPlayer() + { + return _mantleLocation; } public Option FindMantleLocationAtPoint(Vector3 point, Vector3 wallNormal) diff --git a/systems/mantle/mantle_system.tscn b/systems/mantle/mantle_system.tscn index 4de928e..4b0ef74 100644 --- a/systems/mantle/mantle_system.tscn +++ b/systems/mantle/mantle_system.tscn @@ -22,7 +22,7 @@ debug_shape_custom_color = Color(1, 0, 0, 1) [node name="WallInFrontCast3D" type="ShapeCast3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) shape = SubResource("CapsuleShape3D_qu4wy") -target_position = Vector3(0, 0, -1.5) +target_position = Vector3(0, 0, -2) max_results = 1 collision_mask = 2 debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1) diff --git a/systems/move/MoveSystem.cs b/systems/move/MoveSystem.cs new file mode 100644 index 0000000..1131d1c --- /dev/null +++ b/systems/move/MoveSystem.cs @@ -0,0 +1,184 @@ +using Godot; +using PolarBears.PlayerControllerAddon; + +public partial class MoveSystem : Node3D +{ + public record MoveSystemParameters( + CharacterBody3D Parent, + Gravity Gravity, + MantleSystem MantleSystem, + TweenQueueSystem TweenQueueSystem, + HeadSystem HeadSystem, + CapsuleCollider CapsuleCollider); + + [Export(PropertyHint.Range, "0,20,0.1,or_greater")] + public float WalkSpeed { get; set; } = 5.0f; + [Export(PropertyHint.Range, "0,20,0.1,or_greater")] + public float SprintSpeed { get; set; } = 7.2f; + [Export(PropertyHint.Range, "0,10,0.1,or_greater")] + public float CrouchSpeed { get; set; } = 2.5f; + [Export(PropertyHint.Range, "0,100,0.1,or_greater")] + + public float _currentSpeed; + private const float DecelerationSpeedFactorFloor = 15.0f; + private const float DecelerationSpeedFactorAir = 7.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; + private float _lastFrameWasOnFloor = -Mathf.Inf; + + private Gravity _gravity; + private CharacterBody3D _parent; + private MantleSystem _mantleSystem; + private TweenQueueSystem _tweenQueueSystem; + private CapsuleCollider _capsuleCollider; + private HeadSystem _headSystem; + public void Init(MoveSystemParameters parameters) + { + _parent = parameters.Parent; + _gravity = parameters.Gravity; + _mantleSystem = parameters.MantleSystem; + _tweenQueueSystem = parameters.TweenQueueSystem; + _capsuleCollider = parameters.CapsuleCollider; + _headSystem = parameters.HeadSystem; + + _currentSpeed = WalkSpeed; + } + + public void MoveAround(double delta, Vector3 movementDirection, bool isOnFloor, bool isDead, bool isHeadTouchingCeiling) + { + var doesCapsuleHaveCrouchingHeight = _capsuleCollider.IsCrouchingHeight(); + var doesCapsuleHaveDefaultHeight = _capsuleCollider.IsDefaultHeight(); + + // Adding the gravity + if (!isOnFloor) + { + _parent.Velocity = new Vector3( + x: _parent.Velocity.X, + y: _parent.Velocity.Y - (_gravity.CalculateGravityForce() * (float)delta), + z: _parent.Velocity.Z); + } + + if (isOnFloor) + { + _lastFrameWasOnFloor = Engine.GetPhysicsFrames(); + _canDoubleJump = true; + } + + // The code below is required to quickly adjust player's position on Y-axis when there's a ceiling on the + // trajectory of player's jump and player is standing + if (isHeadTouchingCeiling && doesCapsuleHaveDefaultHeight) + { + _parent.Velocity = new Vector3( + x: _parent.Velocity.X, + y: _parent.Velocity.Y - 2.0f, + z: _parent.Velocity.Z); + } + + + if (!isDead) + { + + // Used both for detecting the moment when we enter into crouching mode and the moment when we're already + // in the crouching mode + if (Input.IsActionPressed("crouch") || + (doesCapsuleHaveCrouchingHeight && isHeadTouchingCeiling)) + { + _capsuleCollider.Crouch((float)delta, CrouchTransitionSpeed); + _currentSpeed = CrouchSpeed; + } + // Used both for the moment when we exit the crouching mode and for the moment when we just walk + else + { + _capsuleCollider.UndoCrouching((float)delta, CrouchTransitionSpeed); + _currentSpeed = WalkSpeed; + } + } + + // Each component of the boolean statement for sprinting is required + if (Input.IsActionPressed("sprint") && !isHeadTouchingCeiling && + !doesCapsuleHaveCrouchingHeight && !isDead) + { + _currentSpeed = SprintSpeed; + } + + // Basis is a 3x4 matrix. It contains information about scaling and rotation of head. + // By multiplying our Vector3 by this matrix we're doing multiple things: + // a) We start to operate in global space; + // b) We're applying to Vector3 the current rotation of "head" object; + // c) We're applying to Vector3 the current scaling of "head" object; + Vector3 direction = _headSystem.Transform.Basis * movementDirection; + + if (isDead) + { + direction = Vector3.Zero; + } + + + if (isOnFloor) + { + // Set velocity based on input direction when on the floor + if (direction.Length() > 0) + { + float newX = direction.X * _currentSpeed; + float newZ = direction.Z * _currentSpeed; + + _parent.Velocity = new Vector3(newX, _parent.Velocity.Y, newZ); + } + // If there is no input, smoothly decelerate the character on the floor + else + { + float xDeceleration = Mathf.Lerp(_parent.Velocity.X, direction.X * _currentSpeed, + (float)delta * DecelerationSpeedFactorFloor); + float zDeceleration = Mathf.Lerp(_parent.Velocity.Z, direction.Z * _currentSpeed, + (float)delta * DecelerationSpeedFactorFloor); + + _parent.Velocity = new Vector3(xDeceleration, _parent.Velocity.Y, zDeceleration); + } + } + else + { + float xDeceleration = Mathf.Lerp(_parent.Velocity.X, direction.X * _currentSpeed, + (float)delta * DecelerationSpeedFactorAir); + float zDeceleration = Mathf.Lerp(_parent.Velocity.Z, direction.Z * _currentSpeed, + (float)delta * DecelerationSpeedFactorAir); + + _parent.Velocity = new Vector3(xDeceleration, _parent.Velocity.Y, zDeceleration); + } + + if (isDead) + { + _parent.MoveAndSlide(); + return; + } + } + + public void Jump(bool isOnFloor) + { + var mantleLocationResult = _mantleSystem.FindMantleInFrontOfPlayer(); + if (mantleLocationResult.IsSome(out var mantleLocation)) + { + var duration = 0.1f * mantleLocation.DistanceTo(_parent.Position); + _tweenQueueSystem.QueueTween(mantleLocation, duration); + } + else if (isOnFloor) + { + _parent.Velocity = new Vector3( + x: _parent.Velocity.X, + y: _gravity.CalculateJumpForce(), + z: _parent.Velocity.Z); + } + else if (_canDoubleJump) + { + _canDoubleJump = false; + _parent.Velocity = new Vector3( + x: _parent.Velocity.X, + y: _gravity.CalculateJumpForce() * DoubleJumpSpeedFactor, + z: _parent.Velocity.Z); + } + + } +} diff --git a/systems/move/MoveSystem.cs.uid b/systems/move/MoveSystem.cs.uid new file mode 100644 index 0000000..e0f07fc --- /dev/null +++ b/systems/move/MoveSystem.cs.uid @@ -0,0 +1 @@ +uid://dyy5njw6pxoh4 diff --git a/systems/tween_queue/TweenQueueSystem.cs b/systems/tween_queue/TweenQueueSystem.cs new file mode 100644 index 0000000..c5537f5 --- /dev/null +++ b/systems/tween_queue/TweenQueueSystem.cs @@ -0,0 +1,52 @@ +using Godot; +using System.Collections.Generic; + +public partial class TweenQueueSystem : Node3D +{ + public record TweenInputs(Vector3 Location, float Duration); + + private Queue _tweenInputs = new Queue(); + private Node3D _tweenObject; + private bool _isTweening = false; + + public void Init(Node3D tweenObject) + { + _tweenObject = tweenObject; + } + + public void EndTween() + { + _isTweening = false; + } + + private void TweenToLocation(TweenInputs inputs) + { + var (location, duration) = inputs; + + var tween = GetTree().CreateTween(); + var callback = new Callable(this, MethodName.EndTween); + + tween.TweenProperty(_tweenObject, "position", location, duration); + tween.TweenCallback(callback); + + _isTweening = true; + tween.Play(); + } + + public void QueueTween(TweenInputs inputs) + { + _tweenInputs.Enqueue(inputs); + } + + public void QueueTween(Vector3 location, float duration) + { + QueueTween(new TweenInputs(location, duration)); + } + + public void ProcessTweens() + { + if (_tweenInputs.Count > 0 && !_isTweening) + TweenToLocation(_tweenInputs.Dequeue()); + } + +} diff --git a/systems/tween_queue/TweenQueueSystem.cs.uid b/systems/tween_queue/TweenQueueSystem.cs.uid new file mode 100644 index 0000000..faa3eaa --- /dev/null +++ b/systems/tween_queue/TweenQueueSystem.cs.uid @@ -0,0 +1 @@ +uid://crm4u4r56hvg7 diff --git a/systems/tween_queue/tween_queue_system.tscn b/systems/tween_queue/tween_queue_system.tscn new file mode 100644 index 0000000..a6fe337 --- /dev/null +++ b/systems/tween_queue/tween_queue_system.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://dbe5f0p6lvqtr"] + +[ext_resource type="Script" uid="uid://crm4u4r56hvg7" path="res://systems/tween_queue/TweenQueueSystem.cs" id="1_iqosd"] + +[node name="TweenQueueSystem" type="Node3D"] +script = ExtResource("1_iqosd")