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,21 @@
MIT License
Copyright (c) 2025 PolarBears studio
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,73 @@
using Godot;
using System;
using Movementtests.interfaces;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/control/icon_text_panel.png")]
public partial class PlayerUi : Control
{
private TextureRect[] _dashIcons = new TextureRect[3];
private TextureRect _enemyTarget;
private Healthbar _healthbar;
public enum TargetState
{
NoTarget,
TargetWouldNotKill,
TargetWouldKill
}
public record TargetProperties(TargetState State, Vector2 Position);
[Export]
public Color WouldKillColor { get; set; } = new Color("009c8f");
[Export]
public Color WouldNotKillColor { get; set; } = new Color("fc001c");
public override void _Ready()
{
_dashIcons[0] = GetNode<TextureRect>("%Dash1");
_dashIcons[1] = GetNode<TextureRect>("%Dash2");
_dashIcons[2] = GetNode<TextureRect>("%Dash3");
_enemyTarget = GetNode<TextureRect>("%EnemyTarget");
_healthbar = GetNode<Healthbar>("%Healthbar");
}
public void Initialize(float initialHealth)
{
_healthbar.Initialize(initialHealth);
}
public void SetEnemyTargetProperties(TargetProperties targetProperties)
{
var (state, position) = targetProperties;
var visible = state != TargetState.NoTarget;
var modulation = state switch
{
TargetState.TargetWouldNotKill => WouldNotKillColor,
TargetState.TargetWouldKill => WouldKillColor,
_ => WouldNotKillColor
};
_enemyTarget.SetVisible(visible);
_enemyTarget.SetPosition(position - _enemyTarget.Size / 2);
_enemyTarget.SetModulate(modulation);
}
public void SetNumberOfDashesLeft(int numberOfDashes)
{
int index = 1;
foreach (var dashIcon in _dashIcons)
{
dashIcon.SetVisible(index <= numberOfDashes);
index++;
}
}
public void OnHealthChanged(IHealthable healthable, HealthChangedRecord healthChanged)
{
_healthbar.CurrentHealth = healthChanged.CurrentHealth;
}
}

View File

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

View File

