complete project reorganization
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 55s
Create tag and build when new code gets to main / Test (push) Successful in 7m7s
Create tag and build when new code gets to main / Export (push) Successful in 9m56s

This commit is contained in:
2026-02-04 11:20:00 +01:00
parent b6e8d0b590
commit cd519e528f
824 changed files with 397 additions and 16380 deletions

View File

@@ -0,0 +1,160 @@
using Godot;
using Movementtests.interfaces;
namespace Movementtests.systems;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_wind.png")]
public partial class DashSystem: Node3D
{
public record DashLocation(bool HasHit, Vector3 TargetLocation, Vector3 CollisionPoint, Vector3 CollisionNormal, GodotObject HitObject = null);
[Export(PropertyHint.Range, "0,0.2,0.01,or_greater")]
public float DashSpeed { get; set; } = 0.1f;
[Export(PropertyHint.Range, "0,1000,1,or_greater")]
public float PostDashSpeed { get; set; } = 0f;
public bool HasHit { get; set; }
public bool CanDashThroughTarget { get; set; }
public Vector3 TargetLocation { get; set; }
public Vector3 CollisionPoint { get; set; }
public Vector3 CollisionNormal { get; set; }
public GodotObject CollidedObject { get; set; }
public Vector3 PlannedLocation { get; set; }
public bool ShouldMantle { get; set; }
public Vector3 PlannedMantleLocation { get; set; }
public MantleSystem MantleSystem { get; set; }
private HeadSystem _head;
public ShapeCast3D DashCast3D;
private Camera3D _camera;
private Vector3 _dashDirection = Vector3.Zero;
private ShapeCast3D _dashCastDrop;
private MeshInstance3D _dashDropIndicator;
private MeshInstance3D _dashDropLocationIndicator;
private MeshInstance3D _dashTarget;
private CpuParticles3D _dashIndicator;
private AnimationPlayer _dashIndicatorAnim;
[Export]
public PackedScene DashIndicatorScene { get; set; }
[Signal]
public delegate void DashStartedEventHandler();
[Signal]
public delegate void DashEndedEventHandler();
[Signal]
public delegate void DashProgressEventHandler(float progress);
private Vector3 _globalDashPosition = Vector3.Zero;
public float DashCastRadius { get; set; }
public void Init(HeadSystem head, Camera3D camera)
{
DashCast3D = GetNode<ShapeCast3D>("DashCast3D");
var dashShape = DashCast3D.GetShape() as SphereShape3D;
DashCastRadius = dashShape!.Radius;
_dashCastDrop = GetNode<ShapeCast3D>("DashCastDrop");
_dashDropIndicator = GetNode<MeshInstance3D>("DashDropIndicator");
_dashDropIndicator.Visible = false;
_dashDropLocationIndicator = GetNode<MeshInstance3D>("DashDropLocationIndicator");
_dashDropLocationIndicator.Visible = false;
_head = head;
_camera = camera;
MantleSystem = GetNode<MantleSystem>("MantleSystem");
MantleSystem.Init();
_dashTarget = GetNode<MeshInstance3D>("DashTarget");
_dashTarget.SetVisible(false);
_dashIndicator = GetNode<CpuParticles3D>("DashIndicator");
_dashIndicatorAnim = GetNode<AnimationPlayer>("DashIndicator/AnimationPlayer");
}
private DashLocation ComputeDashLocation()
{
var targetLocation = DashCast3D.ToGlobal(DashCast3D.TargetPosition);
var hasHit = DashCast3D.IsColliding();
if (!hasHit)
{
return new DashLocation(false, targetLocation, Vector3.Zero, Vector3.Zero);
}
var collisionPoint = DashCast3D.GetCollisionPoint(0);
var collisionNormal = DashCast3D.GetCollisionNormal(0);
var collidedObject = DashCast3D.GetCollider(0);
var fraction = DashCast3D.GetClosestCollisionSafeFraction();
var globalSweepPath = targetLocation - DashCast3D.GlobalPosition;
var locationAlongPath = DashCast3D.GlobalPosition + globalSweepPath * fraction;
return new DashLocation(true, locationAlongPath, collisionPoint, collisionNormal, collidedObject);
}
public void PrepareDash()
{
DashCast3D.SetRotation(_head.GetGlobalLookRotation());
(HasHit, PlannedLocation, CollisionPoint, CollisionNormal, CollidedObject) = ComputeDashLocation();
CanDashThroughTarget = false;
if (CollidedObject is ITargetable targetable)
{
_dashTarget.SetVisible(false);
CanDashThroughTarget = true;
return;
}
MantleSystem.SetGlobalPosition(PlannedLocation);
MantleSystem.SetRotation(new Vector3(
MantleSystem.Rotation.X,
_head.Rotation.Y,
MantleSystem.Rotation.Z));
MantleSystem.ProcessMantle(false);
ShouldMantle = MantleSystem.IsMantlePossible;
// 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);
var targetLocation = ShouldMantle ? MantleSystem.FirstMantleProfilePoint : PlannedLocation;
_dashTarget.SetGlobalPosition(targetLocation);
return;
var shouldShowDropIndicator = !HasHit && !ShouldMantle;
_dashDropIndicator.SetVisible(shouldShowDropIndicator);
_dashDropLocationIndicator.SetVisible(shouldShowDropIndicator);
if (shouldShowDropIndicator)
{
_dashCastDrop.GlobalPosition = targetLocation; // Place drop indication cast at dash location
var startDropLocation = targetLocation; // Start of the drop is the dash target location
// End of the drop is either max cast distance or first collision
var hasDropLocationHit = _dashCastDrop.IsColliding();
var endDropLocation = hasDropLocationHit ? _dashCastDrop.GetCollisionPoint(0) : _dashCastDrop.ToGlobal(DashCast3D.TargetPosition);
// Only show drop location indicator if drop cast has hit
_dashDropLocationIndicator.SetVisible(hasDropLocationHit);
_dashDropLocationIndicator.SetGlobalPosition(endDropLocation);
var dropLength = (endDropLocation - startDropLocation).Length();
var dropDirection = (endDropLocation - startDropLocation).Normalized();
_dashDropIndicator.SetScale(new Vector3(1, dropLength, 1));
_dashDropIndicator.SetGlobalPosition(startDropLocation + dropDirection * dropLength * 0.5f);
}
}
public void StopPreparingDash()
{
CanDashThroughTarget = false;
_dashTarget.SetVisible(false);
_dashDropIndicator.SetVisible(false);
_dashDropLocationIndicator.SetVisible(false);
}
}

View File

@@ -0,0 +1 @@
uid://dwoppk8j5fxeg

View File

@@ -0,0 +1,77 @@
[gd_scene format=3 uid="uid://hd0868f4pb63"]
[ext_resource type="Texture2D" uid="uid://chvt6g0xn5c2m" path="res://scenes/player_controller/components/dash/light-ring.jpg" id="1_jadbb"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_tqt6i"]
transparency = 1
blend_mode = 1
shading_mode = 0
albedo_texture = ExtResource("1_jadbb")
billboard_mode = 1
[sub_resource type="PlaneMesh" id="PlaneMesh_jngg2"]
orientation = 2
[sub_resource type="Animation" id="Animation_fmn25"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:mesh:size")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(2, 2)]
}
[sub_resource type="Animation" id="Animation_stbcc"]
resource_name = "start"
length = 0.2
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:mesh:size")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.2),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector2(2, 2), Vector2(0, 0)]
}
tracks/1/type = "method"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath(".")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0.2),
"transitions": PackedFloat32Array(1),
"values": [{
"args": [],
"method": &"queue_free"
}]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_3aile"]
_data = {
&"RESET": SubResource("Animation_fmn25"),
&"start": SubResource("Animation_stbcc")
}
[node name="DashIndicator" type="CPUParticles3D" unique_id=585575469]
material_override = SubResource("StandardMaterial3D_tqt6i")
emitting = false
amount = 1
lifetime = 0.5
one_shot = true
mesh = SubResource("PlaneMesh_jngg2")
gravity = Vector3(0, 0, 0)
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=686842148]
libraries/ = SubResource("AnimationLibrary_3aile")
autoplay = &"start"

View File

