wall run, keyboard controls, mouse sensitivity setting, and more
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 19s
Create tag and build when new code gets to main / Export (push) Successful in 6m15s

This commit is contained in:
2025-11-13 22:38:44 +01:00
parent 27130257c9
commit ac14352e7f
13 changed files with 499 additions and 87 deletions

View File

@@ -1,12 +1,16 @@
[gd_scene load_steps=45 format=3 uid="uid://bei4nhkf8lwdo"]
[gd_scene load_steps=49 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/base_mode/base_mode.tres" id="3_cresl"]
[ext_resource type="Resource" uid="uid://cpdaw41ah5gic" path="res://systems/inputs/base_mode/rotate_y.tres" id="4_rxwoh"]
[ext_resource type="Resource" uid="uid://ccrb5xsnphc8" path="res://systems/inputs/base_mode/rotate_floorplane.tres" id="5_4u7i3"]
[ext_resource type="Resource" uid="uid://f3vs6l4m623s" path="res://systems/inputs/base_mode/move_left.tres" id="5_q14ux"]
[ext_resource type="Script" uid="uid://dv7v1ywmbvvcd" path="res://player_controller/Scripts/HealthSystem.cs" id="5_umw0l"]
[ext_resource type="Script" uid="uid://vuq8rjq3vegn" path="res://player_controller/Scripts/Stamina.cs" id="6_lxtc4"]
[ext_resource type="Resource" uid="uid://t612lts1wi1s" path="res://systems/inputs/base_mode/move_right.tres" id="6_q7bng"]
[ext_resource type="Script" uid="uid://cwbvxlfvmocc1" path="res://player_controller/Scripts/StairsSystem.cs" id="7_bmt5a"]
[ext_resource type="Resource" uid="uid://brswsknpgwal2" path="res://systems/inputs/base_mode/move_front.tres" id="7_m8gvy"]
[ext_resource type="Resource" uid="uid://s1l0n1iitc6m" path="res://systems/inputs/base_mode/move_back.tres" id="8_jb43f"]
[ext_resource type="Resource" uid="uid://j1o5ud0plk4" path="res://systems/inputs/base_mode/aim_release.tres" id="8_lhb11"]
[ext_resource type="Script" uid="uid://dd1yrt7eiiyf4" path="res://player_controller/Scripts/CapsuleCollider.cs" id="8_lmtjd"]
[ext_resource type="Resource" uid="uid://c3e0ivgaxrsyb" path="res://systems/inputs/base_mode/aim_down.tres" id="8_obsfv"]
@@ -87,6 +91,10 @@ WallHugHorizontalDeceleration = 0.5
script = ExtResource("16_v31n3")
base_mode = ExtResource("3_cresl")
move = ExtResource("17_h6vvl")
move_left = ExtResource("5_q14ux")
move_right = ExtResource("6_q7bng")
move_front = ExtResource("7_m8gvy")
move_back = ExtResource("8_jb43f")
rotate_y = ExtResource("4_rxwoh")
rotate_floorplane = ExtResource("5_4u7i3")
aim_down = ExtResource("8_obsfv")
@@ -170,18 +178,38 @@ script = ExtResource("27_n7qhm")
target_position = Vector3(0, 0, 1)
collision_mask = 2
[node name="back2" type="RayCast3D" parent="WallHugSystem"]
transform = Transform3D(0.70710677, 0, 0.70710677, 0, 1, 0, -0.70710677, 0, 0.70710677, 0, 0, 0)
target_position = Vector3(0, 0, 1)
collision_mask = 2
[node name="front" type="RayCast3D" parent="WallHugSystem"]
target_position = Vector3(0, 0, -1)
collision_mask = 2
[node name="front2" type="RayCast3D" parent="WallHugSystem"]
transform = Transform3D(0.70710677, 0, 0.70710677, 0, 1, 0, -0.70710677, 0, 0.70710677, 0, 0, 0)
target_position = Vector3(0, 0, -1)
collision_mask = 2
[node name="right" type="RayCast3D" parent="WallHugSystem"]
target_position = Vector3(1, 0, 0)
collision_mask = 2
[node name="right2" type="RayCast3D" parent="WallHugSystem"]
transform = Transform3D(0.70710677, 0, 0.70710677, 0, 1, 0, -0.70710677, 0, 0.70710677, 0, 0, 0)
target_position = Vector3(1, 0, 0)
collision_mask = 2
[node name="left" type="RayCast3D" parent="WallHugSystem"]
target_position = Vector3(-1, 0, 0)
collision_mask = 2
[node name="left2" type="RayCast3D" parent="WallHugSystem"]
transform = Transform3D(0.70710677, 0, 0.70710677, 0, 1, 0, -0.70710677, 0, 0.70710677, 0, 0, 0)
target_position = Vector3(-1, 0, 0)
collision_mask = 2
[node name="DashSystem" parent="." instance=ExtResource("18_q5h8a")]
DashSpeed = 0.2
PostDashSpeed = 30.0
@@ -566,6 +594,12 @@ to = NodePath("../../OnWall/Hugging")
event = &"wall_hug"
delay_in_seconds = "0.0"
[node name="OnWallRun" type="Node" parent="StateChart/Root/Movement/Airborne"]
script = ExtResource("28_n7qhm")
to = NodePath("../../OnWall/Running")
event = &"wall_run"
delay_in_seconds = "0.0"
[node name="OnDash" type="Node" parent="StateChart/Root/Movement/Airborne"]
script = ExtResource("28_n7qhm")
to = NodePath("../../Dashing/Dash")
@@ -651,50 +685,27 @@ 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")
[node name="ToHanging" type="Node" parent="StateChart/Root/Movement/OnWall/HugCanceled"]
[node name="OnLeaveWall" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("28_n7qhm")
to = NodePath("../../Hanging")
event = &"oh_hit_wall"
to = NodePath("../../Airborne/Reset")
event = &"start_falling"
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")
event = &"start_falling"
delay_in_seconds = "0.0"
[node name="OnDrop" type="Node" parent="StateChart/Root/Movement/OnWall/Hugging"]
script = ExtResource("28_n7qhm")
to = NodePath("../../HugCanceled")
event = &"__unused_dash"
delay_in_seconds = "0.0"
[node name="Hanging" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("27_34snm")
[node name="OnDrop" type="Node" parent="StateChart/Root/Movement/OnWall/Hanging"]
script = ExtResource("28_n7qhm")
to = NodePath("../../Hugging")
event = &"dash"
delay_in_seconds = "0.0"
[node name="Running" type="Node" parent="StateChart/Root/Movement/OnWall"]
script = ExtResource("27_34snm")
[connection signal="input_aim_canceled" from="InputController" to="." method="OnInputAimCanceled"]
[connection signal="input_aim_down" from="InputController" to="." method="OnInputAimDown"]
[connection signal="input_aim_pressed" from="InputController" to="." method="OnInputAimPressed"]
[connection signal="input_aim_released" from="InputController" to="." method="OnInputAimReleased"]
[connection signal="input_dash" from="InputController" to="." method="OnInputDashPressed"]
[connection signal="input_device_changed" from="InputController" to="." method="InputDeviceChanged"]
[connection signal="input_empower_down" from="InputController" to="." method="OnInputEmpowerDown"]
[connection signal="input_empower_released" from="InputController" to="." method="OnInputEmpowerReleased"]
[connection signal="input_hit" from="InputController" to="." method="OnInputHitPressed"]
@@ -702,6 +713,7 @@ delay_in_seconds = "0.0"
[connection signal="input_jump_ongoing" from="InputController" to="." method="OnInputJumpOngoing"]
[connection signal="input_jump_started" from="InputController" to="." method="OnInputJumpStarted"]
[connection signal="input_move" from="InputController" to="." method="OnInputMove"]
[connection signal="input_move_keyboard" from="InputController" to="." method="OnInputMoveKeyboard"]
[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"]

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Godot;
using GodotStateCharts;
using Movementtests.addons.godot_state_charts.csharp;
@@ -14,6 +15,7 @@ public partial class PlayerController : CharacterBody3D
MoveCamera,
None,
}
private bool _isUsingGamepad = false;
// User API to important child nodes.
public HeadSystem HeadSystem;
@@ -48,6 +50,7 @@ public partial class PlayerController : CharacterBody3D
private RayCast3D[] _headCollisionDetectors;
private Vector3 _inputMove = Vector3.Zero;
private Vector3 _inputMoveKeyboard = Vector3.Zero;
private float _inputRotateY;
private float _inputRotateFloorplane;
@@ -59,6 +62,7 @@ public partial class PlayerController : CharacterBody3D
private Timer _powerCooldownTimer;
[Export] public Marker3D TutorialWeaponTarget;
[Export] public bool TutorialDone { get; set; }
[ExportCategory("Movement")]
[ExportGroup("Ground")]
@@ -165,7 +169,6 @@ public partial class PlayerController : CharacterBody3D
PlayerUi.SetNumberOfDashesLeft(value);
}
}
public bool TutorialDone { get; set; }
public AllowedInputs CurrentlyAllowedInputs { get; set; } = AllowedInputs.All;
@@ -191,9 +194,10 @@ public partial class PlayerController : CharacterBody3D
private StateChartState _simpleDash;
private StateChartState _poweredDash;
private StateChartState _aimedDash;
private StateChartState _onWallHugCanceled;
private StateChartState _onWall;
private StateChartState _onWallHugging;
private StateChartState _onWallHanging;
private StateChartState _onWallRunning;
private Transition _onJumpFromWall;
private Transition _onMegajumpFromWall;
@@ -202,6 +206,7 @@ public partial class PlayerController : CharacterBody3D
private float _playerRadius;
private float _lookSensitivityMultiplier = 1.0f;
private float _mouseSensitivityMultiplier = 1.0f;
private float _headBobbingMultiplier = 1.0f;
private float _fovChangeMultiplier = 1.0f;
@@ -286,9 +291,10 @@ public partial class PlayerController : CharacterBody3D
_megaJump = StateChartState.Of(GetNode("StateChart/Root/Movement/Jump/MegaJump"));
_onJumpFromWall = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/OnJump"));
_onMegajumpFromWall = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/OnMegajump"));
_onWall = StateChartState.Of(GetNode("StateChart/Root/Movement/OnWall"));
_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"));
_onWallRunning = StateChartState.Of(GetNode("StateChart/Root/Movement/OnWall/Running"));
// State timers
_powerCooldownTimer = GetNode<Timer>("PowerCooldown");
_timeScaleAimInAirTimer = GetNode<Timer>("TimeScaleAimInAir");
@@ -329,7 +335,9 @@ public partial class PlayerController : CharacterBody3D
Stamina.SetSpeeds(WalkSpeed, WalkSpeed);
EmpoweredActionsLeft = MaxNumberOfEmpoweredActions;
PlaceWeaponForTutorial();
if (!TutorialDone)
PlaceWeaponForTutorial();
///////////////////////////
// Signal setup ///////////
@@ -374,9 +382,11 @@ public partial class PlayerController : CharacterBody3D
_simpleDashCooldownTimer.Timeout += DashCooldownTimeout;
_onWallHugCanceled.StatePhysicsProcessing += HandleAirborne;
_onWall.StateEntered += OnWallStarted;
_onWall.StateExited += OnWallStopped;
_onWallHugging.StatePhysicsProcessing += HandleWallHugging;
_onWallHanging.StatePhysicsProcessing += HandleWallHanging;
_onWallRunning.StatePhysicsProcessing += HandleWallRunning;
_onJumpFromWall.Taken += OnJumpFromWall;
_onMegajumpFromWall.Taken += OnMegajumpFromWall;
@@ -409,6 +419,7 @@ public partial class PlayerController : CharacterBody3D
}
_lookSensitivityMultiplier = (float) config.GetValue("InputSettings", "LookSensitivity", 1.0f);
_mouseSensitivityMultiplier = (float) config.GetValue("InputSettings", "MouseSensitivity", 1.0f);
_headBobbingMultiplier = (float) config.GetValue("InputSettings", "HeadBobbingWhileWalking", 1.0f);
_fovChangeMultiplier = (float) config.GetValue("InputSettings", "FovChangeWithSpeed", 1.0f);
}
@@ -418,11 +429,6 @@ public partial class PlayerController : CharacterBody3D
TutorialDone = true;
}
public void OnWallDetected()
{
FinishPoweredDash();
}
public void OnGrounded()
{
_isWallJumpAvailable = true;
@@ -443,26 +449,121 @@ public partial class PlayerController : CharacterBody3D
if (!isOnFloorCustom())
_playerState.SendEvent("start_falling");
}
private float _wallRunSpeedThreshold = 8f;
public void HandleAirborne(float delta)
{
MoveInAir(delta);
if (isOnFloorCustom())
_playerState.SendEvent("grounded");
if (WallHugSystem.IsWallHugging() && Velocity.Y < 0)
if (!WallHugSystem.IsWallHugging())
return;
// Going upwards, we stay simply airborne
if (Velocity.AngleTo(Vector3.Up) < Math.PI / 4)
return;
// Should we start a wall run
var wallNormal = WallHugSystem.WallHugNormal.UnwrapOr(Vector3.Zero);
var hvel = new Vector3(Velocity.X, 0, Velocity.Z);
var hvelProjected = hvel.Slide(_wallHugStartNormal);
var haveEnoughSpeed = hvelProjected.Length() > _wallRunSpeedThreshold;
var isHeadPlanting = Velocity.AngleTo(wallNormal) < Math.PI / 4;
var isGoingDownwards = Velocity.AngleTo(Vector3.Down) < Math.PI / 4;
if (haveEnoughSpeed && !isHeadPlanting && !isGoingDownwards)
{
_playerState.SendEvent("wall_run");
return;
}
// If all else fail and we go down, we hug
if (Velocity.Y < 0)
_playerState.SendEvent("wall_hug");
}
private Vector3 _wallHugStartLocation = Vector3.Zero;
private Vector3 _wallHugStartNormal = Vector3.Zero;
private Vector3 _wallHugStartProjectedVelocity = Vector3.Zero;
public void OnWallDetected()
{
FinishPoweredDash();
if (!_onWall.Active)
return;
var newWallNormal = WallHugSystem.WallHugNormal.UnwrapOr(Vector3.Up);
_wallHugStartNormal = newWallNormal;
}
private float _timeSinceWallStarted;
public void OnWallStarted()
{
_wallHugStartNormal = WallHugSystem.WallHugNormal.UnwrapOr(Vector3.Up);
_wallHugStartLocation = WallHugSystem.WallHugLocation.UnwrapOr(Vector3.Zero) + _wallHugStartNormal * _playerRadius;
_wallHugStartProjectedVelocity = Velocity.Slide(_wallHugStartNormal);
_timeSinceWallStarted = 0;
}
public void OnWallStopped()
{
}
public void HandleWallHugging(float delta)
{
WallHug(delta);
if (isOnFloorCustom())
_playerState.SendEvent("grounded");
if (!WallHugSystem.IsWallHugging())
{
_playerState.SendEvent("start_falling");
}
}
public void HandleWallHanging(float delta)
{
WallHang(delta);
}
private float _wallRunUpwardVelocity = 10f;
public void HandleWallRunning(float delta)
{
_timeSinceWallStarted += delta;
var hvel = new Vector3(Velocity.X, 0, Velocity.Z);
var hvelProjected = hvel.Slide(_wallHugStartNormal);
Velocity = hvelProjected + hvelProjected.Length()*Vector3.Up*0.3f/(1+_timeSinceWallStarted);
Velocity *= 0.99f;
// if (CanMantle())
// {
// MantleToLocation(_plannedMantleLocation.Unwrap());
// }
if (!WallHugSystem.IsWallHugging() || Velocity.Length() < _wallRunSpeedThreshold)
{
_playerState.SendEvent("start_falling");
}
}
public void WallHug(float delta)
{
var hvel = ComputeHVelocity(delta, WallHugHorizontalDeceleration, WallHugHorizontalDeceleration);
var hvelProjected = hvel.Slide(_wallHugStartNormal);
var vvel = Velocity.Y - (CalculateGravityForce() * delta / WallHugGravityLesseningFactor);
vvel = Math.Abs(vvel) > WallHugDownwardMaxSpeed ? -WallHugDownwardMaxSpeed : vvel;
Velocity = hvelProjected + vvel*Vector3.Up;
}
public void WallHang(float delta)
{
Velocity = Vector3.Zero;
GlobalPosition = _wallHugStartLocation;
}
private Option<Vector3> _plannedMantleLocation = Option<Vector3>.None;
@@ -511,20 +612,6 @@ public partial class PlayerController : CharacterBody3D
PerformEmpoweredAction();
OnJumpStarted(MegaJumpStartVelocity);
}
public void WallHug(float delta)
{
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)
{
@@ -533,7 +620,7 @@ public partial class PlayerController : CharacterBody3D
// _isWallJumpAvailable = false;
// var isLookingTowardsWall = HeadSystem.GetForwardHorizontalVector().Dot(wallNormal) > 0.5;
// var jumpDirection = isLookingTowardsWall ? Vector3.Up : wallNormal;
var wallNormal = WallHugSystem.GetWallNormal().UnwrapOr(Vector3.Up);
var wallNormal = WallHugSystem.WallHugNormal.UnwrapOr(Vector3.Up);
var jumpVector = wallNormal * jumpStrength;
var currentHorizontalVelocity = new Vector2(Velocity.X, Velocity.Z);
@@ -550,9 +637,21 @@ public partial class PlayerController : CharacterBody3D
ComputeJumpFromWallHSpeed(WallMegajumpStartVelocity);
}
public void InputDeviceChanged(bool isUsingGamepad)
{
_isUsingGamepad = isUsingGamepad;
}
public Vector3 GetMoveInput()
{
if (_isUsingGamepad)
return _inputMove;
return _inputMoveKeyboard;
}
public Vector3 ComputeHVelocity(float delta, float accelerationFactor, float decelerationFactor, Vector3? direction = null)
{
var dir = direction ?? Transform.Basis * HeadSystem.Transform.Basis * _inputMove;
var dir = direction ?? Transform.Basis * HeadSystem.Transform.Basis * GetMoveInput();
var acceleration = dir.Length() > 0 ? accelerationFactor : decelerationFactor;
@@ -654,6 +753,12 @@ public partial class PlayerController : CharacterBody3D
///////////////////////////
// Input Management ///////
///////////////////////////
public void OnInputMoveKeyboard(Vector3 value)
{
_inputMoveKeyboard = value;
}
public void OnInputMove(Vector3 value)
{
_inputMove = value;
@@ -911,13 +1016,13 @@ public partial class PlayerController : CharacterBody3D
public Vector3 GetInputGlobalHDirection()
{
var direction = Transform.Basis * HeadSystem.Transform.Basis * _inputMove;
var direction = Transform.Basis * HeadSystem.Transform.Basis * GetMoveInput();
return new Vector3(direction.X, 0, direction.Z).Normalized();
}
public Vector3 GetInputLocalHDirection()
{
var direction = _inputMove;
var direction = GetMoveInput();
return new Vector3(direction.X, 0, direction.Z).Normalized();
}
@@ -997,7 +1102,8 @@ public partial class PlayerController : CharacterBody3D
private void LookAround()
{
Vector2 inputLookDir = new Vector2(_inputRotateY, _inputRotateFloorplane);
HeadSystem.LookAround(inputLookDir, _lookSensitivityMultiplier);
var lookSensitivity = _isUsingGamepad ? _lookSensitivityMultiplier : _mouseSensitivityMultiplier;
HeadSystem.LookAround(inputLookDir, lookSensitivity);
}
public void MoveOnGround(double delta)