@@ -0,0 +1,119 @@
[gd_resource type="AudioStreamInteractive" format=3 uid="uid://clfggn87oeg1s"]
[ext_resource type="AudioStream" uid="uid://dedx5ronjavvh" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Footsteps/Dirt/Dirt Run 1.ogg" id="1_tkpjh"]
[ext_resource type="AudioStream" uid="uid://gihwx3xm7qoq" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Footsteps/Dirt/Dirt Run 2.ogg" id="2_npc7y"]
[ext_resource type="AudioStream" uid="uid://qr5qyql01rf5" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Footsteps/Dirt/Dirt Run 3.ogg" id="3_xfjxc"]
[ext_resource type="AudioStream" uid="uid://blbvci0fvniy3" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Footsteps/Dirt/Dirt Run 4.ogg" id="4_ycvo6"]
[ext_resource type="AudioStream" uid="uid://d01n6qtsadqvm" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Footsteps/Dirt/Dirt Run 5.ogg" id="5_5bvpy"]
[ext_resource type="AudioStream" uid="uid://2joty7h4guqs" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Footsteps/Dirt/Dirt Jump.ogg" id="6_w27l5"]
[ext_resource type="AudioStream" uid="uid://d0pwtd271fukd" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Footsteps/Dirt/Dirt Land.ogg" id="7_5j00h"]
[ext_resource type="AudioStream" uid="uid://co335a0d00667" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Attacks/Sword Attacks Hits and Blocks/Sword Attack 1.ogg" id="8_r7v0u"]
[ext_resource type="AudioStream" uid="uid://dtl4blkueud3n" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Attacks/Sword Attacks Hits and Blocks/Sword Attack 2.ogg" id="9_l756u"]
[ext_resource type="AudioStream" uid="uid://bd8n4slwggxrq" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Attacks/Sword Attacks Hits and Blocks/Sword Attack 3.ogg" id="10_7b65l"]
[ext_resource type="AudioStream" uid="uid://jwy682rlwm2v" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Attacks/Sword Attacks Hits and Blocks/Sword Impact Hit 1.ogg" id="11_447ch"]
[ext_resource type="AudioStream" uid="uid://cn6j83octlmg1" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Attacks/Sword Attacks Hits and Blocks/Sword Impact Hit 2.ogg" id="12_1yt5p"]
[ext_resource type="AudioStream" uid="uid://buqmqota12r4g" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Attacks/Sword Attacks Hits and Blocks/Sword Impact Hit 3.ogg" id="13_t5u7s"]
[ext_resource type="AudioStream" uid="uid://cm4332loplxmb" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Attacks/Sword Attacks Hits and Blocks/Sword Blocked 1.ogg" id="14_qnngs"]
[ext_resource type="AudioStream" uid="uid://dhw1imlbuu7nl" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Attacks/Sword Attacks Hits and Blocks/Sword Blocked 2.ogg" id="15_3j1dm"]
[ext_resource type="AudioStream" uid="uid://bis0qp2jqrwl7" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Attacks/Sword Attacks Hits and Blocks/Sword Blocked 3.ogg" id="16_hln0b"]
[ext_resource type="AudioStream" uid="uid://dka35ab4pudfn" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Footsteps/Dirt/Dirt Chain Jump.ogg" id="17_npc7y"]
[ext_resource type="AudioStream" uid="uid://4rhskycj4qqp" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Spells/Fireball 1.ogg" id="18_ycvo6"]
[ext_resource type="AudioStream" uid="uid://bk03bbt0bbdu4" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Waterfalls Rivers and Streams/Waterfall Loop.ogg" id="19_5bvpy"]
[ext_resource type="AudioStream" uid="uid://dn04ssm4qonxs" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Spells/Fireball 2.ogg" id="19_5j00h"]
[ext_resource type="AudioStream" uid="uid://bsb2crsm8gkmc" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Spells/Fireball 3.ogg" id="20_r7v0u"]
[ext_resource type="AudioStream" uid="uid://4mx3c0ercvu1" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Spells/Rock Wall 1.ogg" id="21_r7v0u"]
[ext_resource type="AudioStream" uid="uid://bg4ujtrihj1jl" path="res://assets/audio/sfx/Free Fantasy SFX Pack By TomMusic/OGG Files/SFX/Spells/Rock Wall 2.ogg" id="22_l756u"]
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_rs8q3"]
random_pitch = 1.1
streams_count = 5
stream_0/stream = ExtResource("1_tkpjh")
stream_1/stream = ExtResource("2_npc7y")
stream_2/stream = ExtResource("3_xfjxc")
stream_3/stream = ExtResource("4_ycvo6")
stream_4/stream = ExtResource("5_5bvpy")
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_r7v0u"]
random_pitch = 1.0999973
streams_count = 3
stream_0/stream = ExtResource("14_qnngs")
stream_1/stream = ExtResource("15_3j1dm")
stream_2/stream = ExtResource("16_hln0b")
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_i5yri"]
random_pitch = 1.1
streams_count = 3
stream_0/stream = ExtResource("8_r7v0u")
stream_1/stream = ExtResource("9_l756u")
stream_2/stream = ExtResource("10_7b65l")
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_5cmm3"]
random_pitch = 1.1
streams_count = 3
stream_0/stream = ExtResource("11_447ch")
stream_1/stream = ExtResource("12_1yt5p")
stream_2/stream = ExtResource("13_t5u7s")
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_jjm4g"]
random_pitch = 1.1
streams_count = 3
stream_0/stream = ExtResource("14_qnngs")
stream_1/stream = ExtResource("15_3j1dm")
stream_2/stream = ExtResource("16_hln0b")
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_l756u"]
random_pitch = 1.1
streams_count = 3
stream_0/stream = ExtResource("18_ycvo6")
stream_1/stream = ExtResource("19_5j00h")
stream_2/stream = ExtResource("20_r7v0u")
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_7b65l"]
random_pitch = 1.1
streams_count = 2
stream_0/stream = ExtResource("21_r7v0u")
stream_1/stream = ExtResource("22_l756u")
[resource]
clip_count = 11
clip_0/name = &"footsteps"
clip_0/stream = SubResource("AudioStreamRandomizer_rs8q3")
clip_0/auto_advance = 0
clip_1/name = &"jump"
clip_1/stream = ExtResource("6_w27l5")
clip_1/auto_advance = 0
clip_2/name = &"land"
clip_2/stream = ExtResource("7_5j00h")
clip_2/auto_advance = 0
clip_3/name = &"mantle"
clip_3/stream = ExtResource("17_npc7y")
clip_3/auto_advance = 0
clip_4/name = &"attacks"
clip_4/stream = SubResource("AudioStreamRandomizer_i5yri")
clip_4/auto_advance = 0
clip_5/name = &"hits"
clip_5/stream = SubResource("AudioStreamRandomizer_5cmm3")
clip_5/auto_advance = 0
clip_6/name = &"damage_taken"
clip_6/stream = SubResource("AudioStreamRandomizer_jjm4g")
clip_6/auto_advance = 0
clip_7/name = &"dash"
clip_7/stream = SubResource("AudioStreamRandomizer_l756u")
clip_7/auto_advance = 0
clip_8/name = &"slam"
clip_8/stream = SubResource("AudioStreamRandomizer_7b65l")
clip_8/auto_advance = 0
clip_9/name = &"glide"
clip_9/stream = ExtResource("19_5bvpy")
clip_9/auto_advance = 0
clip_10/name = &"parry"
clip_10/stream = SubResource("AudioStreamRandomizer_r7v0u")
clip_10/auto_advance = 0
_transitions = {
Vector2i(-1, -1): {
"fade_beats": 1.0,
"fade_mode": 4,
"from_time": 0,
"to_time": 1
}
}

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

View File

@@ -0,0 +1,4 @@
[gd_resource type="CapsuleShape3D" format=3 uid="uid://keseacdcooot"]
[resource]
height = 1.7

View File

@@ -0,0 +1,7 @@
[gd_resource type="Resource" script_class="RHealth" format=3 uid="uid://bjyd801wvverk"]
[ext_resource type="Script" uid="uid://baiapod3csndf" path="res://scenes/components/health/RHealth.cs" id="1_tv6ah"]
[resource]
script = ExtResource("1_tv6ah")
metadata/_custom_type_script = "uid://baiapod3csndf"

View File

@@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="RKnockback" format=3 uid="uid://bs8b0oojixm4q"]
[ext_resource type="Script" uid="uid://b44cse62qru7j" path="res://scenes/components/knockback/RKnockback.cs" id="1_dthjm"]
[resource]
script = ExtResource("1_dthjm")
Modifier = 30.0
metadata/_custom_type_script = "uid://b44cse62qru7j"

View File

@@ -0,0 +1,7 @@
[gd_resource type="Resource" script_class="RDamageModifier" format=3 uid="uid://dyru7mxo121w6"]
[ext_resource type="Script" uid="uid://b6y3ugfydvch0" path="res://scenes/components/damage/RDamageModifier.cs" id="1_7i47t"]
[resource]
script = ExtResource("1_7i47t")
metadata/_custom_type_script = "uid://b6y3ugfydvch0"

View File

@@ -0,0 +1,9 @@
namespace Movementtests.player_controller.Scripts;
public partial class AnimationPlayer : Godot.AnimationPlayer
{
public void PlayCameraRotationOnDeath()
{
Play(Constants.PLAYERS_HEAD_ANIMATION_ON_DYING);
}
}

View File

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

View File

@@ -0,0 +1,48 @@
using Godot;
namespace Movementtests.player_controller.Scripts;
public partial class Bobbing: Node3D
{
[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;
private Camera3D _camera;
public void Init(Camera3D cam)
{
_camera = cam;
}
public struct CameraBobbingParams
{
public float Delta;
public bool IsOnFloorCustom;
public Vector3 Velocity;
public float SettingsMultiplier;
}
private float _bobbingAccumulator; // Constantly increases when player moves in X or/and Z axis
public void PerformCameraBobbing(CameraBobbingParams parameters)
{
if (parameters.IsOnFloorCustom)
{
// Head bob
_bobbingAccumulator += parameters.Delta * parameters.Velocity.Length();
Vector3 newPositionForCamera = Vector3.Zero;
// 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 * parameters.SettingsMultiplier;
newPositionForCamera.X = Mathf.Cos(_bobbingAccumulator * BobbingFrequency / 2.0f) * BobbingAmplitude * parameters.SettingsMultiplier;
_camera.Position = newPositionForCamera;
}
}
}

View File

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

View File

@@ -0,0 +1,52 @@
using Godot;
namespace Movementtests.player_controller.Scripts;
public partial class CapsuleCollider : CollisionShape3D
{
[Export(PropertyHint.Range, "0,5.0,0.01,suffix:m,or_greater")]
public float CapsuleDefaultHeight { get; set; } = 2.0f;
[Export(PropertyHint.Range, "0,5.0,0.01,suffix:m,or_greater")]
public float CapsuleCrouchHeight { get; set; } = 1.0f;
public float GetCurrentHeight() { return _shape.Height; }
public float GetDefaultHeight() { return CapsuleDefaultHeight; }
private CapsuleShape3D _shape;
public override void _Ready()
{
_shape = Shape as CapsuleShape3D;
_shape.Height = CapsuleDefaultHeight;
}
public bool IsCapsuleHeightLessThanNormal()
{
return _shape.Height < CapsuleDefaultHeight;
}
public bool IsBetweenCrouchingAndNormalHeight()
{
return _shape.Height > CapsuleCrouchHeight && _shape.Height < CapsuleDefaultHeight;
}
public bool IsDefaultHeight()
{
return Mathf.IsEqualApprox(_shape.Height, CapsuleDefaultHeight);
}
public bool IsCrouchingHeight()
{
return Mathf.IsEqualApprox(_shape.Height, CapsuleCrouchHeight);
}
public void Crouch()
{
_shape.Height = CapsuleCrouchHeight;
}
public void Uncrouch()
{
_shape.Height = CapsuleDefaultHeight;
}
}

View File

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

View File

@@ -0,0 +1,45 @@
using Godot;
namespace Movementtests.player_controller.Scripts;
public partial class FieldOfView: Node3D
{
[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;
private Camera3D _camera;
public void Init(Camera3D cam)
{
_camera = cam;
}
public struct FovParameters
{
public bool IsCrouchingHeight;
public float Delta;
public float SprintSpeed;
public Vector3 Velocity;
public float FOVMultiplier;
}
public void PerformFovAdjustment(FovParameters parameters)
{
float velocityClamped = Mathf.Clamp(
Mathf.Abs(parameters.Velocity.X) + Mathf.Abs(parameters.Velocity.Z),
0.5f,
parameters.SprintSpeed * 2.0f);
float targetFov = BaseFov + FovChangeFactor * velocityClamped * parameters.FOVMultiplier;
if (parameters.IsCrouchingHeight){
targetFov = BaseFov - FovChangeFactor * velocityClamped * parameters.FOVMultiplier;
}
_camera.Fov = Mathf.Lerp(_camera.Fov, targetFov, parameters.Delta * FovChangeSpeed);
}
}

View File

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

View File

@@ -0,0 +1,23 @@
namespace Movementtests.player_controller.Scripts;
public class Constants
{
// Shaders' parameters
public const string DISTORTION_SHADER_SCREEN_DARKNESS = "screen_darkness";
public const string DISTORTION_SHADER_DARKNESS_PROGRESSION = "darkness_progression";
public const string DISTORTION_SHADER_UV_OFFSET = "uv_offset";
public const string DISTORTION_SHADER_SIZE = "size";
public const string VIGNETTE_SHADER_MULTIPLIER = "multiplier";
public const string VIGNETTE_SHADER_SOFTNESS = "softness";
public const string BLUR_SHADER_LIMIT = "limit";
public const string BLUR_SHADER_BLUR = "blur";
// Animation
public const string PLAYERS_HEAD_ANIMATION_ON_DYING = "players_head_on_dying";
// Math
public const float ACCEPTABLE_TOLERANCE = 0.01f;
}

View File

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

View File

@@ -0,0 +1,32 @@
using Godot;
namespace Movementtests.player_controller.Scripts;
public partial class Gravity: Node3D
{
[Export(PropertyHint.Range, "0,10,0.01,or_greater")]
public float Weight { get; set; } = 3.0f;
[Export(PropertyHint.Range, "0,2,0.01,or_greater")]
public float StartVelocity { get; set; } = 1.0f;
[Export(PropertyHint.Range, "0.1,10,0.1,or_greater")]
public float DoubleJumpSpeedFactor { get; set; } = 2f;
[Export(PropertyHint.Range, "0.1,10,0.1,or_greater")]
public float JumpFromDashSpeedFactor { get; set; } = 2f;
[Export(PropertyHint.Range, "0.1,10,0.1,or_greater")]
public float JumpFromWallSpeedFactor { get; set; } = 2f;
[Export(PropertyHint.Range, "0,1,0.01,or_greater")]
public float AdditionalGravityPower { get; set; } = 1f;
private float _gravity;
public void Init(float gravitySetting)
{
_gravity = gravitySetting;
}
public float CalculateJumpForce() => _gravity * (StartVelocity / AdditionalGravityPower);
public float CalculateJumpFromDashForce() => CalculateJumpForce() * JumpFromDashSpeedFactor;
public float CalculateJumpFromWallForce() => CalculateJumpForce() * JumpFromWallSpeedFactor;
public float CalculateDoubleJumpForce() => CalculateJumpForce() * DoubleJumpSpeedFactor;
public float CalculateGravityForce() => _gravity * Weight;
}

View File

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

View File

@@ -0,0 +1,470 @@
using System;
using Godot;
namespace Movementtests.player_controller.Scripts;
public partial class HealthSystem : Node3D
{
new enum Rotation
{
NoRotation = 0,
CameraRotationTriggered = 1,
RotatingOnZAxis = 2,
ReturningBack = 3,
}
[ExportGroup("Health Metrics")]
[ExportSubgroup("Amounts")]
[Export(PropertyHint.Range, "0,100,0.1,or_greater")]
public float MaxHealth { get; set; } = 100.0f;
[Export(PropertyHint.Range, "0,100,0.1,or_greater")]
public float CurrentHealth { get; set; } = 100.0f;
[Export(PropertyHint.Range, "0,100,0.1,or_greater")]
public float MinimalDamageUnit { get; set; } = 25.0f;
[Export(PropertyHint.Range, "-100,0,0.1,or_smaller")]
public float ThresholdVelYForDamage { get; set; } = -15.0f;
[ExportSubgroup("Regeneration")]
[Export(PropertyHint.Range, "0,10,0.01,suffix:s,or_greater")]
public float SecondsBeforeRegeneration { get; set; } = 5.5f;
[Export(PropertyHint.Range, "0,10,0.01,or_greater")]
public float RegenerationSpeed { get; set; } = 10.0f;
[ExportGroup("Damage Camera Effects")]
[ExportSubgroup("Camera Shake")]
[Export(PropertyHint.Range, "0,100,0.1,or_greater")]
public float RotationSpeed { get; set; } = 9.0f;
[Export(PropertyHint.Range, "0,180,0.1,degrees")]
public float RotationDegree { get; set; } = 14.0f;
[ExportSubgroup("Visual Distortion")]
// Screen darkness controls how dark the screen will be, where 0.0 - natural
// color of the screen(unaltered) and 1.0 - black screen
[Export(PropertyHint.Range, "0.0,1.0,0.01")]
public float ScreenDarknessMin { get; set; } = 0.0f;
[Export(PropertyHint.Range, "0.0,1.0,0.01")]
public float ScreenDarknessMax { get; set; } = 0.3f;
[Export(PropertyHint.Range, "0.0,1.0,0.01")]
public float DistortionSpeedMin { get; set; } = 0.0f;
[Export(PropertyHint.Range, "0.0,1.0,0.01")]
public float DistortionSpeedMax { get; set; } = 0.6f;
[Export(PropertyHint.Range, "0.0,1.0,0.01")]
public float DistortionSizeMin { get; set; } = 0.0f;
[Export(PropertyHint.Range, "0.0,1.0,0.01")]
public float DistortionSizeMax { get; set; } = 1.0f;
[ExportSubgroup("Vignetting")]
[Export(PropertyHint.Range, "0.0,1.0,0.01")]
public float ActiveZoneMultiplierMin { get; set; } = 0.45f;
[Export(PropertyHint.Range, "0.0,1.0,0.01")]
public float ActiveZoneMultiplierMax { get; set; } = 0.475f;
[Export(PropertyHint.Range, "0.0,1.0,0.01,or_greater")]
public float MultiplierDeltaForAnimation { get; set; } = 0.066f;
[Export(PropertyHint.Range, "0.0,1.0,0.01")]
public float Softness { get; set; } = 1.0f;
[Export(PropertyHint.Range, "0.0,10,0.01")]
public float SpeedMin { get; set; } = 2.95f;
[Export(PropertyHint.Range, "0.0,10,0.01")]
public float SpeedMax { get; set; } = 4.0f;
// Death / GameOver
[ExportGroup("Death")]
[ExportSubgroup("Before Fade Out")]
[Export(PropertyHint.Range, "0,1,0.01,or_less,or_greater")]
public float BlurLimitValueToStartFadeOut { get; set; } = 0.3f;
[Export(PropertyHint.Range, "0,1,0.01,or_greater")]
public float BlurValueToStartFadeOut { get; set; } = 3.376f;
[ExportSubgroup("Speeds")]
[Export(PropertyHint.Range, "0.1,20.0,0.1,or_greater")]
public float CameraDropSpeedOnDeath { get; set; } = 18.0f;
[Export(PropertyHint.Range, "0.01,5.0,0.01,or_greater")]
public float FadeOutSpeed { get; set; } = 0.11f;
[Export(PropertyHint.Range, "0.1,10,0.01,or_greater")]
public float BlurLimitSpeedOnDeath { get; set; } = 0.9f;
[Export(PropertyHint.Range, "0.1,10,0.01,or_greater")]
public float BlurSpeedOnDeath { get; set; } = 1.5f;
[ExportSubgroup("Target values")]
[Export(PropertyHint.Range, "0,5.0,0.01,suffix:m,or_greater")]
public float CameraHeightOnDeath { get; set; } = 0.68f;
[Export(PropertyHint.Range, "0,5.0,0.01,suffix:m,or_greater")]
public float FadeOutTargetValue { get; set; } = 4.0f;
// TODO: add setter: BlurLimitValueToStartFadeOut should always be less than BlurLimitTargetValue
// (control it in editor)
[Export(PropertyHint.Range, "0,10,0.01,or_greater")]
public float BlurLimitTargetValue { get; set; } = 0.5f;
// TODO: add setter: BlurValueToStartFadeOut should always be less than BlurTargetValue
// (control it in editor)
[Export(PropertyHint.Range, "0,10,0.01,or_greater")]
public float BlurTargetValue { get; set; } = 7.0f;
[ExportSubgroup("Other")]
[Export(PropertyHint.Range, "0.0,4.0,0.01,suffix:s,or_greater")]
public float ScreenDarknessToReloadScene { get; set; } = 1.74f;
// Required to hide Vignette effect
private float _currentHealthInPrevFrame;
private float _currentVelocityYInAir;
private CharacterBody3D _characterBody3D;
private Camera3D _camera;
private float _cameraInitialRotationZ;
private float _targetRotationZAxis;
private Rotation _cameraRotation = Rotation.NoRotation;
private float _progressOnCamRotation;
private Vector2 _uvOffset = Vector2.Zero;
private float _offsetResetThreshold = 5.0f;
private ShaderMaterial _distortionMaterial;
private float _timeAccumulator;
private float _currentSpeed;
private const float InitialMultiplierMidVal = 0.6f;
private const float MultiplierMidValToHideVignette = 0.8f;
private float _currentMultiplierMidValue;
private ShaderMaterial _vignetteMaterial;
private bool _deathAnimationPlayed;
private float _screenDarknessOnDeath;
private float _currentBlurLimit;
private float _currentBlur;
private float _currentScreenDarkness;
private bool _dead;
private Node3D _head;
private ShaderMaterial _blurMaterial;
public struct HealthSystemInitParams
{
public CharacterBody3D Parent;
public Camera3D Camera;
public Node3D Head;
}
public void Init(HealthSystemInitParams initParams)
{
_currentHealthInPrevFrame = CurrentHealth;
_currentMultiplierMidValue = InitialMultiplierMidVal;
_currentSpeed = SpeedMin;
_characterBody3D = initParams.Parent;
_camera = initParams.Camera;
_head = initParams.Head;
// Resetting shaders' parameters
_vignetteMaterial.SetShaderParameter(Constants.VIGNETTE_SHADER_MULTIPLIER, 1.0f);
_vignetteMaterial.SetShaderParameter(Constants.VIGNETTE_SHADER_SOFTNESS, 1.0f);
_distortionMaterial.SetShaderParameter(Constants.DISTORTION_SHADER_SCREEN_DARKNESS, 0.0f);
_distortionMaterial.SetShaderParameter(Constants.DISTORTION_SHADER_DARKNESS_PROGRESSION, 0.0f);
_distortionMaterial.SetShaderParameter(
Constants.DISTORTION_SHADER_UV_OFFSET, new Vector2(0.0f, 0.0f));
_distortionMaterial.SetShaderParameter(Constants.DISTORTION_SHADER_SIZE, 0.0);
_blurMaterial.SetShaderParameter(Constants.BLUR_SHADER_LIMIT, 0.0f);
_blurMaterial.SetShaderParameter(Constants.BLUR_SHADER_BLUR, 0.0f);
}
public override void _Process(double delta)
{
float deltaConverted = (float)delta;
HandleDeath(deltaConverted);
HandleVignetteShader(deltaConverted);
HandleDistortionShader(deltaConverted);
HandleCameraRotationOnHit(deltaConverted);
HandleDamageOnFall();
HandleHealthRegeneration(deltaConverted);
}
public void TakeDamage(float amount)
{
if (_dead)
{
return;
}
if (_cameraRotation == Rotation.NoRotation)
{
_cameraRotation = Rotation.CameraRotationTriggered;
}
CurrentHealth -= amount;
CurrentHealth = Mathf.Clamp(CurrentHealth, 0, MaxHealth);
if (CurrentHealth == 0)
{
_dead = true;
return;
}
_lastHitTime = DateTime.UtcNow;
}
public float GetCurrentHealth() { return CurrentHealth; }
#if DEBUG
public override void _UnhandledInput(InputEvent @event)
{
if (@event is InputEventKey eventKey)
if (eventKey.Pressed && eventKey.Keycode == Key.H)
TakeDamage(MinimalDamageUnit);
}
#endif
public bool IsDead() { return _dead; }
private void HandleDeath(float delta)
{
if (!_dead) { return; }
if (!_deathAnimationPlayed)
{
_deathAnimationPlayed = true;
}
Vector3 newPosition = _head.Position;
newPosition.Y = Mathf.Lerp(newPosition.Y, CameraHeightOnDeath, CameraDropSpeedOnDeath * delta);
if (newPosition.Y < CameraHeightOnDeath) { newPosition.Y = CameraHeightOnDeath; }
_head.Position = newPosition;
_currentBlurLimit = Mathf.Lerp(
_currentBlurLimit, BlurLimitTargetValue, BlurLimitSpeedOnDeath * delta);
_blurMaterial.SetShaderParameter(Constants.BLUR_SHADER_LIMIT, _currentBlurLimit);
_currentBlur = Mathf.Lerp(_currentBlur, BlurTargetValue, BlurSpeedOnDeath * delta);
_blurMaterial.SetShaderParameter(Constants.BLUR_SHADER_BLUR, _currentBlur);
if (_currentBlurLimit >= BlurLimitValueToStartFadeOut && _currentBlur >= BlurValueToStartFadeOut)
{
float currentScreenDarknessVariant = (float)_distortionMaterial.GetShaderParameter(
Constants.DISTORTION_SHADER_SCREEN_DARKNESS);
_screenDarknessOnDeath = Mathf.Lerp(
currentScreenDarknessVariant, FadeOutTargetValue, FadeOutSpeed * delta);
_distortionMaterial.SetShaderParameter(
Constants.DISTORTION_SHADER_SCREEN_DARKNESS, _screenDarknessOnDeath);
if (_screenDarknessOnDeath >= ScreenDarknessToReloadScene)
{
GD.Print("reload");
// Reload the current scene
GetTree().ReloadCurrentScene();
}
}
}
private void HandleVignetteShader(float delta)
{
if (Mathf.IsEqualApprox(CurrentHealth, MaxHealth))
{
_currentHealthInPrevFrame = CurrentHealth;
_currentMultiplierMidValue = InitialMultiplierMidVal;
_timeAccumulator = 0;
return;
}
float healthNormalized = CurrentHealth / MaxHealth;
float healthReverted = 1.0f - healthNormalized;
float newAnimationSpeed = Mathf.Lerp(SpeedMin, SpeedMax, healthReverted);
_currentSpeed = Mathf.Lerp(_currentSpeed, newAnimationSpeed, delta);
float completeSinCycle = Mathf.Tau / _currentSpeed;
_timeAccumulator = Mathf.Wrap(_timeAccumulator + delta, 0.0f, completeSinCycle);
float rawAnimationWeight = Mathf.Sin(_timeAccumulator * _currentSpeed);
float animationWeight = Mathf.Abs(rawAnimationWeight);
float difference = _currentHealthInPrevFrame - CurrentHealth;
float newMultiplierMidValue;
if (difference < 0)
{
newMultiplierMidValue = Mathf.Lerp(
MultiplierMidValToHideVignette, ActiveZoneMultiplierMin, healthReverted);
} else
{
newMultiplierMidValue = Mathf.Lerp(
ActiveZoneMultiplierMax, ActiveZoneMultiplierMin, healthReverted);
}
_currentMultiplierMidValue = Mathf.Lerp(
_currentMultiplierMidValue, newMultiplierMidValue, delta);
float multiplier = Mathf.Lerp(
_currentMultiplierMidValue - MultiplierDeltaForAnimation,
_currentMultiplierMidValue + MultiplierDeltaForAnimation,
animationWeight * animationWeight
);
_vignetteMaterial.SetShaderParameter(Constants.VIGNETTE_SHADER_MULTIPLIER, multiplier);
_vignetteMaterial.SetShaderParameter(Constants.VIGNETTE_SHADER_SOFTNESS, Softness);
_currentHealthInPrevFrame = CurrentHealth;
}
private void HandleDistortionShader(float delta)
{
if (Mathf.IsEqualApprox(CurrentHealth, MaxHealth))
{
return;
}
float healthNormalized = CurrentHealth / MaxHealth;
float healthReverted = 1 - healthNormalized;
_distortionMaterial.SetShaderParameter(
Constants.DISTORTION_SHADER_DARKNESS_PROGRESSION, healthReverted);
if (!_dead)
{
float screenDarkness = Mathf.Remap(
healthReverted, 0, 1, ScreenDarknessMin, ScreenDarknessMax);
_distortionMaterial.SetShaderParameter(
Constants.DISTORTION_SHADER_SCREEN_DARKNESS, screenDarkness);
}
float distortionSpeed = Mathf.Remap(
healthReverted, 0.0f, 1.0f, DistortionSpeedMin, DistortionSpeedMax);
float offsetVal = delta * distortionSpeed;
_uvOffset += new Vector2(offsetVal, offsetVal);
_distortionMaterial.SetShaderParameter(
Constants.DISTORTION_SHADER_UV_OFFSET, _uvOffset);
if (_uvOffset.X > _offsetResetThreshold) { _uvOffset.X = 0.0f; _uvOffset.Y = 0.0f; }
float distortionSize = Mathf.Remap(
healthReverted, 0.0f, 1.0f, DistortionSizeMin, DistortionSizeMax);
_distortionMaterial.SetShaderParameter(
Constants.DISTORTION_SHADER_SIZE, distortionSize);
}
private void RotateCameraOnZAxis(float delta, float targetAngleInRadians, Rotation rotationStateToSetOnFinish)
{
_progressOnCamRotation += delta * RotationSpeed;
_progressOnCamRotation = Mathf.Clamp(_progressOnCamRotation, 0f, 1f);
float lerpedAngleZ = Mathf.LerpAngle(
_camera.Rotation.Z,targetAngleInRadians, _progressOnCamRotation);
_camera.Rotation = new Vector3(_camera.Rotation.X, _camera.Rotation.Y, lerpedAngleZ);
float difference = Mathf.Abs(targetAngleInRadians - _camera.Rotation.Z);
if (difference < Constants.ACCEPTABLE_TOLERANCE)
{
_cameraRotation = rotationStateToSetOnFinish;
_progressOnCamRotation = 0;
}
}
private void HandleCameraRotationOnHit(float delta)
{
if (_cameraRotation == Rotation.NoRotation || _dead) return;
if (_cameraRotation == Rotation.CameraRotationTriggered)
{
if (GD.Randi() % 2 == 0)
{
_targetRotationZAxis = Mathf.DegToRad(RotationDegree * -1);
}
else
{
_targetRotationZAxis = Mathf.DegToRad(RotationDegree);
}
_cameraRotation = Rotation.RotatingOnZAxis;
}
if (_cameraRotation == Rotation.RotatingOnZAxis)
{
RotateCameraOnZAxis(delta, _targetRotationZAxis, Rotation.ReturningBack);
}
if (_cameraRotation == Rotation.ReturningBack)
{
RotateCameraOnZAxis(delta, 0, Rotation.NoRotation);
}
}
private void HandleDamageOnFall()
{
if (_dead) { return;}
if (!_characterBody3D.IsOnFloor())
{
_currentVelocityYInAir = _characterBody3D.Velocity.Y;
}
else
{
if (_currentVelocityYInAir < ThresholdVelYForDamage && ThresholdVelYForDamage > 0)
{
float hit = Mathf.Remap(_currentVelocityYInAir,
ThresholdVelYForDamage, ThresholdVelYForDamage - 9.0f,
MinimalDamageUnit, MaxHealth);
GD.Print("Hit damage: ", hit);
TakeDamage(hit);
}
_currentVelocityYInAir = 0.0f;
}
}
private DateTime? _lastHitTime;
private void HandleHealthRegeneration(float delta)
{
if (_lastHitTime == null || _dead) return;
DateTime lastHitTimeConverted = (DateTime)_lastHitTime;
double differenceInSeconds = (DateTime.UtcNow - lastHitTimeConverted).TotalSeconds;
float differenceInSecondsConverted = (float)differenceInSeconds;
if (differenceInSecondsConverted < SecondsBeforeRegeneration)
{
return;
}
if (Mathf.IsEqualApprox(CurrentHealth, MaxHealth))
{
CurrentHealth = MaxHealth;
_lastHitTime = null;
return;
}
CurrentHealth += delta * RegenerationSpeed;
CurrentHealth = Mathf.Clamp(CurrentHealth, 0, MaxHealth);
}
}

View File

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

View File

@@ -0,0 +1,41 @@
using System;
using Godot;
namespace Movementtests.player_controller.Scripts;
public partial class Mouse : Node3D
{
[Export(PropertyHint.Range, "0,0.1,0.001,or_greater")]
public float Sensitivity { get; set; } = 0.004f;
private Node3D _head;
private Camera3D _camera;
public delegate bool IsDead();
private IsDead _isPlayerDead;
public void Init(Node3D head, Camera3D cam, IsDead isDeadFunc)
{
Input.SetMouseMode(Input.MouseModeEnum.Captured);
_head = head;
_camera = cam;
_isPlayerDead = isDeadFunc;
}
public void LookAround(Vector2 lookDir)
{
// Horizontal movement of head
float angleForHorizontalRotation = lookDir.X * Sensitivity;
_head.RotateY(angleForHorizontalRotation);
// Vertical movement of head
Vector3 currentCameraRotation = _camera.Rotation;
currentCameraRotation.X += Convert.ToSingle(lookDir.Y * Sensitivity);
currentCameraRotation.X = Mathf.Clamp(currentCameraRotation.X, Mathf.DegToRad(-90f), Mathf.DegToRad(90f));
_camera.Rotation = currentCameraRotation;
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,353 @@
using Godot;
namespace Movementtests.player_controller.Scripts;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_boots.png")]
public partial class StairsSystem: Node3D
{
[Export(PropertyHint.Range, "0,10,0.01,suffix:m,or_greater")]
public float MaxStepHeight = 0.5f;
private RayCast3D _stairsBelowRayCast3D;
private RayCast3D _stairsAheadRayCast3D;
private Node3D _cameraSmooth;
private bool _snappedToStairsLastFrame;
private Vector3? _savedCameraGlobalPos;
public void Init(RayCast3D stairsBelowRayCast3D, RayCast3D stairsAheadRayCast3D, Node3D cameraSmooth)
{
_stairsBelowRayCast3D = stairsBelowRayCast3D;
_stairsAheadRayCast3D = stairsAheadRayCast3D;
_cameraSmooth = cameraSmooth;
}
public bool WasSnappedToStairsLastFrame() { return _snappedToStairsLastFrame; }
private bool RunBodyTestMotion(
Transform3D from, Vector3 motion, Rid rid, out PhysicsTestMotionResult3D resultOut)
{
PhysicsTestMotionResult3D result = new PhysicsTestMotionResult3D();
resultOut = result;
PhysicsTestMotionParameters3D parameters = new PhysicsTestMotionParameters3D
{
From = from,
Motion = motion,
Margin = 0.00001f
};
return PhysicsServer3D.BodyTestMotion(rid, parameters, result);
}
public struct UpStairsCheckParams
{
public bool IsOnFloorCustom;
public bool IsCapsuleHeightLessThanNormal;
public bool CurrentSpeedGreaterThanWalkSpeed;
public bool IsCrouchingHeight;
public float Delta;
public float FloorMaxAngle;
public Vector3 GlobalPositionFromDriver;
public Vector3 Velocity;
public Transform3D GlobalTransformFromDriver;
public Rid Rid;
}
public delegate void UpdateAfterUpStairsCheck(CharacterBody3D cb3D);
public struct UpStairsCheckResult
{
public bool UpdateRequired;
public UpdateAfterUpStairsCheck Update;
}
public UpStairsCheckResult SnapUpStairsCheck(UpStairsCheckParams parameters)
{
UpStairsCheckResult updateIsNotRequired = new UpStairsCheckResult
{
UpdateRequired = false,
Update = (CharacterBody3D cb3D) => { }
};
if (!parameters.IsOnFloorCustom) { return updateIsNotRequired; }
// Different velocity multipliers are set for different situations because we alter player's speed
// depending on those situations. For example, while crouching, player is moving slower, so we should account
// for this while running body test motion, as the velocity of the player becomes lower. When sprinting,
// player will have higher velocity and we can compensate it by setting lower velocity multiplier.
float motionVelocityMultiplier;
if (parameters.IsCapsuleHeightLessThanNormal)
{
motionVelocityMultiplier = 1.55f; // Going to crouch mode
}
else if (parameters.CurrentSpeedGreaterThanWalkSpeed)
{
motionVelocityMultiplier = 1.1f; // Sprinting
}
else
{
motionVelocityMultiplier = 1.4f; // Walking
}
Vector3 expectedMoveMotion = parameters.Velocity *
new Vector3(motionVelocityMultiplier, 0.0f, motionVelocityMultiplier) *
parameters.Delta;
Vector3 offset = expectedMoveMotion + new Vector3(0, MaxStepHeight * 2.0f, 0);
Transform3D stepPosWithClearance = parameters.GlobalTransformFromDriver.Translated(offset);
Vector3 motion = new Vector3(0, -MaxStepHeight * 2.0f, 0);
bool doesProjectionCollide = RunBodyTestMotion(
stepPosWithClearance, motion, parameters.Rid, out var downCheckResult);
if (doesProjectionCollide)
{
GodotObject collider = downCheckResult.GetCollider();
if (!collider.IsClass("StaticBody3D") && !collider.IsClass("CSGShape3D"))
{
return updateIsNotRequired;
}
// We add 0.5 because when player is crouching, his height is less than normal by the factor of 2:
// so, 2 meters / 2 = 1 meter (Crouching height). In Godot, this is achieved by subtracting 0.5 from the
// top and the bottom of capsule collider shape. As a result, GlobalPosition goes under the ground by 0.5
// because capsule shape collider was cut off by 0.5 from the bottom, and GlobalPosition does not give a
// a damn about physics (it's not the GlobalPosition of capsule shape, it's just the global coordinate of a
// point in space). So, MaxHeight is 0.5 - 0.5(GlobalPosition that went under the ground) = 0. It means that
// MaxStepHeight for the player while he is crouching is 0, so he can't overcome obstacles while crouching.
// In order to address this problem we should add some offset to 0. Basically, the average height of
// stairs is 0.23. But, also, we want to climb automatically to obstacles that are 50cm height. So, we add
// 0.5 offset. And it means, that we balanced the max step height while crouching: when capsule height is
// normal then max step height is 0.5, when player is crouching, then max step height is also 0.5.
float maxStepHeightAdjusted = parameters.IsCrouchingHeight ? MaxStepHeight + 0.5f : MaxStepHeight;
Vector3 stepHeight = stepPosWithClearance.Origin + downCheckResult.GetTravel() - parameters.GlobalPositionFromDriver;
float stepHeightYToTravelEnd = stepHeight.Y;
float realStepHeightY = (downCheckResult.GetCollisionPoint() - parameters.GlobalPositionFromDriver).Y;
if (stepHeightYToTravelEnd <= 0.01 || realStepHeightY > maxStepHeightAdjusted)
{
return updateIsNotRequired;
}
_stairsAheadRayCast3D.GlobalPosition = downCheckResult.GetCollisionPoint() + new Vector3(
0, MaxStepHeight, 0) + expectedMoveMotion.Normalized() * 0.1f;
_stairsAheadRayCast3D.ForceRaycastUpdate();
// It's needed in order to deny too steep angles of climbing. For hills. And hills-like bumps
// For casual stairs it's, of course, will pass
if (!IsSurfaceTooSteep(
_stairsAheadRayCast3D.GetCollisionNormal(), parameters.FloorMaxAngle))
{
return new UpStairsCheckResult
{
UpdateRequired = true,
Update = (CharacterBody3D cb3D) =>
{
SaveCameraGlobalPosForSmoothing();
cb3D.GlobalPosition = stepPosWithClearance.Origin + downCheckResult.GetTravel();
cb3D.ApplyFloorSnap();
_snappedToStairsLastFrame = true;
}
};
}
}
return updateIsNotRequired;
}
public struct DownStairsCheckParams
{
public bool IsOnFloor;
public bool IsCrouchingHeight;
public float LastFrameWasOnFloor;
public float CapsuleDefaultHeight;
public float CurrentCapsuleHeight;
public float FloorMaxAngle;
public float VelocityY;
public Transform3D GlobalTransformFromDriver;
public Rid Rid;
}
public delegate void UpdateAfterDownStairsCheck(CharacterBody3D cb3D);
public struct DownStairsCheckResult
{
public bool UpdateIsRequired;
public UpdateAfterDownStairsCheck Update;
}
public DownStairsCheckResult SnapDownStairsCheck(DownStairsCheckParams parameters)
{
bool didSnap = false;
if (parameters.IsCrouchingHeight)
{
float yCoordAdjustment = (parameters.CapsuleDefaultHeight - parameters.CurrentCapsuleHeight) / 2.0f;
_stairsBelowRayCast3D.Position = new Vector3(0f, yCoordAdjustment, 0.0f);
}
else
{
_stairsBelowRayCast3D.Position = new Vector3(0f, 0.0f, 0.0f);
}
_stairsBelowRayCast3D.ForceRaycastUpdate();
bool floorBelow = _stairsBelowRayCast3D.IsColliding() && !IsSurfaceTooSteep(
_stairsBelowRayCast3D.GetCollisionNormal(), parameters.FloorMaxAngle);
float differenceInPhysicalFrames = Engine.GetPhysicsFrames() - parameters.LastFrameWasOnFloor;
bool wasOnFloorLastFrame = Mathf.IsEqualApprox(differenceInPhysicalFrames, 1.0f);
PhysicsTestMotionResult3D bodyTestResult = new PhysicsTestMotionResult3D();
if (!parameters.IsOnFloor && parameters.VelocityY <= 0 &&
(wasOnFloorLastFrame || _snappedToStairsLastFrame) && floorBelow)
{
Vector3 motion = new Vector3(0, -MaxStepHeight, 0);
bool doesProjectionCollide = RunBodyTestMotion(
parameters.GlobalTransformFromDriver, motion, parameters.Rid, out bodyTestResult);
if (doesProjectionCollide)
{
didSnap = true;
}
}
_snappedToStairsLastFrame = didSnap;
if (_snappedToStairsLastFrame)
{
return new DownStairsCheckResult
{
UpdateIsRequired = true,
Update = (CharacterBody3D cb3D) =>
{
SaveCameraGlobalPosForSmoothing();
float yDelta = bodyTestResult.GetTravel().Y;
Vector3 positionForModification = cb3D.Position;
positionForModification.Y += yDelta;
cb3D.Position = positionForModification;
cb3D.ApplyFloorSnap();
}
};
}
return new DownStairsCheckResult
{
UpdateIsRequired = false,
Update = (CharacterBody3D cb3D) => { }
};
}
private void SaveCameraGlobalPosForSmoothing()
{
if (_savedCameraGlobalPos == null)
{
_savedCameraGlobalPos = _cameraSmooth.GlobalPosition;
}
}
public struct SlideCameraParams
{
public bool IsCapsuleHeightLessThanNormal;
public bool CurrentSpeedGreaterThanWalkSpeed;
public bool BetweenCrouchingAndNormalHeight;
public float Delta;
}
private const float CrouchingLerpingWeight = 15;
private const float WalkingLerpingWeight = 30;
private const float SprintingLerpingWeight = 75;
private const float DefaultLerpingWeight = 100;
private float _lerpingWeight = DefaultLerpingWeight;
private const float MaxCameraDelayDistance = 0.25f;
public void SlideCameraSmoothBackToOrigin(SlideCameraParams parameters)
{
if (_savedCameraGlobalPos == null)
{
return;
}
Vector3 savedCameraGlobalPosConverted = (Vector3)_savedCameraGlobalPos;
Vector3 globalPositionForModification = _cameraSmooth.GlobalPosition;
globalPositionForModification.Y = savedCameraGlobalPosConverted.Y;
_cameraSmooth.GlobalPosition = globalPositionForModification;
Vector3 positionForModification = _cameraSmooth.Position;
positionForModification.Y = Mathf.Clamp(
_cameraSmooth.Position.Y, -MaxCameraDelayDistance, MaxCameraDelayDistance);
_cameraSmooth.Position = positionForModification;
if (parameters.IsCapsuleHeightLessThanNormal)
{
_lerpingWeight = CrouchingLerpingWeight;
}else
{
if (parameters.CurrentSpeedGreaterThanWalkSpeed)
{
_lerpingWeight = SprintingLerpingWeight;
}
else
{
_lerpingWeight = WalkingLerpingWeight;
}
}
// Smooth control, to smoothly go to crouching mode on stairs (if capsule height has default height initially)
if (parameters.BetweenCrouchingAndNormalHeight)
{
_lerpingWeight = 150;
positionForModification.Y = 0.05f;
}
positionForModification.Y = Mathf.Lerp(
_cameraSmooth.Position.Y, 0.0f, _lerpingWeight * parameters.Delta);
_cameraSmooth.Position = positionForModification;
_savedCameraGlobalPos = _cameraSmooth.GlobalPosition;
if (_cameraSmooth.Position.Y == 0)
{
_savedCameraGlobalPos = null;
}
}
private bool IsSurfaceTooSteep(Vector3 normal, float floorMaxAngle)
{
return normal.AngleTo(Vector3.Up) > floorMaxAngle;
}
}

View File

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

View File

@@ -0,0 +1,40 @@
using Godot;
namespace Movementtests.player_controller.Scripts;
public partial class Stamina : Node
{
[Export(PropertyHint.Range, "0,60,0.1,suffix:s,or_greater")]
public float MaxRunTime { get; set; } = 10.0f;
// Regenerate run time multiplier (when run 10s and RunTimeMultiplier = 2.0f to full regenerate you need 5s)
[Export(PropertyHint.Range, "0,10,0.01,or_greater")]
public float RunTimeMultiplier { get; set; } = 2.0f;
private float _currentRunTime;
private float _walkSpeed;
private float _sprintSpeed;
public void SetSpeeds(float walkSpeed, float sprintSpeed)
{
_walkSpeed = walkSpeed;
_sprintSpeed = sprintSpeed;
}
public float AccountStamina(double delta, float wantedSpeed)
{
if (Mathf.Abs(wantedSpeed - _sprintSpeed) > 0.1f)
{
float runtimeLeft = _currentRunTime - (RunTimeMultiplier * (float)delta);
if (_currentRunTime != 0.0f)
_currentRunTime = Mathf.Clamp(runtimeLeft, 0, MaxRunTime);
return wantedSpeed;
}
_currentRunTime = Mathf.Clamp(_currentRunTime + (float) delta, 0, MaxRunTime);
return _currentRunTime >= MaxRunTime ? _walkSpeed : wantedSpeed;
}
}

View File

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

View File

@@ -0,0 +1,59 @@
using Godot;
using System;
using System.Collections.Generic;
using RustyOptions;
namespace Movementtests.systems;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_wall.png")]
public partial class WallHugSystem : Node3D
{
[Signal]
public delegate void WallDetectedEventHandler();
private List<RayCast3D> _raycasts;
public Option<Vector3> WallHugLocation { get; private set; } = Option<Vector3>.None;
public Option<Vector3> WallHugNormal { get; private set; } = Option<Vector3>.None;
public void Init()
{
_raycasts = new List<RayCast3D>();
_raycasts.Add(GetNode<RayCast3D>("front"));
_raycasts.Add(GetNode<RayCast3D>("front2"));
_raycasts.Add(GetNode<RayCast3D>("back"));
_raycasts.Add(GetNode<RayCast3D>("back2"));
_raycasts.Add(GetNode<RayCast3D>("left"));
_raycasts.Add(GetNode<RayCast3D>("left2"));
_raycasts.Add(GetNode<RayCast3D>("right"));
_raycasts.Add(GetNode<RayCast3D>("right2"));
}
public override void _PhysicsProcess(double delta)
{
base._PhysicsProcess(delta);
CheckWallHugging();
if (IsWallHugging())
EmitSignal(SignalName.WallDetected);
}
public void CheckWallHugging()
{
foreach (RayCast3D raycast in _raycasts)
{
if (raycast.IsColliding() && Math.Abs(raycast.GetCollisionNormal().Y) < 0.3f)
{
WallHugLocation = raycast.GetCollisionPoint().Some();
WallHugNormal = raycast.GetCollisionNormal().Some();
return;
}
}
WallHugLocation = Option<Vector3>.None;
WallHugNormal = Option<Vector3>.None;
}
public bool IsWallHugging()
{
return !WallHugLocation.IsNone;
}
}

View File

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

View File

@@ -0,0 +1,24 @@
// Original by ChaffDave : https://godotshaders.com/shader/tilt-shift-shader/
shader_type canvas_item;
uniform float limit: hint_range(0.0,0.5) = 0.2;
uniform float blur: hint_range(0.0,8.0) = 2.0;
uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap;
void fragment(){
if (UV.y<limit){
float blur_amount = blur * (1.0 - (SCREEN_UV.y / limit));
COLOR = textureLod(screen_texture, SCREEN_UV, blur_amount);
} else if (UV.y > 1.0-limit){
float blur_amount = blur * (1.0 - ((1.0 - SCREEN_UV.y) / limit));
COLOR = textureLod(screen_texture, SCREEN_UV, blur_amount);
} else {
COLOR.a = 0.0;
}
}

View File

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

View File

@@ -0,0 +1,45 @@
shader_type canvas_item;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
uniform float screen_darkness = 0.0;
uniform float darkness_progression = 0.0;
uniform sampler2D smoke;
uniform float size: hint_range(0.0, 1.0);
uniform vec2 uv_offset;
vec4 lerp(vec4 a, vec4 b, float t){
vec4 val = vec4(
(b.x * t) + a.x * (1.0 - t),
(b.y * t) + a.y * (1.0 - t),
(b.z * t) + a.z * (1.0 - t),
(b.w * t) + a.w * (1.0 - t));
return clamp(val, 0, 1);
}
// Function to remap a value from one range to another
float remap(float value, float old_min, float old_max, float new_min, float new_max) {
return new_min + (value - old_min) * (new_max - new_min) / (old_max - old_min);
}
void fragment(){
vec2 smoke_uv = UV;
smoke_uv += uv_offset;
vec4 smoke_color = texture(smoke, fract(smoke_uv));
float size_remapped = remap(size, 0.0, 1.0, 0.0, 0.008);
smoke_color = clamp(smoke_color * size_remapped, 0.0, 1.0);
vec4 img_color = texture(SCREEN_TEXTURE, SCREEN_UV + vec2(smoke_color.g - size_remapped/2.0,0.0));
float screen_darkness_inverted = 1.0 - screen_darkness;
float darkness_scalar = (img_color.x + img_color.y + img_color.z) / 3.0 * screen_darkness_inverted;
vec4 darkness_color = vec4(darkness_scalar, darkness_scalar, darkness_scalar, 1.0);
COLOR = lerp(img_color, darkness_color, darkness_progression);
}

View File

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

View File

@@ -0,0 +1,10 @@
shader_type canvas_item;
uniform vec4 color : source_color;
uniform float multiplier = 0.2;
uniform float softness = 3.0;
void fragment() {
float distance_to_center = distance(UV, vec2(0.5));
COLOR = vec4(color.rgb, smoothstep(multiplier, softness, distance_to_center));
}

View File

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