@@ -0,0 +1,57 @@
[gd_scene format=3 uid="uid://cqduhd4opgwvm"]
[ext_resource type="Script" uid="uid://dwoppk8j5fxeg" path="res://scenes/player_controller/components/dash/DashSystem.cs" id="1_hwig2"]
[ext_resource type="PackedScene" uid="uid://wq1okogkhc5l" path="res://scenes/player_controller/components/mantle/mantle_system.tscn" id="2_pff7b"]
[ext_resource type="PackedScene" uid="uid://hd0868f4pb63" path="res://scenes/player_controller/components/dash/dash_indicator.tscn" id="2_tqt6i"]
[sub_resource type="SphereShape3D" id="SphereShape3D_jngg2"]
[sub_resource type="SphereMesh" id="SphereMesh_qu4wy"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_v31n3"]
[sub_resource type="CylinderMesh" id="CylinderMesh_jngg2"]
top_radius = 0.1
bottom_radius = 0.1
height = 1.0
[sub_resource type="TorusMesh" id="TorusMesh_tqt6i"]
inner_radius = 0.1
outer_radius = 0.5
[node name="DashSystem" type="Node3D" unique_id=2116632075]
script = ExtResource("1_hwig2")
DashIndicatorScene = ExtResource("2_tqt6i")
[node name="DashCast3D" type="ShapeCast3D" parent="." unique_id=1635795914]
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
collision_mask = 304
debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1)
[node name="DashCastDrop" type="ShapeCast3D" parent="." unique_id=980436638]
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0, 1.6, 0)
shape = SubResource("SphereShape3D_jngg2")
target_position = Vector3(0, 0, -50)
max_results = 1
collision_mask = 304
debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1)
[node name="DashTarget" type="MeshInstance3D" parent="." unique_id=711803810]
mesh = SubResource("SphereMesh_qu4wy")
surface_material_override/0 = SubResource("StandardMaterial3D_v31n3")
[node name="MantleSystem" parent="." unique_id=1511791010 instance=ExtResource("2_pff7b")]
MantleEndLocationDistanceFromWall = 0.25
MantleHeightCastStart = 2.0
[node name="DashIndicator" parent="." unique_id=98967688 instance=ExtResource("2_tqt6i")]
visible = false
[node name="DashDropIndicator" type="MeshInstance3D" parent="." unique_id=173959533]
mesh = SubResource("CylinderMesh_jngg2")
[node name="DashDropLocationIndicator" type="MeshInstance3D" parent="." unique_id=1260955364]
mesh = SubResource("TorusMesh_tqt6i")

View File

@@ -0,0 +1,5 @@
[gd_resource type="Curve" format=3 uid="uid://c2a8soliruf35"]
[resource]
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.5, 1), -1.89032e-07, -1.89032e-07, 0, 0, Vector2(0.8, 0.05), -9.56219, 0.0, 0, 1, Vector2(0.995, 0.05), 0.0, 0.0, 0, 0, Vector2(1, 1), -0.0540619, -0.0540619, 0, 0]
point_count = 5

BIN
scenes/player_controller/components/dash/light-ring.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View File

@@ -0,0 +1,42 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://chvt6g0xn5c2m"
path.s3tc="res://.godot/imported/light-ring.jpg-59a7aa6aff8e55915b68cd23f0e30ad8.s3tc.ctex"
path.etc2="res://.godot/imported/light-ring.jpg-59a7aa6aff8e55915b68cd23f0e30ad8.etc2.ctex"
metadata={
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://scenes/player_controller/components/dash/light-ring.jpg"
dest_files=["res://.godot/imported/light-ring.jpg-59a7aa6aff8e55915b68cd23f0e30ad8.s3tc.ctex", "res://.godot/imported/light-ring.jpg-59a7aa6aff8e55915b68cd23f0e30ad8.etc2.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

@@ -0,0 +1,370 @@
using System;
using Godot;
using RustyOptions;
namespace Movementtests.systems;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_face.png")]
public partial class HeadSystem : Node3D
{
[Signal]
public delegate void HitboxActivatedEventHandler();
[Signal]
public delegate void HitboxDeactivatedEventHandler();
[Signal]
public delegate void ParryboxActivatedEventHandler();
[Signal]
public delegate void ParryboxDeactivatedEventHandler();
[Signal]
public delegate void HitTargetEventHandler();
[Signal]
public delegate void GotHitEventHandler();
[Signal]
public delegate void DeathAnimationFinishedEventHandler();
[Signal]
public delegate void StepFootEventHandler();
public record CameraParameters(
double Delta,
Vector2 LookDir,
Vector3 PlayerInput,
Vector3 PlayerVelocity,
Vector3 WallContactPoint,
float SensitivitMultiplier,
bool WithCameraJitter,
bool WithCameraBobbing,
float BobbingMultiplier,
float FovMultiplier);
private Camera3D _camera;
private Marker3D _cameraAnchor;
private AnimationPlayer _animationPlayer;
private AnimationTree _animationTree;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
public float LookSensitivity { get; set; } = 1f;
[ExportGroup("Camera incline")]
[Export(PropertyHint.Range, "0.1,50,0.1,or_greater")]
public double CameraInclineAcceleration { get; set; } = 10f;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
public float WallRunCameraIncline { get; set; } = 5f;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
public float GroundedCameraIncline { get; set; } = 5f;
[ExportGroup("Sliding")]
[Export(PropertyHint.Range, "0,2,0.1,or_greater")]
public float SlidingCameraHeightOffset { get; set; } = 1.0f;
[Export(PropertyHint.Range, "0,1,0.01,or_greater")]
public float SlidingJitterFrequency { get; set; } = 0.01f;
[Export(PropertyHint.Range, "0,1,0.01,or_greater")]
public float SlidingJitterAmplitude { get; set; } = 0.1f;
private FastNoiseLite _slidingNoise = new FastNoiseLite();
[ExportGroup("Bobbing")]
private float _bobbingAccumulator; // Constantly increases when player moves in X or/and Z axis
[Export(PropertyHint.Range, "0,10,0.01,or_greater")]
public float BobbingFrequency { set; get; } = 2.4f;
[Export(PropertyHint.Range, "0,0.4,0.01,or_greater")]
public float BobbingAmplitude { set; get; } = 0.08f;
[ExportGroup("FOV")]
[Export(PropertyHint.Range, "0,180,0.1,degrees")]
public float BaseFov { get; set; } = 75.0f;
[Export(PropertyHint.Range, "0,10,0.01,or_greater")]
public float FovChangeFactor { get; set; } = 1.2f;
[Export(PropertyHint.Range, "0,10,0.01,or_greater")]
public float FovChangeSpeed { get; set; } = 6.25f;
[Export(PropertyHint.Range, "0,100,1,or_greater")]
public float FovMaxedOutSpeed { get; set; } = 20f;
[ExportGroup("First Person rig")]
private Node3D _fpRig;
private Node3D _rightHandedWeapon;
private Node3D _leftHandedWeapon;
private Node3D _fpDisplacedRig;
private Vector3 _fpDisplacedRigInitialRotation;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
public float WeaponSway { get; set; } = 5f;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
public float WeaponLookRotation { get; set; } = 1f;
[Export(PropertyHint.Range, "0,200,1,or_greater")]
public float WeaponMoveRotation { get; set; } = 80f;
[Export(PropertyHint.Range, "0,20,0.1,or_greater")]
public float WeaponAdjustmentSpeed { get; set; } = 10f;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
public float DisplacedWeaponSway { get; set; } = 5f;
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
public float DisplacedWeaponLookRotation { get; set; } = 1f;
[Export(PropertyHint.Range, "0,1,0.01,or_greater")]
public float DisplacedWeaponMoveRotation { get; set; } = 0.1f;
[Export(PropertyHint.Range, "0,20,0.1,or_greater")]
public float DisplacedWeaponAdjustmentSpeed { get; set; } = 10f;
public void Init()
{
_isPlayingForcingAnim = false;
Input.SetMouseMode(Input.MouseModeEnum.Captured);
_camera = GetNode<Camera3D>("CameraSmooth/Camera3D");
_cameraAnchor = GetNode<Marker3D>("CameraAnchor");
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
_animationTree = GetNode<AnimationTree>("AnimationTree");
_fpRig = GetNode<Node3D>("FPRig");
_rightHandedWeapon = GetNode<Node3D>("FPRig/Sword");
_leftHandedWeapon = GetNode<Node3D>("FPRig/Parry");
_fpDisplacedRig = GetNode<Node3D>("FPRig/Sword");
_fpDisplacedRigInitialRotation = _fpDisplacedRig.Rotation;
_slidingNoise.NoiseType = FastNoiseLite.NoiseTypeEnum.Perlin;
_slidingNoise.SetFrequency(SlidingJitterFrequency);
}
public void OnMantle()
{
_animationTree.Set("parameters/OnMantle/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
}
public void OnJumpStarted()
{
_animationTree.Set("parameters/OnJumpStart/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
}
public void OnJumpEnded()
{
_animationTree.Set("parameters/OnJumpEnd/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
}
public void OnHit()
{
_animationTree.Set("parameters/OnHit/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
}
public void OnParry()
{
_animationTree.Set("parameters/OnParry/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
}
public void OnStartDeathAnimation()
{
_isPlayingForcingAnim = true;
_animationTree.Set("parameters/OnDie/request", (int) AnimationNodeOneShot.OneShotRequest.Fire);
}
public void OnDeathAnimationFinished()
{
EmitSignalDeathAnimationFinished();
}
public void OnHitTarget()
{
EmitSignalHitTarget();
}
public void OnGetHit()
{
EmitSignalGotHit();
}
public void OnHitboxActivated()
{
EmitSignalHitboxActivated();
}
public void OnHitboxDeactivated()
{
EmitSignalHitboxDeactivated();
}
public void OnParryboxActivated()
{
EmitSignalHitboxActivated();
}
public void OnParryboxDeactivated()
{
EmitSignalHitboxDeactivated();
}
private bool _footstepEmitted;
private bool _isPlayingForcingAnim;
public void LookAround(CameraParameters inputs)
{
if (_isPlayingForcingAnim)
{
_camera.Position = Vector3.Zero;
_camera.Rotation = Vector3.Zero;
return;
}
var (delta,
lookDir,
playerInput,
playerVelocity,
wallContactPoint,
sensitivitMultiplier,
withCameraJitter,
withCameraBobbing,
bobbingMultiplier,
fovMultiplier) = inputs;
// Horizontal movement of head
float angleForHorizontalRotation = lookDir.X * LookSensitivity * sensitivitMultiplier;
RotateY(angleForHorizontalRotation);
// Vertical movement of head
Vector3 currentCameraRotation = _cameraAnchor.Rotation;
currentCameraRotation.X += Convert.ToSingle(lookDir.Y * LookSensitivity * sensitivitMultiplier);
currentCameraRotation.X = Mathf.Clamp(currentCameraRotation.X, Mathf.DegToRad(-90f), Mathf.DegToRad(90f));
// Camera incline on Wall and more
var isWallRunning = wallContactPoint.Length() > Mathf.Epsilon;
float cameraIncline;
if (isWallRunning)
{
var directionToWall = (wallContactPoint - GlobalPosition).Normalized();
var cameraInclineFactor = ComputeCameraInclineFactor(directionToWall);
cameraIncline = Mathf.DegToRad(WallRunCameraIncline * cameraInclineFactor);
}
else
{
var cameraInclineFactor = ComputeCameraInclineFactor(playerInput);
cameraIncline = Mathf.DegToRad(GroundedCameraIncline * cameraInclineFactor * -1.0f);
}
currentCameraRotation.Z = (float) Mathf.Lerp(currentCameraRotation.Z, cameraIncline, delta * CameraInclineAcceleration);
_cameraAnchor.Rotation = currentCameraRotation;
if (withCameraJitter)
{
_cameraAnchor.Position = Vector3.Down*SlidingCameraHeightOffset;
float noise1D = _slidingNoise.GetNoise1D(Time.GetTicksMsec());
float noiseAmplitude = SlidingJitterAmplitude*Mathf.Clamp(playerVelocity.Length(), 0f, 1f);
_cameraAnchor.Position += Vector3.Up*noise1D*noiseAmplitude;
}
else
{
_cameraAnchor.Position = Vector3.Zero;
}
Vector3 newPositionForCamera = Vector3.Zero;
Vector3 newPositionForRig = Vector3.Zero;
if (withCameraBobbing)
{
_bobbingAccumulator += (float) delta * playerVelocity.Length();
// As the _bobbingAccumulator increases we're changing values for sin and cos functions.
// Because both of them are just waves, we will be slide up with y and then slide down with y
// creating bobbing effect. The same works for cos. As the _bobbingAccumulator increases the cos decreases and then increases
newPositionForCamera.Y = Mathf.Sin(_bobbingAccumulator * BobbingFrequency) * BobbingAmplitude * bobbingMultiplier;
newPositionForCamera.X = Mathf.Cos(_bobbingAccumulator * BobbingFrequency / 2.0f) * BobbingAmplitude * bobbingMultiplier;
if (newPositionForCamera.Y < -0.07 && !_footstepEmitted) Footstep();
if (newPositionForCamera.Y > 0) _footstepEmitted = false;
// Offset bobbing for weapon rig
newPositionForRig.Y = Mathf.Cos(_bobbingAccumulator * BobbingFrequency) * BobbingAmplitude * bobbingMultiplier * 0.2f;
newPositionForRig.X = Mathf.Sin(_bobbingAccumulator * BobbingFrequency / 2.0f) * BobbingAmplitude * bobbingMultiplier * 0.2f;
}
_cameraAnchor.Position += newPositionForCamera;
_camera.GlobalTransform = _cameraAnchor.GetGlobalTransformInterpolated();
// First person rig adjustments
_fpRig.GlobalTransform = _cameraAnchor.GetGlobalTransformInterpolated();
// Apply bobbing
_fpRig.Position += newPositionForRig;
// Rotate the whole rig based on movement input
var newRigRotation = _fpRig.Rotation;
var camTilt = Mathf.Lerp(_fpRig.Rotation.Z, cameraIncline*WeaponMoveRotation, delta*WeaponAdjustmentSpeed);
newRigRotation.Z = (float) camTilt;
// Rotate the whole rig based on camera rotation input
newRigRotation.X = Mathf.Lerp(newRigRotation.X, -lookDir.Y*WeaponSway, (float) delta*WeaponAdjustmentSpeed);
newRigRotation.Y = Mathf.Lerp(newRigRotation.Y, -lookDir.X*WeaponSway, (float) delta*WeaponAdjustmentSpeed);
// Apply
_fpRig.Rotation = newRigRotation;
// Compute displaced rig adjustments, starting with movement input
var newDisplacedRigRotation = _fpDisplacedRig.Rotation;
var howMuchForward = ComputeHowMuchInputForward(playerInput);
var howMuchSideways = ComputeHowMuchInputSideways(playerInput);
var displacedCamTiltForward = Mathf.Lerp(newDisplacedRigRotation.Z,
_fpDisplacedRigInitialRotation.Z + howMuchForward*DisplacedWeaponMoveRotation,
delta*DisplacedWeaponAdjustmentSpeed);
var displacedCamTiltSide = Mathf.Lerp(newDisplacedRigRotation.X,
_fpDisplacedRigInitialRotation.X - howMuchSideways*DisplacedWeaponMoveRotation,
delta*DisplacedWeaponAdjustmentSpeed);
newDisplacedRigRotation.X = (float) displacedCamTiltSide;
newDisplacedRigRotation.Z = (float) displacedCamTiltForward;
var displacedSwayY = Mathf.Lerp(newDisplacedRigRotation.Y,
_fpDisplacedRigInitialRotation.Y - lookDir.X*DisplacedWeaponSway,
delta*DisplacedWeaponAdjustmentSpeed);
newDisplacedRigRotation.Y = (float) displacedSwayY;
// Apply
_fpDisplacedRig.Rotation = newDisplacedRigRotation;
// Camera adjustments
float velocityClamped = Mathf.Clamp(playerVelocity.Length(), 0.5f, FovMaxedOutSpeed);
float targetFov = BaseFov + FovChangeFactor * velocityClamped * fovMultiplier;
_camera.Fov = Mathf.Lerp(_camera.Fov, targetFov, (float) delta * FovChangeSpeed);
}
public void Footstep()
{
_footstepEmitted = true;
EmitSignalStepFoot();
}
public void HideWeapon()
{
_rightHandedWeapon.Visible = false;
}
public void ShowWeapon()
{
_rightHandedWeapon.Visible = true;
}
public float ComputeCameraInclineFactor(Vector3 direction)
{
var forward = GetForwardHorizontalVector().Normalized();
var crossProduct = forward.Cross(direction);
return crossProduct.Length()*Mathf.Sign(crossProduct.Y);
}
public float ComputeHowMuchInputForward(Vector3 playerInput)
{
var forwardAngle = GetForwardHorizontalVector().AngleTo(playerInput);
var forwardRemapped = Mathf.Remap(forwardAngle, 0, Mathf.Pi, -1, 1);
return playerInput.Length() > 0 ? forwardRemapped : 0;
}
public float ComputeHowMuchInputSideways(Vector3 playerInput)
{
var rightAngle = GetForwardHorizontalVector().Cross(Vector3.Up).Normalized().AngleTo(playerInput);
var forwardRemapped = Mathf.Remap(rightAngle, 0, Mathf.Pi, -1, 1);
return playerInput.Length() > 0 ? forwardRemapped : 0;
}
public Vector3 GetForwardHorizontalVector()
{
return GetGlobalTransform().Basis.Z;
}
public Vector3 GetGlobalLookRotation()
{
return new Vector3(
_camera.Rotation.X,
Rotation.Y,
_camera.Rotation.Z);
}
public void SetHeight(float height)
{
Position = new Vector3(Position.X, height, Position.Z);
}
}

View File

@@ -0,0 +1 @@
uid://dtkdrnsmlwm67

View File

@@ -0,0 +1,76 @@
[gd_resource type="AnimationNodeBlendTree" format=3 uid="uid://c26yvcyyyj811"]
[ext_resource type="AnimationNodeStateMachine" uid="uid://3r5oeg0ho0d4" path="res://scenes/player_controller/components/head/fp_state_machine.tres" id="1_knaxl"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_1hkum"]
animation = &"die"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_knaxl"]
animation = &"idle"
[sub_resource type="AnimationNodeOneShot" id="AnimationNodeOneShot_ao3u1"]
filters = ["../..", "../../FPRig/Sword:position", "../../FPRig/Sword:rotation", "..:position", "..:rotation", ".:position", ".:rotation"]
[sub_resource type="AnimationNodeOneShot" id="AnimationNodeOneShot_1hkum"]
[sub_resource type="AnimationNodeOneShot" id="AnimationNodeOneShot_knaxl"]
filter_enabled = true
filters = ["..:position", "..:rotation"]
[sub_resource type="AnimationNodeOneShot" id="AnimationNodeOneShot_23rmc"]
filter_enabled = true
filters = ["..:position", "..:rotation"]
[sub_resource type="AnimationNodeOneShot" id="AnimationNodeOneShot_dlkjl"]
filter_enabled = true
filters = ["..:position", "..:rotation", "..:rotation:x", "..:rotation:z"]
[sub_resource type="AnimationNodeOneShot" id="AnimationNodeOneShot_lwjon"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_calte"]
animation = &"parry"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_23rmc"]
animation = &"hit1"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_dlkjl"]
animation = &"jump_end"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_ao3u1"]
animation = &"jump_start"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_lwjon"]
animation = &"mantle"
[resource]
graph_offset = Vector2(-363.5551, -25.864124)
nodes/output/position = Vector2(2020, -40)
nodes/AnimationNodeStateMachine/node = ExtResource("1_knaxl")
nodes/AnimationNodeStateMachine/position = Vector2(-560, 180)
nodes/Idle/node = SubResource("AnimationNodeAnimation_knaxl")
nodes/Idle/position = Vector2(-100, -20)
nodes/OnHit/node = SubResource("AnimationNodeOneShot_1hkum")
nodes/OnHit/position = Vector2(1240, -60)
nodes/hit1/node = SubResource("AnimationNodeAnimation_23rmc")
nodes/hit1/position = Vector2(1080, 320)
nodes/OnJumpStart/node = SubResource("AnimationNodeOneShot_23rmc")
nodes/OnJumpStart/position = Vector2(140, 0)
nodes/OnJumpEnd/node = SubResource("AnimationNodeOneShot_knaxl")
nodes/OnJumpEnd/position = Vector2(560, -20)
nodes/jump_start/node = SubResource("AnimationNodeAnimation_ao3u1")
nodes/jump_start/position = Vector2(-120, 320)
nodes/jump_end/node = SubResource("AnimationNodeAnimation_dlkjl")
nodes/jump_end/position = Vector2(300, 340)
nodes/OnMantle/node = SubResource("AnimationNodeOneShot_dlkjl")
nodes/OnMantle/position = Vector2(900, -60)
nodes/mantle/node = SubResource("AnimationNodeAnimation_lwjon")
nodes/mantle/position = Vector2(640, 320)
nodes/OnDie/node = SubResource("AnimationNodeOneShot_ao3u1")
nodes/OnDie/position = Vector2(1500, -60)
nodes/Die/node = SubResource("AnimationNodeAnimation_1hkum")
nodes/Die/position = Vector2(1280, 340)
nodes/OnParry/node = SubResource("AnimationNodeOneShot_lwjon")
nodes/OnParry/position = Vector2(1780, -40)
nodes/Parry/node = SubResource("AnimationNodeAnimation_calte")
nodes/Parry/position = Vector2(1600, 300)
node_connections = [&"output", 0, &"OnParry", &"OnHit", 0, &"OnMantle", &"OnHit", 1, &"hit1", &"OnJumpStart", 0, &"Idle", &"OnJumpStart", 1, &"jump_start", &"OnJumpEnd", 0, &"OnJumpStart", &"OnJumpEnd", 1, &"jump_end", &"OnMantle", 0, &"OnJumpEnd", &"OnMantle", 1, &"mantle", &"OnDie", 0, &"OnHit", &"OnDie", 1, &"Die", &"OnParry", 0, &"OnDie", &"OnParry", 1, &"Parry"]

View File

@@ -0,0 +1,14 @@
[gd_resource type="AnimationNodeStateMachine" format=3 uid="uid://3r5oeg0ho0d4"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_73q32"]
animation = &"idle"
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_adm0b"]
advance_mode = 2
[resource]
states/Start/position = Vector2(100, 91)
states/idle/node = SubResource("AnimationNodeAnimation_73q32")
states/idle/position = Vector2(331, 91)
transitions = ["Start", "idle", SubResource("AnimationNodeStateMachineTransition_adm0b")]
graph_offset = Vector2(-82, -9)

View File

@@ -0,0 +1,735 @@
[gd_scene format=3 uid="uid://0ysqmqphq6mq"]
[ext_resource type="Script" uid="uid://dtkdrnsmlwm67" path="res://scenes/player_controller/components/head/HeadSystem.cs" id="1_8abgy"]
[ext_resource type="ArrayMesh" uid="uid://ckr26s4e3fj1m" path="res://assets/meshes/swords/resources/fp_sword23.tres" id="2_c5qep"]
[ext_resource type="ArrayMesh" uid="uid://dogiv0piqfmfu" path="res://assets/meshes/swords/resources/fp_sword20.tres" id="3_1ay6d"]
[ext_resource type="AnimationNodeBlendTree" uid="uid://c26yvcyyyj811" path="res://scenes/player_controller/components/head/fp_blend_tree.tres" id="3_r0h40"]
[ext_resource type="Script" uid="uid://dnlxsrumw6ygp" path="res://addons/shaker/src/Vector3/shaker_component3D.gd" id="3_ubhf8"]
[ext_resource type="Script" uid="uid://0tu2q57qqu4s" path="res://addons/shaker/data/Vector3/BaseShakerType3D.gd" id="4_1ay6d"]
[ext_resource type="Script" uid="uid://ptaespkh1sk2" path="res://addons/shaker/data/Vector3/ShakerTypeNoiseShake3D.gd" id="5_sdjj3"]
[ext_resource type="Script" uid="uid://mlwdmecg12xd" path="res://addons/shaker/data/Vector3/ShakerPreset3D.gd" id="6_ll12k"]
[sub_resource type="FastNoiseLite" id="FastNoiseLite_ubhf8"]
frequency = 0.15
fractal_octaves = 1
[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_1ay6d"]
noise = SubResource("FastNoiseLite_ubhf8")
[sub_resource type="Resource" id="Resource_sdjj3"]
script = ExtResource("5_sdjj3")
noise_texture = SubResource("NoiseTexture3D_1ay6d")
amplitude = Vector3(0.1, 0.1, 0.1)
metadata/_custom_type_script = "uid://ptaespkh1sk2"
[sub_resource type="FastNoiseLite" id="FastNoiseLite_sdjj3"]
frequency = 0.1
[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_ll12k"]
noise = SubResource("FastNoiseLite_sdjj3")
[sub_resource type="Resource" id="Resource_dvot2"]
script = ExtResource("5_sdjj3")
noise_texture = SubResource("NoiseTexture3D_ll12k")
amplitude = Vector3(0.02, 0.02, 0.02)
metadata/_custom_type_script = "uid://ptaespkh1sk2"
[sub_resource type="Resource" id="Resource_60ouj"]
script = ExtResource("6_ll12k")
PositionShake = Array[ExtResource("4_1ay6d")]([SubResource("Resource_sdjj3")])
RotationShake = Array[ExtResource("4_1ay6d")]([SubResource("Resource_dvot2")])
metadata/_custom_type_script = "uid://mlwdmecg12xd"
[sub_resource type="FastNoiseLite" id="FastNoiseLite_1ay6d"]
frequency = 0.02
fractal_octaves = 1
[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_sdjj3"]
noise = SubResource("FastNoiseLite_1ay6d")
[sub_resource type="Resource" id="Resource_ll12k"]
script = ExtResource("5_sdjj3")
noise_texture = SubResource("NoiseTexture3D_sdjj3")
amplitude = Vector3(0.2, 0, 0)
metadata/_custom_type_script = "uid://ptaespkh1sk2"
[sub_resource type="FastNoiseLite" id="FastNoiseLite_ll12k"]
frequency = 0.02
fractal_octaves = 1
[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_se3kf"]
noise = SubResource("FastNoiseLite_ll12k")
[sub_resource type="Resource" id="Resource_0k6hv"]
script = ExtResource("5_sdjj3")
noise_texture = SubResource("NoiseTexture3D_se3kf")
amplitude = Vector3(0.1, 0.2, 0.1)
metadata/_custom_type_script = "uid://ptaespkh1sk2"
[sub_resource type="Resource" id="Resource_se3kf"]
script = ExtResource("6_ll12k")
PositionShake = Array[ExtResource("4_1ay6d")]([SubResource("Resource_ll12k")])
RotationShake = Array[ExtResource("4_1ay6d")]([SubResource("Resource_0k6hv")])
metadata/_custom_type_script = "uid://mlwdmecg12xd"
[sub_resource type="Animation" id="Animation_urko7"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("../../FPRig/Sword:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0.53640664, -0.7880347, -1.9288678)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("../../FPRig/Sword:rotation")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(-0.083978735, -1.136043, 0.19867715)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("../../FPRig/Sword:scale")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(1.0000001, 1.0000001, 1.0000005)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("..:rotation")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0.00011616433)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("..:position")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("../../FPRig/Parry:position")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(-0.22145952, -0.19867475, -1.3653086)]
}
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("../../FPRig/Parry:rotation")
tracks/6/interp = 1
tracks/6/loop_wrap = true
tracks/6/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0.9350104, 3.0957325, -1.9789876)]
}
tracks/7/type = "value"
tracks/7/imported = false
tracks/7/enabled = true
tracks/7/path = NodePath("../../FPRig/Parry:visible")
tracks/7/interp = 1
tracks/7/loop_wrap = true
tracks/7/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [true]
}
tracks/8/type = "bezier"
tracks/8/imported = false
tracks/8/enabled = true
tracks/8/path = NodePath("../../FPRig/Parry:rotation:x")
tracks/8/interp = 1
tracks/8/loop_wrap = true
tracks/8/keys = {
"handle_modes": PackedInt32Array(0),
"points": PackedFloat32Array(0.9350104, -0.15, 0, 0.15, 0),
"times": PackedFloat32Array(0)
}
tracks/9/type = "bezier"
tracks/9/imported = false
tracks/9/enabled = true
tracks/9/path = NodePath("../../FPRig/Parry:rotation:y")
tracks/9/interp = 1
tracks/9/loop_wrap = true
tracks/9/keys = {
"handle_modes": PackedInt32Array(0),
"points": PackedFloat32Array(3.0957325, -0.15, 0, 0.15, 0),
"times": PackedFloat32Array(0)
}
tracks/10/type = "bezier"
tracks/10/imported = false
tracks/10/enabled = true
tracks/10/path = NodePath("../../FPRig/Parry:rotation:z")
tracks/10/interp = 1
tracks/10/loop_wrap = true
tracks/10/keys = {
"handle_modes": PackedInt32Array(0),
"points": PackedFloat32Array(-1.9789876, -0.15, 0, 0.15, 0),
"times": PackedFloat32Array(0)
}
tracks/11/type = "value"
tracks/11/imported = false
tracks/11/enabled = true
tracks/11/path = NodePath("../../FPRig/Parry:scale")
tracks/11/interp = 1
tracks/11/loop_wrap = true
tracks/11/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(1.2, 1.2, 1.2)]
}
[sub_resource type="Animation" id="Animation_sdjj3"]
resource_name = "die"
length = 1.0000033
tracks/0/type = "method"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("../..")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(1),
"transitions": PackedFloat32Array(1),
"values": [{
"args": [],
"method": &"OnDeathAnimationFinished"
}]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("../../FPRig/Sword:position")
tracks/1/interp = 2
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.20000002, 0.4, 0.53333336, 0.8000001),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(0.53640664, -0.7880347, -1.9288678), Vector3(0.1057997, -0.21274538, -0.63147813), Vector3(0.53640664, 1.0949166, -1.9288678), Vector3(0.13969281, 3.1670854, 0.20333667), Vector3(0.14, -1.255, 0)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("../../FPRig/Sword:rotation")
tracks/2/interp = 2
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 0.20000002, 0.4, 0.53333336, 0.8000001),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(-0.083978735, -1.136043, 0.19867715), Vector3(-1.113491, -0.31576312, -0.983999), Vector3(-0.7104627, -0.98405164, -0.17152688), Vector3(0.111641094, -0.3489763, -2.955844), Vector3(0.11164107, -0.34897622, -2.955844)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("..:position")
tracks/3/interp = 2
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.20000002, 0.6333333),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, -0.35507536, 0.32742357), Vector3(0.219, -1.5, 1.166)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("..:rotation")
tracks/4/interp = 2
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0, 0.20000002, 0.6333333),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0.00011616433), Vector3(0, 0, -0.092299014), Vector3(0, 0, 1.2653637)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("../../FPRig/Parry:position")
tracks/5/interp = 2
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(0, 0.2),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(-0.22145952, -0.19867475, -1.3653086), Vector3(-1.3323143, -0.19867463, -1.7020192)]
}
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("../../FPRig/Parry:rotation")
tracks/6/interp = 2
tracks/6/loop_wrap = true
tracks/6/keys = {
"times": PackedFloat32Array(0, 0.2),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(0.9350104, 3.0957325, -1.9789876), Vector3(0.5242357, 2.32568, -3.0527115)]
}
tracks/7/type = "value"
tracks/7/imported = false
tracks/7/enabled = true
tracks/7/path = NodePath("../../FPRig/Parry:visible")
tracks/7/interp = 1
tracks/7/loop_wrap = true
tracks/7/keys = {
"times": PackedFloat32Array(0, 0.2),
"transitions": PackedFloat32Array(1, 1),
"update": 1,
"values": [true, false]
}
[sub_resource type="Animation" id="Animation_r0h40"]
resource_name = "hit1"
length = 0.30000168
step = 0.016666668
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("../../FPRig/Sword:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.06666667, 0.11666667, 0.15, 0.21666667, 0.3),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(0.53640664, -0.7880347, -1.9288678), Vector3(0.4045868, -0.4412415, -1.5352597), Vector3(-0.4799922, -0.5403832, -1.6861614), Vector3(-0.46995986, -0.53766656, -1.3638693), Vector3(-0.49520528, -0.5369735, -1.3145388), Vector3(-0.4048354, -0.5878634, -1.2836416)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("../../FPRig/Sword:rotation")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.06666667, 0.11666667, 0.15, 0.21666667, 0.3),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(-0.083978735, -1.136043, 0.19867715), Vector3(-0.7788485, -2.0049822, -0.2951485), Vector3(-0.94931036, -0.5881021, -0.61733377), Vector3(-1.3252386, -0.102411434, 0.58406436), Vector3(-1.2938086, -0.18945412, 0.7334958), Vector3(-1.1484056, -0.2900904, 0.6867544)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("../../FPRig/Sword:scale")
tracks/2/interp = 2
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 0.06666667, 0.11666667, 0.15, 0.21666667, 0.3),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(1.0000001, 1.0000001, 1.0000005), Vector3(1, 1.0004268, 1.0000002), Vector3(0.99999994, 1.2493719, 0.99999976), Vector3(1.0000001, 1.1750004, 1.0000004), Vector3(0.99999994, 0.99999994, 0.99999994), Vector3(1.0000001, 0.9999999, 1)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("..:rotation")
tracks/3/interp = 2
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.083333336, 0.11666667, 0.2, 0.23333333, 0.3),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(0, 0, 0.00011616433), Vector3(0, -0.02617994, -0.02617994), Vector3(0, 0.02617994, 0.02617994), Vector3(0, 0, 0)]
}
tracks/4/type = "method"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("../..")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0.083333336, 0.23333333),
"transitions": PackedFloat32Array(1, 1),
"values": [{
"args": [],
"method": &"OnHitboxActivated"
}, {
"args": [],
"method": &"OnHitboxDeactivated"
}]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("../../FPRig/Parry:position")
tracks/5/interp = 2
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(0, 0.033333335, 0.083333336, 0.16666667, 0.3),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(-0.22145952, -0.19867475, -1.3653086), Vector3(-0.0715476, -0.16325326, -0.8197592), Vector3(-0.36483923, -0.26392323, -1.3945884), Vector3(-0.8528395, -0.26392323, -1.2049117), Vector3(-0.8528395, -0.26392323, -1.2049117)]
}
[sub_resource type="Animation" id="Animation_0hyrq"]
resource_name = "idle"
length = 2.0
loop_mode = 1
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("../../FPRig/Sword:position")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.3, 0.6, 1, 1.4),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(0.53640664, -0.7880347, -1.9288678), Vector3(0.53640664, -0.83580256, -1.9288678), Vector3(0.53640664, -0.86088884, -1.9288678), Vector3(0.53640664, -0.8256072, -1.9288678), Vector3(0.53640664, -0.7880347, -1.9288678)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("../../FPRig/Sword:rotation")
tracks/1/interp = 2
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.3, 0.6, 1, 1.4),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(-0.083978735, -1.136043, 0.19867715), Vector3(-0.06987281, -1.1365474, 0.20524277), Vector3(-0.05990464, -1.1368362, 0.20987195), Vector3(-0.06303402, -1.1367121, 0.2084137), Vector3(-0.083978735, -1.136043, 0.19867715)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("../../FPRig/Parry:position")
tracks/2/interp = 2
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 0.3, 0.8000001),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(-0.22145952, -0.19867475, -1.3653086), Vector3(-0.221, -0.211, -1.365), Vector3(-0.221, -0.16, -1.365)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("../../FPRig/Parry:rotation")
tracks/3/interp = 2
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.3, 0.8000001),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0.9350104, 3.0957325, -1.9789876), Vector3(0.93194425, 3.0397656, -2.0486145), Vector3(0.9362563, 3.1298003, -1.9366695)]
}
[sub_resource type="Animation" id="Animation_1ay6d"]
resource_name = "jump_end"
length = 0.26667002
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("..:rotation")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.13333334, 0.26666668),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0.00011616433), Vector3(-0.08726646, 0, 0), Vector3(0, 0, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("..:position")
tracks/1/interp = 2
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.06666667, 0.26666668),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, -0.05, 0), Vector3(0, 0, 0)]
}
[sub_resource type="Animation" id="Animation_ubhf8"]
resource_name = "jump_start"
length = 0.26667002
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("..:position")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.06666667, 0.26666668),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, -0.1, 0), Vector3(0, 0, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("..:rotation")
tracks/1/interp = 2
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.13333334, 0.26666668),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0.00011616433), Vector3(-0.08726646, 0, 0), Vector3(0, 0, 0)]
}
[sub_resource type="Animation" id="Animation_8abgy"]
resource_name = "mantle"
length = 0.3
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("..:rotation")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.1, 0.3),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0.00011616433), Vector3(-0.5235988, 0, 0), Vector3(0, 0, 0)]
}
[sub_resource type="Animation" id="Animation_ll12k"]
resource_name = "parry"
length = 0.3
step = 0.016666668
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("../../FPRig/Parry:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.083333336, 0.13333334, 0.16666667, 0.20000002, 0.3),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(-0.22145952, -0.19867475, -1.3653086), Vector3(0.08582078, -0.10871372, -0.57329714), Vector3(0.23993218, -0.07025133, -0.8836378), Vector3(0.2783246, -0.07025109, -0.9678366), Vector3(0.2897812, -0.07025109, -0.8572479), Vector3(-0.22145952, -0.19867475, -1.3653086)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("../../FPRig/Sword:position")
tracks/1/interp = 2
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.06666667, 0.15, 0.21666668, 0.3),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(0.53640664, -0.7880347, -1.9288678), Vector3(0.35144368, -0.7880347, -0.88497114), Vector3(0.87958574, -0.7880347, -1.4807583), Vector3(0.87958574, -0.7880347, -1.4807583), Vector3(0.53640664, -0.7880347, -1.9288678)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("../../FPRig/Sword:rotation")
tracks/2/interp = 2
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 0.06666667, 0.15, 0.21666668, 0.3),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(-0.083978735, -1.136043, 0.19867715), Vector3(0.012032291, -1.1376454, 0.24317425), Vector3(0.012032287, -1.8018653, 0.24317427), Vector3(0.012032287, -1.8018653, 0.24317427), Vector3(-0.083978735, -1.136043, 0.19867715)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("..:rotation")
tracks/3/interp = 2
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.016666666, 0.1, 0.16666667, 0.2, 0.3),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(0, 0, 0.05235988), Vector3(0, -0.05235988, -0.10471976), Vector3(0, 0.02617994, 0.05235988), Vector3(0, 0, 0)]
}
tracks/4/type = "method"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("../..")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0.06666667, 0.18333334),
"transitions": PackedFloat32Array(1, 1),
"values": [{
"args": [],
"method": &"OnParryboxActivated"
}, {
"args": [],
"method": &"OnParryboxDeactivated"
}]
}
tracks/5/type = "bezier"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("../../FPRig/Parry:rotation:x")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
"handle_modes": PackedInt32Array(0, 0, 2, 2, 2, 0),
"points": PackedFloat32Array(0.9350104, -0.15, 0, 0.033333335, 0.17374629, 0.98194534, -0.01666667, 0.016720235, 0, 0, 1.4891908, -0.03333334, -0.06340563, 0, 0, 1.5010982, -0.005555555, 0, 0, 0, 1.3694806, -0.008333336, 0.021936258, 0, 0, 0.9350104, -0.03333333, 0.17374629, 0.033333335, 0.17374629),
"times": PackedFloat32Array(0, 0.083333336, 0.13333334, 0.16666667, 0.21666668, 0.3)
}
tracks/6/type = "bezier"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("../../FPRig/Parry:rotation:y")
tracks/6/interp = 1
tracks/6/loop_wrap = true
tracks/6/keys = {
"handle_modes": PackedInt32Array(0, 0, 2, 2, 2, 0),
"points": PackedFloat32Array(3.0957325, -0.15, 0, 0.05, -0.045176744, 2.8761902, -0.033333335, 0.30117726, 0, 0, 2.9792244, -0.03333334, -0.25362277, 0, 0, 2.9158187, -0.016666666, 0.11096001, 0, 0, 2.8365617, -0.01666668, -0.18834376, 0, 0, 3.0957325, -0.050000012, -0.21161652, 0.05, -0.045176744),
"times": PackedFloat32Array(0, 0.083333336, 0.13333334, 0.16666667, 0.21666668, 0.3)
}
tracks/7/type = "bezier"
tracks/7/imported = false
tracks/7/enabled = true
tracks/7/path = NodePath("../../FPRig/Parry:rotation:z")
tracks/7/interp = 1
tracks/7/loop_wrap = true
tracks/7/keys = {
"handle_modes": PackedInt32Array(0, 0, 2, 2, 2, 0),
"points": PackedFloat32Array(-1.9789876, -0.15, 0, 0.016666668, 0.6069969, -1.5225792, -0.01666667, 0.26527464, 0, 0, -0.9026986, -0.011111112, -0.101292565, 0, 0, -0.90269864, -0.005555555, 9.934108e-09, 0, 0, -1.642684, -0.008333336, 0.1233309, 0, 0, -1.9789876, -0.050000012, 0.13937998, 0.016666668, 0.6069969),
"times": PackedFloat32Array(0, 0.083333336, 0.13333334, 0.16666667, 0.21666668, 0.3)
}
tracks/8/type = "value"
tracks/8/imported = false
tracks/8/enabled = true
tracks/8/path = NodePath("../../FPRig/Parry:scale")
tracks/8/interp = 2
tracks/8/loop_wrap = true
tracks/8/keys = {
"times": PackedFloat32Array(0, 0.083333336, 0.13333334, 0.16666667, 0.3),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
"update": 0,
"values": [Vector3(1, 1, 1), Vector3(1.2, 1.2, 1.2), Vector3(1.65, 1, 1), Vector3(1, 1, 1), Vector3(1, 1, 1)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_0hyrq"]
_data = {
&"RESET": SubResource("Animation_urko7"),
&"die": SubResource("Animation_sdjj3"),
&"hit1": SubResource("Animation_r0h40"),
&"idle": SubResource("Animation_0hyrq"),
&"jump_end": SubResource("Animation_1ay6d"),
&"jump_start": SubResource("Animation_ubhf8"),
&"mantle": SubResource("Animation_8abgy"),
&"parry": SubResource("Animation_ll12k")
}
[node name="HeadSystem" type="Node3D" unique_id=2067407038]
script = ExtResource("1_8abgy")
WeaponMoveRotation = 20.0
DisplacedWeaponSway = 1.0
DisplacedWeaponAdjustmentSpeed = 8.0
[node name="FPRig" type="Node3D" parent="." unique_id=922968399]
transform = Transform3D(0.9999998, 0, 0, 0, 1.0000002, 0, 0, 0, 1.0000002, 0, 0, 0)
[node name="Sword" type="Node3D" parent="FPRig" unique_id=1946191657]
transform = Transform3D(0.42791694, -0.008550272, -0.9037781, 0.19667713, 0.9768738, 0.0838801, 0.88215953, -0.2136461, 0.41970265, 0.53640664, -0.7880347, -1.9288678)
[node name="SwordMesh" type="MeshInstance3D" parent="FPRig/Sword" unique_id=1887561286]
transform = Transform3D(1, 0, 0, 0, 0.99999994, 0, 0, 0, 1, 0, 0, 0)
cast_shadow = 0
mesh = ExtResource("2_c5qep")
[node name="Parry" type="Node3D" parent="FPRig" unique_id=1218775403]
transform = Transform3D(0.43521196, -1.1178209, 0.03266725, -0.65402746, -0.2828554, -0.96552634, 0.9071047, 0.33236945, -0.711823, -0.22145952, -0.19867475, -1.3653086)
[node name="ParryMesh" type="MeshInstance3D" parent="FPRig/Parry" unique_id=1993291456]
mesh = ExtResource("3_1ay6d")
[node name="CameraSmooth" type="Node3D" parent="." unique_id=2072010960]
transform = Transform3D(0.9999998, -0.00011616429, 0, 0.00011616431, 0.99999964, 0, 0, 0, 0.99999976, 0, 0, 0)
[node name="Camera3D" type="Camera3D" parent="CameraSmooth" unique_id=544372058]
transform = Transform3D(1, 0, 0, 0, 1.0000002, 0, 0, 0, 1.0000001, 0, 0, 0)
current = true
fov = 90.0
[node name="OnGetHitShaker" type="Node3D" parent="CameraSmooth/Camera3D" unique_id=1644568585]
transform = Transform3D(1, 0, 0, -7.275958e-12, 0.99999976, 0, 0, 0, 0.99999976, 0, 1.8626451e-09, 3.7252903e-09)
script = ExtResource("3_ubhf8")
intensity = 1.2
duration = 0.5
fade_in = 0.06470415
fade_out = 0.46651623
shakerPreset = SubResource("Resource_60ouj")
metadata/_custom_type_script = "uid://dnlxsrumw6ygp"
[node name="OnHitShaker" type="Node3D" parent="CameraSmooth/Camera3D" unique_id=1445921461]
transform = Transform3D(1, 0, 0, -7.275958e-12, 0.99999976, 0, 0, 0, 0.99999976, 0, 1.8626451e-09, 3.7252903e-09)
script = ExtResource("3_ubhf8")
duration = 0.3
fade_in = 0.041234624
fade_out = 0.5547845
shakerPreset = SubResource("Resource_se3kf")
metadata/_custom_type_script = "uid://dnlxsrumw6ygp"
[node name="CameraAnchor" type="Marker3D" parent="." unique_id=1554357312]
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=1831491746]
root_node = NodePath("../CameraSmooth/Camera3D")
libraries/ = SubResource("AnimationLibrary_0hyrq")
[node name="AnimationTree" type="AnimationTree" parent="." unique_id=1817901670]
root_node = NodePath("../CameraSmooth/Camera3D")
tree_root = ExtResource("3_r0h40")
anim_player = NodePath("../AnimationPlayer")
parameters/OnHit/active = false
parameters/OnHit/internal_active = false
parameters/OnHit/request = 0
parameters/OnJumpStart/active = false
parameters/OnJumpStart/internal_active = false
parameters/OnJumpStart/request = 0
parameters/OnJumpEnd/active = false
parameters/OnJumpEnd/internal_active = false
parameters/OnJumpEnd/request = 0
parameters/OnMantle/active = false
parameters/OnMantle/internal_active = false
parameters/OnMantle/request = 0
parameters/OnDie/active = false
parameters/OnDie/internal_active = false
parameters/OnDie/request = 0
parameters/OnParry/active = false
parameters/OnParry/internal_active = false
parameters/OnParry/request = 0
[connection signal="GotHit" from="." to="CameraSmooth/Camera3D/OnGetHitShaker" method="play_shake"]
[connection signal="HitTarget" from="." to="CameraSmooth/Camera3D/OnHitShaker" method="play_shake"]

View File

@@ -0,0 +1,114 @@
using Godot;
using RustyOptions;
namespace Movementtests.systems;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_follower.png")]
public partial class MantleSystem: Node3D
{
[Export(PropertyHint.Range, "0,2,0.01,suffix:m,or_greater")]
public float MantleEndLocationDistanceFromWall { get; set; } = 1f;
[Export(PropertyHint.Range, "0,10,0.1,suffix:m,or_greater")]
public float MantleHeightCastStart { get; set; } = 2f;
[Export(PropertyHint.Range, "0,10,0.01,suffix:m,or_greater")]
public float MaxStepHeight = 0.5f;
private ShapeCast3D _wallInFrontCast3D;
private ShapeCast3D _mantleCast3D;
private ShapeCast3D _inAirWallDetect;
private ShapeCast3D _groundedWallDetect;
public Curve3D MantleCurve { get; private set; }
public Vector3 FirstMantleProfilePoint { get; private set; } = Vector3.Zero;
public bool IsMantlePossible { get; private set; } = false;
public bool EndedOnOtherSideOfWall { get; private set; } = false;
public bool FoundGround { get; private set; } = false;
public const int WallProfileCastCount = 7;
private ShapeCast3D[] _wallProfileShapecasts = new ShapeCast3D[WallProfileCastCount];
public void Init()
{
_wallInFrontCast3D = GetNode<ShapeCast3D>("WallInFrontCast3D");
_mantleCast3D = GetNode<ShapeCast3D>("MantleCast3D");
_inAirWallDetect = GetNode<ShapeCast3D>("InAirWallDetect");
_groundedWallDetect = GetNode<ShapeCast3D>("GroundedWallDetect");
for (int i = 0; i < _wallProfileShapecasts.Length; i++)
{
_wallProfileShapecasts[i] = GetNode<ShapeCast3D>($"WallProfileShapeCasts/ShapeCast{i + 1}");
}
}
private void SetCastsEnabled(bool enabled)
{
foreach (var wallProfileShapecast in _wallProfileShapecasts)
{
wallProfileShapecast.SetEnabled(enabled);
}
}
public void ProcessMantle(bool isGrounded)
{
_inAirWallDetect.SetEnabled(!isGrounded);
_groundedWallDetect.SetEnabled(isGrounded);
var isColliding = _inAirWallDetect.IsColliding() || _groundedWallDetect.IsColliding();
SetCastsEnabled(isColliding);
// Reset state
IsMantlePossible = false;
EndedOnOtherSideOfWall = false;
FoundGround = false;
if (!isColliding) return;
// Check if face something wall-like that should be climbable
var collisionNormal = isGrounded ? _groundedWallDetect.GetCollisionNormal(0) : _inAirWallDetect.GetCollisionNormal(0);
if (collisionNormal.Y > 0.7f) return;
var spaceState = GetWorld3D().DirectSpaceState;
MantleCurve = new Curve3D();
MantleCurve.AddPoint(Vector3.Zero);
var hasFirstProfileHit = false;
var previousProfilePoint = GlobalPosition;
foreach (var wallProfileShapecast in _wallProfileShapecasts)
{
// Haven't met the wall yet
if (!wallProfileShapecast.IsColliding() && !hasFirstProfileHit) continue;
var globalTargetPosition = wallProfileShapecast.GlobalPosition + wallProfileShapecast.TargetPosition;
// Got to the other side of the wall, we stop there
if (!wallProfileShapecast.IsColliding())
{
break;
}
var profilePoint = wallProfileShapecast.GetCollisionPoint(0);
var profileNormal = wallProfileShapecast.GetCollisionNormal(0);
var shape = wallProfileShapecast.Shape as SphereShape3D;
var shapeRadius = shape == null ? 0.125f : shape.Radius;
var centerOfShape = profilePoint + profileNormal * shapeRadius;
// Check if we collided parallel to a wall
var isCollisionSameAsTarget = globalTargetPosition.IsEqualApprox(centerOfShape);
var isCollidingWithWall = profileNormal.Y < 0.1f;
if (isCollisionSameAsTarget || isCollidingWithWall) continue;
// Check if the path from the previous point makes us go through a wall
var query = PhysicsRayQueryParameters3D.Create(previousProfilePoint, centerOfShape, wallProfileShapecast.CollisionMask);
var result = spaceState.IntersectRay(query);
if (result.Count > 0) break; // We are going through a wall, we stop there
// We have a valid collision
if (!hasFirstProfileHit) FirstMantleProfilePoint = centerOfShape;
hasFirstProfileHit = true;
previousProfilePoint = centerOfShape;
MantleCurve.AddPoint(ToLocal(centerOfShape));
}
if (MantleCurve.PointCount == 1) return;
IsMantlePossible = true;
}
}

View File

@@ -0,0 +1 @@
uid://bja6tis1vaysu

View File

@@ -0,0 +1,4 @@
[gd_resource type="SphereShape3D" format=3 uid="uid://dp2p8v7demb5j"]
[resource]
radius = 0.25

View File

@@ -0,0 +1,104 @@
[gd_scene format=3 uid="uid://wq1okogkhc5l"]
[ext_resource type="Script" uid="uid://bja6tis1vaysu" path="res://scenes/player_controller/components/mantle/MantleSystem.cs" id="1_2oobp"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_4coqe"]
height = 1.7
[sub_resource type="SphereShape3D" id="SphereShape3D_2oobp"]
radius = 0.75
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_2oobp"]
radius = 0.25
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_i32qj"]
radius = 0.25
height = 1.5
[sub_resource type="SphereShape3D" id="SphereShape3D_i32qj"]
radius = 0.125
[node name="MantleSystem" type="Node3D" unique_id=1117790260]
script = ExtResource("1_2oobp")
MantleEndLocationDistanceFromWall = 0.2
MantleHeightCastStart = 3.0
[node name="MantleCast3D" type="ShapeCast3D" parent="." unique_id=977434819]
visible = false
shape = SubResource("CapsuleShape3D_4coqe")
target_position = Vector3(0, 0, 0)
max_results = 1
collision_mask = 256
debug_shape_custom_color = Color(1, 0, 0, 1)
[node name="WallInFrontCast3D" type="ShapeCast3D" parent="." unique_id=774357590]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
visible = false
shape = SubResource("SphereShape3D_2oobp")
target_position = Vector3(0, 0, -1.5)
max_results = 1
collision_mask = 256
debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1)
[node name="InAirWallDetect" type="ShapeCast3D" parent="." unique_id=276043236]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.01, 0)
shape = SubResource("CapsuleShape3D_2oobp")
target_position = Vector3(0, 0, -2)
collision_mask = 256
[node name="GroundedWallDetect" type="ShapeCast3D" parent="." unique_id=1673208243]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.26, 0)
shape = SubResource("CapsuleShape3D_i32qj")
target_position = Vector3(0, 0, -2)
collision_mask = 256
[node name="WallProfileShapeCasts" type="Node3D" parent="." unique_id=857147957]
[node name="ShapeCast1" type="ShapeCast3D" parent="WallProfileShapeCasts" unique_id=1271662121]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -0.5)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 256
[node name="ShapeCast2" type="ShapeCast3D" parent="WallProfileShapeCasts" unique_id=147611166]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -0.75)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 256
[node name="ShapeCast3" type="ShapeCast3D" parent="WallProfileShapeCasts" unique_id=1248645023]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -1)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 256
[node name="ShapeCast4" type="ShapeCast3D" parent="WallProfileShapeCasts" unique_id=839558141]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -1.25)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 256
[node name="ShapeCast5" type="ShapeCast3D" parent="WallProfileShapeCasts" unique_id=886271592]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -1.5)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 256
[node name="ShapeCast6" type="ShapeCast3D" parent="WallProfileShapeCasts" unique_id=1927435390]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -1.75)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 256
[node name="ShapeCast7" type="ShapeCast3D" parent="WallProfileShapeCasts" unique_id=2112972214]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -2)
enabled = false
shape = SubResource("SphereShape3D_i32qj")
target_position = Vector3(0, -2.125, 0)
collision_mask = 256

View File

@@ -0,0 +1,196 @@
using System;
using Godot;
using GodotStateCharts;
using Movementtests.interfaces;
using Movementtests.systems.damage;
namespace Movementtests.systems;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_sword.png")]
public partial class WeaponSystem : RigidBody3D, IDamageDealer
{
[Signal]
public delegate void WeaponThrownEventHandler();
[Signal]
public delegate void WeaponRetrievedEventHandler();
[Export]
public RDamage RDamage { get; set; }
[Export(PropertyHint.Range, "0,100,1,or_greater")]
public float ThrowForce { get; set; } = 1f;
[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 ShapeCast3D _dashCast3D;
private Transform3D _startTransform;
private Vector3 _startMeshRotation;
private Vector3 _throwDirection;
public Vector3 PlantLocation { get; set; }
public Vector3 PlantNormal { get; set; }
public Node PlantObject { get; set; }
public MeshInstance3D WeaponLocationIndicator { get; set; }
public StandardMaterial3D WeaponLocationIndicatorMaterial { get; set; }
public MeshInstance3D WeaponMesh { get; set; }
public void Init()
{
_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"));
WeaponLocationIndicator = GetNode<MeshInstance3D>("WeaponLocationIndicator");
WeaponLocationIndicator.Visible = false;
WeaponLocationIndicatorMaterial = WeaponLocationIndicator.GetActiveMaterial(0) as StandardMaterial3D;
WeaponMesh = GetNode<MeshInstance3D>("Weapon");
_startMeshRotation = WeaponMesh.Rotation;
_startTransform = Transform;
Freeze = true;
Visible = false;
BodyEntered += OnThrownWeaponReachesGround;
InHandState.StateExited += WeaponLeft;
InHandState.StateEntered += WeaponBack;
}
public void WeaponLeft()
{
Visible = true;
// WeaponLocationIndicator.Visible = true;
EmitSignalWeaponThrown();
}
public void WeaponBack()
{
Visible = false;
// WeaponLocationIndicator.Visible = false;
EmitSignalWeaponRetrieved();
}
public void PlaceWeaponForTutorial(Vector3 location)
{
_weaponState.SendEvent("plant");
Freeze = true;
GlobalPosition = location;
PlantLocation = location;
}
public void ThrowWeapon(Vector3 end, bool hasHit, Vector3 collisionLocation, Vector3 collisionNormal, Node collidedObject)
{
_weaponState.SendEvent("throw");
// WeaponLocationIndicatorMaterial.StencilColor = new Color(1f, 1f, 1f);
_throwDirection = (end - GlobalPosition).Normalized();
PlantLocation = collisionLocation;
PlantNormal = collisionNormal;
LookAt(end);
var tween = GetTree().CreateTween();
tween.SetParallel(true);
tween.TweenProperty(this, "global_position", end, StraightThrowDuration);
if (hasHit)
{
PlantObject = collidedObject;
tween.Finished += PlantWeaponInWall;
}
else
tween.Finished += ThrowWeaponOnCurve;
}
public void PlantInEnemy(Node3D enemy)
{
GetTree().GetRoot().CallDeferred(Node.MethodName.RemoveChild, this);
enemy.CallDeferred(Node.MethodName.AddChild, this);
if (enemy is IDamageable damageable)
{
damageable.TakeDamage(new DamageRecord(GlobalPosition, RDamage));
}
}
public void RethrowWeapon()
{
_weaponState.SendEvent("throw");
_throwDirection = Vector3.Up;
ThrowWeaponOnCurve();
}
public void ThrowWeaponOnCurve()
{
Freeze = false;
ApplyImpulse(_throwDirection * ThrowForce);
}
public void PlantWeaponInWall()
{
_weaponState.SendEvent("plant");
Freeze = true;
WeaponMesh.Rotation = _startMeshRotation;
// WeaponLocationIndicatorMaterial.StencilColor = new Color(1f, 0.2f, 0.2f);
if (PlantObject is Node3D node)
{
PlantInEnemy(node);
}
CallDeferred(Node3D.MethodName.SetGlobalPosition, PlantLocation);
CallDeferred(Node3D.MethodName.LookAt, GlobalTransform.Origin + PlantNormal, Vector3.Up, true);
}
public void OnThrownWeaponReachesGround(Node other)
{
PlantObject = other;
PlantWeaponInWall();
}
public void ResetWeapon()
{
_weaponState.SendEvent("recover");
Transform = _startTransform;
Freeze = true;
Visible = false;
}
public override void _IntegrateForces(PhysicsDirectBodyState3D state)
{
base._IntegrateForces(state);
if (!Freeze && state.GetContactCount() > 0)
{
PlantLocation = state.GetContactLocalPosition(0);
PlantNormal = state.GetContactLocalNormal(0);
}
}
public override void _Process(double delta)
{
if (!FlyingState.Active) return;
WeaponMesh.Rotation = new Vector3(WeaponMesh.Rotation.X, WeaponMesh.Rotation.Y + (float) delta * 100, WeaponMesh.Rotation.Z);
//LookAt(GlobalTransform.Origin + LinearVelocity.Normalized(), Vector3.Up, false);
}
public bool IsPlantedUnderPlatform()
{
return PlantedState.Active && GlobalRotation.X > 1 && Math.Abs(GlobalRotation.Y) > 1;
}
public bool IsPlantedInWall()
{
return PlantedState.Active && Math.Abs(GlobalRotation.X) + Math.Abs(GlobalRotation.Z) < 0.3;
}
}

View File

@@ -0,0 +1 @@
uid://iii3wfto4t5b

View File

@@ -0,0 +1,5 @@
extends MeshInstance3D
func _on_weapon_retrieved_body_entered(body: Node3D) -> void:
visible = false

View File

@@ -0,0 +1 @@
uid://v4nnql2laqdn

View File

@@ -0,0 +1,13 @@
[gd_resource type="CylinderMesh" format=3 uid="uid://b7vt0nk2htpo4"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_jv82r"]
use_z_clip_scale = true
z_clip_scale = 0.9
use_fov_override = true
fov_override = 70.0
[resource]
material = SubResource("StandardMaterial3D_jv82r")
top_radius = 0.0
bottom_radius = 0.05
height = 1.0

View File

@@ -0,0 +1,109 @@
[gd_scene format=3 uid="uid://ckm3d6k08a72u"]
[ext_resource type="Script" uid="uid://iii3wfto4t5b" path="res://scenes/player_controller/components/weapon/WeaponSystem.cs" id="1_csqwk"]
[ext_resource type="Script" uid="uid://jitubgv6judn" path="res://scenes/components/damage/RDamage.cs" id="2_m0v1h"]
[ext_resource type="Script" uid="uid://couw105c3bde4" path="res://addons/godot_state_charts/state_chart.gd" id="3_5owyf"]
[ext_resource type="ArrayMesh" uid="uid://cho5fixitrbds" path="res://assets/meshes/swords/resources/sword23.tres" id="3_svc06"]
[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="Resource" id="Resource_jpdh0"]
script = ExtResource("2_m0v1h")
DamageDealt = 2.0
metadata/_custom_type_script = "uid://jitubgv6judn"
[sub_resource type="CylinderShape3D" id="CylinderShape3D_avini"]
height = 1.0
radius = 0.1
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_svc06"]
render_priority = 1
transparency = 1
no_depth_test = true
shading_mode = 0
grow_amount = 0.1
stencil_mode = 3
stencil_flags = 1
stencil_compare = 5
metadata/_stencil_owned = true
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m0v1h"]
next_pass = SubResource("StandardMaterial3D_svc06")
transparency = 1
albedo_color = Color(1, 1, 1, 0)
z_clip_scale = 0.1
stencil_mode = 2
stencil_flags = 2
stencil_color = Color(1, 1, 1, 1)
stencil_outline_thickness = 0.1
[sub_resource type="SphereMesh" id="SphereMesh_jpdh0"]
material = SubResource("StandardMaterial3D_m0v1h")
[node name="Weapon" type="RigidBody3D" unique_id=831063023]
collision_layer = 65536
collision_mask = 304
continuous_cd = true
contact_monitor = true
max_contacts_reported = 1
script = ExtResource("1_csqwk")
RDamage = SubResource("Resource_jpdh0")
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=884463982]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0)
shape = SubResource("CylinderShape3D_avini")
[node name="Weapon" type="MeshInstance3D" parent="." unique_id=1970473659]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0.8673003)
mesh = ExtResource("3_svc06")
[node name="WeaponLocationIndicator" type="MeshInstance3D" parent="." unique_id=406396593]
mesh = SubResource("SphereMesh_jpdh0")
[node name="StateChart" type="Node" parent="." unique_id=1135887603]
script = ExtResource("3_5owyf")
metadata/_custom_type_script = "uid://couw105c3bde4"
[node name="Root" type="Node" parent="StateChart" unique_id=1816439862]
script = ExtResource("4_svc06")
initial_state = NodePath("InHand")
[node name="ToPlanted" type="Node" parent="StateChart/Root" unique_id=357013486]
script = ExtResource("6_jpdh0")
to = NodePath("../Planted")
event = &"plant"
delay_in_seconds = "0.0"
[node name="InHand" type="Node" parent="StateChart/Root" unique_id=1828871728]
script = ExtResource("5_m0v1h")
[node name="ToFlying" type="Node" parent="StateChart/Root/InHand" unique_id=1644664016]
script = ExtResource("6_jpdh0")
to = NodePath("../../Flying")
event = &"throw"
delay_in_seconds = "0.0"
[node name="Flying" type="Node" parent="StateChart/Root" unique_id=861606667]
script = ExtResource("5_m0v1h")
[node name="ToHand" type="Node" parent="StateChart/Root/Flying" unique_id=1236392249]
script = ExtResource("6_jpdh0")
to = NodePath("../../InHand")
event = &"recover"
delay_in_seconds = "0.0"
[node name="Planted" type="Node" parent="StateChart/Root" unique_id=1036062749]
script = ExtResource("5_m0v1h")
[node name="ToFlying" type="Node" parent="StateChart/Root/Planted" unique_id=1472568793]
script = ExtResource("6_jpdh0")
to = NodePath("../../Flying")
event = &"throw"
delay_in_seconds = "0.0"
[node name="ToHand" type="Node" parent="StateChart/Root/Planted" unique_id=627081934]
script = ExtResource("6_jpdh0")
to = NodePath("../../InHand")
event = &"recover"
delay_in_seconds = "0.0"

View File

@@ -0,0 +1,11 @@
[gd_resource type="CylinderMesh" format=3 uid="uid://bhkbwvuft1bpg"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_f5qr4"]
z_clip_scale = 0.9
fov_override = 70.0
[resource]
material = SubResource("StandardMaterial3D_f5qr4")
top_radius = 0.0
bottom_radius = 0.05
height = 1.0