Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 58bb1d9ca5 | |||
| cf7591b413 | |||
| 92cc4f0264 | |||
| 18c8b741dd | |||
| b84b7e4dd5 | |||
| 4d419b9010 | |||
| 8b2bf3e32e | |||
| db49703326 | |||
| fb78add739 | |||
| 04121f18a4 | |||
| fa029b9e53 |
@@ -1,5 +1,8 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAction_00601_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7c0f83388bfc4d2c9d09befcec9dd79bc90908_003Fb8_003F4d300c4d_003FAction_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAction_00602_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7c0f83388bfc4d2c9d09befcec9dd79bc90908_003F87_003Fded27e2d_003FAction_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEnemy_005FScriptMethods_002Egenerated_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F8e71dc81611862c01a2cb998a1f327de14747655_003FEnemy_005FScriptMethods_002Egenerated_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANode_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F716d154fef5cbe863cd637bd32beda6e3cec5f12e8fed2dc5b2d8149a0d558ab_003FNode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANode_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fdf73a4db74df89d59655c5fb6326406f47fbfa9af1fa81518fe0a07c49d34133_003FNode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASceneTree_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F8d6960554e939a669841b1ece03d27df4ab42f92bb80be3767eaec8cdaccf84b_003FSceneTree_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=floorplane/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
BIN
assets/ui/white-square-100px.png
(Stored with Git LFS)
Normal file
BIN
assets/ui/white-square-100px.png
(Stored with Git LFS)
Normal file
Binary file not shown.
42
assets/ui/white-square-100px.png.import
Normal file
42
assets/ui/white-square-100px.png.import
Normal file
@@ -0,0 +1,42 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://vpcxswwn1mt6"
|
||||
path.s3tc="res://.godot/imported/white-square-100px.png-45d5a1e60348740b59c87085347e502a.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/white-square-100px.png-45d5a1e60348740b59c87085347e502a.etc2.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/ui/white-square-100px.png"
|
||||
dest_files=["res://.godot/imported/white-square-100px.png-45d5a1e60348740b59c87085347e502a.s3tc.ctex", "res://.godot/imported/white-square-100px.png-45d5a1e60348740b59c87085347e502a.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
|
||||
@@ -20,4 +20,12 @@ public partial class CDamageable : Node, IDamageable
|
||||
DamageTaken?.Invoke(this, finalDamageRecord);
|
||||
return finalDamageRecord;
|
||||
}
|
||||
|
||||
public DamageRecord ComputeDamage(DamageRecord damageRecord)
|
||||
{
|
||||
var finalDamage = 0f;
|
||||
foreach (var damageable in DamageModifiers.ToIDamageables())
|
||||
finalDamage += damageable.ComputeDamage(damageRecord).Damage.DamageDealt;
|
||||
return damageRecord with { Damage = new RDamage(finalDamage, damageRecord.Damage.DamageType) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,12 @@ using Movementtests.systems.damage;
|
||||
public partial class RDamage : Resource
|
||||
{
|
||||
[Export(PropertyHint.Range, "0,10,0.1,or_greater")]
|
||||
public float DamageDealt = 1.0f;
|
||||
public float DamageDealt { get; set;}
|
||||
|
||||
[Export]
|
||||
public EDamageTypes DamageType = EDamageTypes.Normal;
|
||||
public EDamageTypes DamageType { get; set;}
|
||||
|
||||
public RDamage()
|
||||
{
|
||||
DamageDealt = 1.0f;
|
||||
DamageType = EDamageTypes.Normal;
|
||||
}
|
||||
public RDamage() : this(1.0f, EDamageTypes.Normal) {}
|
||||
public RDamage(float damageDealt, EDamageTypes damageType)
|
||||
{
|
||||
DamageDealt = damageDealt;
|
||||
|
||||
@@ -9,15 +9,11 @@ public partial class RDamageModifier : Resource, IDamageable
|
||||
public event Action<IDamageable, DamageRecord> DamageTaken;
|
||||
|
||||
[Export]
|
||||
public EDamageTypes DamageType = EDamageTypes.Normal;
|
||||
public EDamageTypes DamageType { get; set;}
|
||||
[Export]
|
||||
public float Modifier = 1.0f;
|
||||
public float Modifier { get; set;}
|
||||
|
||||
public RDamageModifier()
|
||||
{
|
||||
Modifier = 1.0f;
|
||||
DamageType = EDamageTypes.Normal;
|
||||
}
|
||||
public RDamageModifier() : this(EDamageTypes.Normal, 1.0f) {}
|
||||
public RDamageModifier(EDamageTypes damageType, float modifier)
|
||||
{
|
||||
Modifier = modifier;
|
||||
@@ -34,4 +30,13 @@ public partial class RDamageModifier : Resource, IDamageable
|
||||
DamageTaken?.Invoke(this, finalDamageRecord);
|
||||
return finalDamageRecord;
|
||||
}
|
||||
|
||||
public DamageRecord ComputeDamage(DamageRecord damageRecord)
|
||||
{
|
||||
if (damageRecord.Damage.DamageType != DamageType)
|
||||
return damageRecord with { Damage = new RDamage(0, damageRecord.Damage.DamageType) };
|
||||
|
||||
var finalDamage = damageRecord.Damage.DamageDealt * Modifier;
|
||||
return damageRecord with { Damage = new RDamage(finalDamage, damageRecord.Damage.DamageType) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using Movementtests.interfaces;
|
||||
[GlobalClass]
|
||||
public partial class CHealth : Node, IHealthable
|
||||
{
|
||||
public event Action<IHealthable, float> HealthChanged;
|
||||
public event Action<IHealthable, HealthChangedRecord> HealthChanged;
|
||||
public event Action<IHealthable> HealthDepleted;
|
||||
|
||||
[Export]
|
||||
@@ -18,15 +18,18 @@ public partial class CHealth : Node, IHealthable
|
||||
CurrentHealth = RHealth.StartingHealth;
|
||||
}
|
||||
|
||||
public void ReduceHealth(IDamageable source, DamageRecord damageRecord)
|
||||
public HealthChangedRecord ReduceHealth(IDamageable source, DamageRecord damageRecord)
|
||||
{
|
||||
var previousHealth = CurrentHealth;
|
||||
CurrentHealth -= damageRecord.Damage.DamageDealt;
|
||||
HealthChanged?.Invoke(this, CurrentHealth);
|
||||
var record = new HealthChangedRecord(CurrentHealth, previousHealth, RHealth.StartingHealth);
|
||||
HealthChanged?.Invoke(this, record);
|
||||
|
||||
if (CurrentHealth <= 0)
|
||||
{
|
||||
CurrentHealth = 0;
|
||||
HealthDepleted?.Invoke(this);
|
||||
}
|
||||
return record;
|
||||
}
|
||||
}
|
||||
|
||||
26
components/health/CHealthbar.cs
Normal file
26
components/health/CHealthbar.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using Movementtests.interfaces;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class CHealthbar : Node3D
|
||||
{
|
||||
private Sprite3D _currentHealth;
|
||||
private float _initialXScale;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Visible = false;
|
||||
_currentHealth = GetNode<Sprite3D>("Health");
|
||||
_initialXScale = _currentHealth.Scale.X;
|
||||
}
|
||||
|
||||
public void OnHealthChanged(HealthChangedRecord healthChanged)
|
||||
{
|
||||
if (healthChanged.MaxHealth == 0) return;
|
||||
|
||||
Visible = true;
|
||||
var healthPercentage = healthChanged.CurrentHealth / healthChanged.MaxHealth;
|
||||
_currentHealth.Scale = new Vector3(_initialXScale * healthPercentage, _currentHealth.Scale.Y, _currentHealth.Scale.Z);
|
||||
}
|
||||
}
|
||||
1
components/health/CHealthbar.cs.uid
Normal file
1
components/health/CHealthbar.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dve6vg6yvg4y8
|
||||
27
components/health/CHealthbar.tscn
Normal file
27
components/health/CHealthbar.tscn
Normal file
@@ -0,0 +1,27 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://bwx2um43k0ou4"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://vpcxswwn1mt6" path="res://assets/ui/white-square-100px.png" id="1_jlvej"]
|
||||
[ext_resource type="Script" uid="uid://dve6vg6yvg4y8" path="res://components/health/CHealthbar.cs" id="1_w5itk"]
|
||||
|
||||
[node name="CHealthBar" type="Node3D"]
|
||||
script = ExtResource("1_w5itk")
|
||||
|
||||
[node name="Bar" type="Sprite3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 0.1, 0, 0, 0, 1, 0, 0, 0)
|
||||
cast_shadow = 0
|
||||
billboard = 1
|
||||
transparent = false
|
||||
double_sided = false
|
||||
no_depth_test = true
|
||||
texture = ExtResource("1_jlvej")
|
||||
|
||||
[node name="Health" type="Sprite3D" parent="."]
|
||||
transform = Transform3D(0.99, 0, 0, 0, 0.09, 0, 0, 0, 1, 0, 0, 0)
|
||||
cast_shadow = 0
|
||||
modulate = Color(0.7191989, 0.19340843, 1.92523e-07, 1)
|
||||
billboard = 1
|
||||
transparent = false
|
||||
double_sided = false
|
||||
no_depth_test = true
|
||||
render_priority = 10
|
||||
texture = ExtResource("1_jlvej")
|
||||
@@ -6,13 +6,9 @@ using Movementtests.interfaces;
|
||||
public partial class RHealth : Resource
|
||||
{
|
||||
[Export]
|
||||
public float StartingHealth = 100.0f;
|
||||
|
||||
public RHealth()
|
||||
{
|
||||
StartingHealth = 100.0f;
|
||||
}
|
||||
public float StartingHealth { get; set;}
|
||||
|
||||
public RHealth() : this(100.0f) {}
|
||||
public RHealth(float startingHealth)
|
||||
{
|
||||
StartingHealth = startingHealth;
|
||||
|
||||
@@ -20,6 +20,7 @@ public partial class CKnockback : Node3D, IKnockbackable
|
||||
|
||||
var knockbackDirection = GlobalPosition - _damageRecord.Source.GlobalPosition;
|
||||
_damageRecord = null;
|
||||
return knockbackDirection.Normalized() * RKnockback.Modifier;
|
||||
var finalKnockback = knockbackDirection.Normalized() * RKnockback.Modifier;
|
||||
return finalKnockback;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,9 @@ using Movementtests.interfaces;
|
||||
public partial class RKnockback : Resource
|
||||
{
|
||||
[Export]
|
||||
public float Modifier = 1.0f;
|
||||
public float Modifier { get; set;}
|
||||
|
||||
public RKnockback()
|
||||
{
|
||||
Modifier = 1.0f;
|
||||
}
|
||||
public RKnockback() : this(1.0f) {}
|
||||
public RKnockback(float modifier)
|
||||
{
|
||||
Modifier = modifier;
|
||||
|
||||
@@ -14,13 +14,7 @@ public partial class RMovement : Resource
|
||||
[Export(PropertyHint.Range, "0,20,1,or_greater")]
|
||||
public float TargetHeight { get; set;}
|
||||
|
||||
public RMovement()
|
||||
{
|
||||
Speed = 3.0f;
|
||||
Acceleration = 1.0f;
|
||||
GravityModifier = 1.0f;
|
||||
TargetHeight = 10.0f;
|
||||
}
|
||||
public RMovement() : this(1.0f, 0.0f, 0.0f, 0.0f) {}
|
||||
public RMovement(float speed, float acceleration, float gravityModifier, float targetHeight)
|
||||
{
|
||||
Speed = speed;
|
||||
|
||||
7
global.json
Normal file
7
global.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "9.0.0",
|
||||
"rollForward": "latestMajor",
|
||||
"allowPrerelease": true
|
||||
}
|
||||
}
|
||||
@@ -8,5 +8,7 @@ public record DamageRecord(Node3D Source, RDamage Damage);
|
||||
public interface IDamageable
|
||||
{
|
||||
event Action<IDamageable, DamageRecord> DamageTaken;
|
||||
|
||||
DamageRecord TakeDamage(DamageRecord damageRecord);
|
||||
DamageRecord ComputeDamage(DamageRecord damageRecord);
|
||||
}
|
||||
@@ -3,14 +3,16 @@ using Godot;
|
||||
|
||||
namespace Movementtests.interfaces;
|
||||
|
||||
public record HealthChangedRecord(float CurrentHealth, float PreviousHealth, float MaxHealth);
|
||||
|
||||
public interface IHealthable
|
||||
{
|
||||
event Action<IHealthable, float> HealthChanged;
|
||||
event Action<IHealthable, HealthChangedRecord> HealthChanged;
|
||||
event Action<IHealthable> HealthDepleted;
|
||||
|
||||
[Export] RHealth RHealth { get; set; }
|
||||
|
||||
float CurrentHealth { get; set; }
|
||||
|
||||
void ReduceHealth(IDamageable source, DamageRecord damageRecord);
|
||||
HealthChangedRecord ReduceHealth(IDamageable source, DamageRecord damageRecord);
|
||||
}
|
||||
12
interfaces/IStunnable.cs
Normal file
12
interfaces/IStunnable.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Godot;
|
||||
|
||||
namespace Movementtests.interfaces;
|
||||
|
||||
public interface IStunnable
|
||||
{
|
||||
bool IsStunned { get; set; }
|
||||
[Export] float StunDuration { get; set; }
|
||||
|
||||
void Stun();
|
||||
void Unstun();
|
||||
}
|
||||
1
interfaces/IStunnable.cs.uid
Normal file
1
interfaces/IStunnable.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cr8ify1hgetw6
|
||||
8
interfaces/ITargetable.cs
Normal file
8
interfaces/ITargetable.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Godot;
|
||||
|
||||
namespace Movementtests.interfaces;
|
||||
|
||||
public interface ITargetable
|
||||
{
|
||||
Vector3 GetTargetGlobalPosition();
|
||||
}
|
||||
1
interfaces/ITargetable.cs.uid
Normal file
1
interfaces/ITargetable.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c7t7d18oi72pj
|
||||
@@ -1,11 +1,11 @@
|
||||
[gd_scene load_steps=20 format=3 uid="uid://q7uc1h2jpbd2"]
|
||||
[gd_scene load_steps=21 format=3 uid="uid://q7uc1h2jpbd2"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://bei4nhkf8lwdo" path="res://player_controller/PlayerController.tscn" id="1_62kkh"]
|
||||
[ext_resource type="Material" uid="uid://31aulub2nqov" path="res://assets/greybox/m_greybox.tres" id="2_3uydm"]
|
||||
[ext_resource type="Script" uid="uid://jitubgv6judn" path="res://components/damage/RDamage.cs" id="2_sysok"]
|
||||
[ext_resource type="Script" uid="uid://jitubgv6judn" path="res://components/damage/RDamage.cs" id="2_5fa36"]
|
||||
[ext_resource type="PackedScene" uid="uid://dxt0e2ugmttqq" path="res://scenes/enemies/grounded_enemy/grounded_enemy.tscn" id="3_3uydm"]
|
||||
[ext_resource type="Script" uid="uid://b4cwruitopcee" path="res://components/health/RDeathEffect.cs" id="5_7m3bq"]
|
||||
[ext_resource type="PackedScene" uid="uid://cmlud1hwkd6sv" path="res://scenes/enemies/flying_enemy/flying_enemy.tscn" id="5_8fd2t"]
|
||||
[ext_resource type="Script" uid="uid://dtpxijlnb2c5" path="res://components/movement/RMovement.cs" id="5_ybosk"]
|
||||
[ext_resource type="PackedScene" uid="uid://c305mfrtumcyq" path="res://scenes/spawners/spawner.tscn" id="6_7m3bq"]
|
||||
[ext_resource type="Resource" uid="uid://bqq6uukbdfysr" path="res://scenes/enemies/grounded_enemy/grounded_enemy_movement.tres" id="7_caohq"]
|
||||
[ext_resource type="Script" uid="uid://baiapod3csndf" path="res://components/health/RHealth.cs" id="9_2e4ci"]
|
||||
@@ -13,9 +13,11 @@
|
||||
[ext_resource type="Resource" uid="uid://dgo65k2ceqfvy" path="res://scenes/enemies/flying_enemy/flying_enemy_damage.tres" id="9_gp7s3"]
|
||||
[ext_resource type="Resource" uid="uid://bwqjaom4k7rc3" path="res://scenes/enemies/flying_enemy/flying_enemy_movement.tres" id="10_spw1u"]
|
||||
[ext_resource type="Resource" uid="uid://dg1xbjhyhgnnk" path="res://scenes/enemies/flying_enemy/flying_enemy_health.tres" id="11_2e4ci"]
|
||||
[ext_resource type="PackedScene" uid="uid://qup00a7x2sji" path="res://scenes/FixedDashTarget/fixed_dashthrough_target.tscn" id="15_5fa36"]
|
||||
|
||||
[sub_resource type="Resource" id="Resource_2e4ci"]
|
||||
script = ExtResource("2_sysok")
|
||||
[sub_resource type="Resource" id="Resource_1hrkh"]
|
||||
script = ExtResource("2_5fa36")
|
||||
DamageDealt = 1.0
|
||||
metadata/_custom_type_script = "uid://jitubgv6judn"
|
||||
|
||||
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_0xm2m"]
|
||||
@@ -40,9 +42,10 @@ ssil_radius = 8.4
|
||||
sdfgi_use_occlusion = true
|
||||
glow_enabled = true
|
||||
|
||||
[sub_resource type="Resource" id="Resource_sysok"]
|
||||
script = ExtResource("5_7m3bq")
|
||||
metadata/_custom_type_script = "uid://b4cwruitopcee"
|
||||
[sub_resource type="Resource" id="Resource_5fa36"]
|
||||
script = ExtResource("5_ybosk")
|
||||
GravityModifier = 5.0
|
||||
metadata/_custom_type_script = "uid://dtpxijlnb2c5"
|
||||
|
||||
[sub_resource type="Resource" id="Resource_ybosk"]
|
||||
script = ExtResource("9_2e4ci")
|
||||
@@ -54,7 +57,7 @@ metadata/_custom_type_script = "uid://baiapod3csndf"
|
||||
[node name="Player" parent="." instance=ExtResource("1_62kkh")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 7.5)
|
||||
TutorialDone = true
|
||||
RDamage = SubResource("Resource_2e4ci")
|
||||
RDamage = SubResource("Resource_1hrkh")
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource("Environment_1bvp3")
|
||||
@@ -92,6 +95,12 @@ use_collision = true
|
||||
size = Vector3(6.5, 4, 17)
|
||||
material = ExtResource("2_3uydm")
|
||||
|
||||
[node name="CSGBox3D10" type="CSGBox3D" parent="Greybox"]
|
||||
transform = Transform3D(1, 0, 0, 0, 0.9659258, 0.25881904, 0, -0.25881904, 0.9659258, 13.653999, 0.9705714, -5.336278)
|
||||
use_collision = true
|
||||
size = Vector3(6.5, 4, 24.5)
|
||||
material = ExtResource("2_3uydm")
|
||||
|
||||
[node name="CSGBox3D8" type="CSGBox3D" parent="Greybox"]
|
||||
transform = Transform3D(0.81915206, 0, 0.57357645, 0, 1, 0, -0.57357645, 0, 0.81915206, -7.3460007, 0, -3.9585)
|
||||
use_collision = true
|
||||
@@ -104,6 +113,12 @@ use_collision = true
|
||||
size = Vector3(6.5, 11, 5.5)
|
||||
material = ExtResource("2_3uydm")
|
||||
|
||||
[node name="CSGBox3D9" type="CSGBox3D" parent="Greybox"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 50.154, 0, -20.4585)
|
||||
use_collision = true
|
||||
size = Vector3(6.5, 2, 116)
|
||||
material = ExtResource("2_3uydm")
|
||||
|
||||
[node name="CSGBox3D4" type="CSGBox3D" parent="Greybox"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 18.154, 4.5, -14.2085)
|
||||
use_collision = true
|
||||
@@ -116,26 +131,33 @@ use_collision = true
|
||||
size = Vector3(6.5, 11, 5.5)
|
||||
material = ExtResource("2_3uydm")
|
||||
|
||||
[node name="FixedDashthroughTarget" parent="." instance=ExtResource("15_5fa36")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 9, 3.5, 2.5)
|
||||
|
||||
[node name="Enemy" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("3_3uydm")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -16.83681)
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 13.5, 2.5, -8.336809)
|
||||
Target = NodePath("../Player")
|
||||
DeathEffects = Array[Object]([SubResource("Resource_sysok")])
|
||||
RMovement = SubResource("Resource_5fa36")
|
||||
|
||||
[node name="Enemy2" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("3_3uydm")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, -16.83681)
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 13, 0, -17.33681)
|
||||
Target = NodePath("../Player")
|
||||
RMovement = SubResource("Resource_5fa36")
|
||||
|
||||
[node name="Enemy3" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("3_3uydm")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.5, 0, -16.83681)
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 14, 4, -3.3368092)
|
||||
Target = NodePath("../Player")
|
||||
RMovement = SubResource("Resource_5fa36")
|
||||
|
||||
[node name="FlyingEnemy" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("5_8fd2t")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8, 7, -16)
|
||||
Target = NodePath("../Player")
|
||||
RMovement = SubResource("Resource_5fa36")
|
||||
|
||||
[node name="FlyingEnemy2" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("5_8fd2t")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 7, -16)
|
||||
Target = NodePath("../Player")
|
||||
RMovement = SubResource("Resource_5fa36")
|
||||
|
||||
[node name="GroundedSpawner" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("6_7m3bq")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 2.5, -15)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=45 format=3 uid="uid://dmkw8cmalm5k"]
|
||||
[gd_scene load_steps=50 format=3 uid="uid://dmkw8cmalm5k"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://bei4nhkf8lwdo" path="res://player_controller/PlayerController.tscn" id="1_2vsi6"]
|
||||
[ext_resource type="Script" uid="uid://blenis2y55fmg" path="res://tools/city_helpers.gd" id="1_qwuk2"]
|
||||
@@ -27,6 +27,11 @@
|
||||
[ext_resource type="PackedScene" uid="uid://dxt0e2ugmttqq" path="res://scenes/enemies/grounded_enemy/grounded_enemy.tscn" id="25_nrosh"]
|
||||
[ext_resource type="PackedScene" uid="uid://cmlud1hwkd6sv" path="res://scenes/enemies/flying_enemy/flying_enemy.tscn" id="25_x7fl1"]
|
||||
[ext_resource type="Script" uid="uid://dtpxijlnb2c5" path="res://components/movement/RMovement.cs" id="26_lu3yt"]
|
||||
[ext_resource type="Resource" uid="uid://dg1xbjhyhgnnk" path="res://scenes/enemies/flying_enemy/flying_enemy_health.tres" id="27_lgco8"]
|
||||
[ext_resource type="Resource" uid="uid://dgo65k2ceqfvy" path="res://scenes/enemies/flying_enemy/flying_enemy_damage.tres" id="28_51ivn"]
|
||||
[ext_resource type="Resource" uid="uid://bqq6uukbdfysr" path="res://scenes/enemies/grounded_enemy/grounded_enemy_movement.tres" id="30_3w3wd"]
|
||||
[ext_resource type="Resource" uid="uid://bohbojc68j7y1" path="res://scenes/enemies/grounded_enemy/grounded_enemy_health.tres" id="31_5hbxb"]
|
||||
[ext_resource type="Resource" uid="uid://otfc2snh8umc" path="res://scenes/enemies/grounded_enemy/grounded_enemy_damage.tres" id="32_hmdts"]
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_2k3fr"]
|
||||
font_size = 30
|
||||
@@ -450,11 +455,16 @@ spot_angle_attenuation = 10.556052
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 19, 43, -111.5)
|
||||
EnemyToSpawn = ExtResource("25_x7fl1")
|
||||
MovementInputs = SubResource("Resource_pxspk")
|
||||
HealthInputs = ExtResource("27_lgco8")
|
||||
DamageInputs = ExtResource("28_51ivn")
|
||||
Target = NodePath("../Player")
|
||||
|
||||
[node name="Spawner2" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("24_qwuk2")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 31, 7.5, -88)
|
||||
EnemyToSpawn = ExtResource("25_nrosh")
|
||||
MovementInputs = ExtResource("30_3w3wd")
|
||||
HealthInputs = ExtResource("31_5hbxb")
|
||||
DamageInputs = ExtResource("32_hmdts")
|
||||
Target = NodePath("../Player")
|
||||
|
||||
[connection signal="timeout" from="TutorialController/WaitToShowBlockingTuto" to="TutorialController" method="_show_weapon_tutorial"]
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
[gd_scene load_steps=56 format=3 uid="uid://bei4nhkf8lwdo"]
|
||||
[gd_scene load_steps=66 format=3 uid="uid://bei4nhkf8lwdo"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bbbrf5ckydfna" path="res://player_controller/Scripts/PlayerController.cs" id="1_poq2x"]
|
||||
[ext_resource type="PackedScene" uid="uid://cf3rrgr1imvv4" path="res://scenes/path/path.tscn" id="2_6lejt"]
|
||||
[ext_resource type="Script" uid="uid://jitubgv6judn" path="res://components/damage/RDamage.cs" id="2_x835q"]
|
||||
[ext_resource type="Script" uid="uid://b44cse62qru7j" path="res://components/knockback/RKnockback.cs" id="3_cb2lu"]
|
||||
[ext_resource type="Resource" uid="uid://bl5crtu1gkrtr" path="res://systems/inputs/base_mode/base_mode.tres" id="3_cresl"]
|
||||
[ext_resource type="PackedScene" uid="uid://c4ikbhojckpnc" path="res://components/health/CHealth.tscn" id="3_q7bng"]
|
||||
[ext_resource type="Script" uid="uid://baiapod3csndf" path="res://components/health/RHealth.cs" id="4_abfq8"]
|
||||
[ext_resource type="Resource" uid="uid://bjyd801wvverk" path="res://player_controller/resources/player_health.tres" id="4_m8gvy"]
|
||||
[ext_resource type="Resource" uid="uid://cpdaw41ah5gic" path="res://systems/inputs/base_mode/rotate_y.tres" id="4_rxwoh"]
|
||||
[ext_resource type="Resource" uid="uid://ccrb5xsnphc8" path="res://systems/inputs/base_mode/rotate_floorplane.tres" id="5_4u7i3"]
|
||||
@@ -47,6 +50,22 @@
|
||||
[ext_resource type="Texture2D" uid="uid://bnwj7ltdfximr" path="res://icon.svg" id="30_h23go"]
|
||||
[ext_resource type="Texture2D" uid="uid://chvt6g0xn5c2m" path="res://systems/dash/light-ring.jpg" id="32_lgpc8"]
|
||||
[ext_resource type="Script" uid="uid://b4dwolbvt8our" path="res://addons/godot_state_charts/history_state.gd" id="41_ruloh"]
|
||||
[ext_resource type="Texture2D" uid="uid://buu21kg4kkhiw" path="res://guide_examples/shared/fireball/fireball.svg" id="42_cmijs"]
|
||||
|
||||
[sub_resource type="Resource" id="Resource_cb2lu"]
|
||||
script = ExtResource("2_x835q")
|
||||
DamageDealt = 30.0
|
||||
metadata/_custom_type_script = "uid://jitubgv6judn"
|
||||
|
||||
[sub_resource type="Resource" id="Resource_abfq8"]
|
||||
script = ExtResource("3_cb2lu")
|
||||
Modifier = 10.0
|
||||
metadata/_custom_type_script = "uid://b44cse62qru7j"
|
||||
|
||||
[sub_resource type="Resource" id="Resource_ue7xq"]
|
||||
script = ExtResource("4_abfq8")
|
||||
StartingHealth = 10.0
|
||||
metadata/_custom_type_script = "uid://baiapod3csndf"
|
||||
|
||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_xc2g5"]
|
||||
height = 1.7
|
||||
@@ -67,6 +86,12 @@ top_radius = 0.2
|
||||
bottom_radius = 0.2
|
||||
height = 1.0
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_abfq8"]
|
||||
radius = 2.0
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_cmijs"]
|
||||
radius = 1.0
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_6lejt"]
|
||||
radius = 1.0
|
||||
height = 3.5
|
||||
@@ -74,12 +99,19 @@ height = 3.5
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_nob5r"]
|
||||
radius = 0.4
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_ue7xq"]
|
||||
radius = 1.5
|
||||
|
||||
[sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_2q0ik"]
|
||||
blend_mode = 1
|
||||
|
||||
[node name="Player" type="CharacterBody3D"]
|
||||
collision_mask = 272
|
||||
script = ExtResource("1_poq2x")
|
||||
RDamage = SubResource("Resource_cb2lu")
|
||||
RKnockback = SubResource("Resource_abfq8")
|
||||
RHealth = SubResource("Resource_ue7xq")
|
||||
TargetingDistance = 5.0
|
||||
WalkSpeed = 7.5
|
||||
AccelerationFloor = 4.0
|
||||
DecelerationFloor = 3.0
|
||||
@@ -296,6 +328,21 @@ visible = false
|
||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0, 0, -1)
|
||||
mesh = SubResource("CylinderMesh_nodcl")
|
||||
|
||||
[node name="DashDamage" type="ShapeCast3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
|
||||
enabled = false
|
||||
shape = SubResource("SphereShape3D_abfq8")
|
||||
target_position = Vector3(0, 0, 0)
|
||||
max_results = 512
|
||||
collision_mask = 16
|
||||
|
||||
[node name="CloseEnemyDetector" type="ShapeCast3D" parent="."]
|
||||
unique_name_in_owner = true
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6, 0)
|
||||
shape = SubResource("SphereShape3D_cmijs")
|
||||
target_position = Vector3(0, 0, -5)
|
||||
collision_mask = 48
|
||||
|
||||
[node name="GroundDetector" type="ShapeCast3D" parent="."]
|
||||
shape = SubResource("CapsuleShape3D_6lejt")
|
||||
collision_mask = 256
|
||||
@@ -311,6 +358,16 @@ collision_mask = 256
|
||||
target_position = Vector3(0, -2, 0)
|
||||
collision_mask = 256
|
||||
|
||||
[node name="SlidingEnemyDetector" type="Area3D" parent="."]
|
||||
collision_layer = 0
|
||||
collision_mask = 16
|
||||
monitoring = false
|
||||
monitorable = false
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="SlidingEnemyDetector"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
|
||||
shape = SubResource("SphereShape3D_ue7xq")
|
||||
|
||||
[node name="InvincibilityTime" type="Timer" parent="."]
|
||||
one_shot = true
|
||||
|
||||
@@ -344,7 +401,6 @@ enabled = false
|
||||
initial_node_to_watch = NodePath("../StateChart")
|
||||
|
||||
[node name="UI" type="Control" parent="."]
|
||||
visible = false
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@@ -434,6 +490,24 @@ unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(100, 10)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="EnemyTarget" type="TextureRect" parent="UI"]
|
||||
unique_name_in_owner = true
|
||||
modulate = Color(0, 0.61278194, 0.56044877, 1)
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = -20.0
|
||||
offset_right = 20.0
|
||||
offset_bottom = 20.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
texture = ExtResource("42_cmijs")
|
||||
expand_mode = 1
|
||||
|
||||
[node name="StateChart" type="Node" parent="."]
|
||||
script = ExtResource("25_wv70j")
|
||||
metadata/_custom_type_script = "uid://couw105c3bde4"
|
||||
@@ -509,6 +583,49 @@ to = NodePath("../../AtLeastOneCharge")
|
||||
event = &"power_used"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="Attack" type="Node" parent="StateChart/Root"]
|
||||
script = ExtResource("26_infe6")
|
||||
initial_state = NodePath("Ready")
|
||||
|
||||
[node name="Ready" type="Node" parent="StateChart/Root/Attack"]
|
||||
script = ExtResource("27_34snm")
|
||||
|
||||
[node name="ToStandardAttack" type="Node" parent="StateChart/Root/Attack/Ready"]
|
||||
script = ExtResource("28_n7qhm")
|
||||
to = NodePath("../../StandardAttack")
|
||||
event = &"standard_attack"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="ToDashAttack" type="Node" parent="StateChart/Root/Attack/Ready"]
|
||||
script = ExtResource("28_n7qhm")
|
||||
to = NodePath("../../DashAttack")
|
||||
event = &"dash_attack"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="StandardAttack" type="Node" parent="StateChart/Root/Attack"]
|
||||
script = ExtResource("27_34snm")
|
||||
|
||||
[node name="ToReady" type="Node" parent="StateChart/Root/Attack/StandardAttack"]
|
||||
script = ExtResource("28_n7qhm")
|
||||
to = NodePath("../../Ready")
|
||||
event = &"attack_finished"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="ToDashAttack" type="Node" parent="StateChart/Root/Attack/StandardAttack"]
|
||||
script = ExtResource("28_n7qhm")
|
||||
to = NodePath("../../DashAttack")
|
||||
event = &"dash_attack"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="DashAttack" type="Node" parent="StateChart/Root/Attack"]
|
||||
script = ExtResource("27_34snm")
|
||||
|
||||
[node name="ToReady" type="Node" parent="StateChart/Root/Attack/DashAttack"]
|
||||
script = ExtResource("28_n7qhm")
|
||||
to = NodePath("../../Ready")
|
||||
event = &"attack_finished"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="Movement" type="Node" parent="StateChart/Root"]
|
||||
script = ExtResource("26_infe6")
|
||||
initial_state = NodePath("Grounded")
|
||||
@@ -535,12 +652,6 @@ to = NodePath("../OnWall/Hanging")
|
||||
event = &"dash_to_planted"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="OnPoweredDash" type="Node" parent="StateChart/Root/Movement"]
|
||||
script = ExtResource("28_n7qhm")
|
||||
to = NodePath("../Dashing/PoweredDash")
|
||||
event = &"powered_dash"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="OnAimedDash" type="Node" parent="StateChart/Root/Movement"]
|
||||
script = ExtResource("28_n7qhm")
|
||||
to = NodePath("../Dashing/AimedDash")
|
||||
@@ -681,9 +792,6 @@ delay_in_seconds = "0.0"
|
||||
[node name="Dash" type="Node" parent="StateChart/Root/Movement/Dashing"]
|
||||
script = ExtResource("27_34snm")
|
||||
|
||||
[node name="PoweredDash" type="Node" parent="StateChart/Root/Movement/Dashing"]
|
||||
script = ExtResource("27_34snm")
|
||||
|
||||
[node name="AimedDash" type="Node" parent="StateChart/Root/Movement/Dashing"]
|
||||
script = ExtResource("27_34snm")
|
||||
|
||||
|
||||
@@ -4,16 +4,53 @@ using System;
|
||||
public partial class PlayerUi : Control
|
||||
{
|
||||
private TextureRect[] _dashIcons = new TextureRect[3];
|
||||
private TextureRect _enemyTarget;
|
||||
|
||||
public enum TargetState
|
||||
{
|
||||
NoTarget,
|
||||
TargetTooFar,
|
||||
TargetInRange,
|
||||
TargetDashThrough
|
||||
}
|
||||
|
||||
public record TargetProperties(TargetState State, Vector2 Position);
|
||||
|
||||
[Export]
|
||||
public Color DashThroughColor { get; set; } = new Color("009c8f");
|
||||
[Export]
|
||||
public Color DashBlockedColor { get; set; } = new Color("fc001c");
|
||||
[Export]
|
||||
public Color DashOutOfRangeColor { get; set; } = new Color("ffffff");
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
base._Ready();
|
||||
|
||||
_dashIcons[0] = GetNode<TextureRect>("%Dash1");
|
||||
_dashIcons[1] = GetNode<TextureRect>("%Dash2");
|
||||
_dashIcons[2] = GetNode<TextureRect>("%Dash3");
|
||||
|
||||
_enemyTarget = GetNode<TextureRect>("%EnemyTarget");
|
||||
}
|
||||
|
||||
public void SetEnemyTargetProperties(TargetProperties targetProperties)
|
||||
{
|
||||
var (state, position) = targetProperties;
|
||||
|
||||
var visible = state != TargetState.NoTarget;
|
||||
|
||||
var modulation = state switch
|
||||
{
|
||||
TargetState.TargetTooFar => DashOutOfRangeColor,
|
||||
TargetState.TargetInRange => DashBlockedColor,
|
||||
TargetState.TargetDashThrough => DashThroughColor,
|
||||
_ => DashOutOfRangeColor
|
||||
};
|
||||
_enemyTarget.SetVisible(visible);
|
||||
_enemyTarget.SetPosition(position - _enemyTarget.Size / 2);
|
||||
_enemyTarget.SetModulate(modulation);
|
||||
}
|
||||
|
||||
|
||||
public void SetNumberOfDashesLeft(int numberOfDashes)
|
||||
{
|
||||
int index = 1;
|
||||
|
||||
@@ -7,6 +7,7 @@ using Movementtests.addons.godot_state_charts.csharp;
|
||||
using Movementtests.interfaces;
|
||||
using Movementtests.systems;
|
||||
using Movementtests.player_controller.Scripts;
|
||||
using Movementtests.systems.damage;
|
||||
using RustyOptions;
|
||||
|
||||
public partial class PlayerController : CharacterBody3D,
|
||||
@@ -40,7 +41,7 @@ public partial class PlayerController : CharacterBody3D,
|
||||
///////////////////////////
|
||||
|
||||
public event Action<IDamageable, DamageRecord> DamageTaken;
|
||||
public event Action<IHealthable, float> HealthChanged;
|
||||
public event Action<IHealthable, HealthChangedRecord> HealthChanged;
|
||||
public event Action<IHealthable> HealthDepleted;
|
||||
|
||||
///////////////////////////
|
||||
@@ -65,22 +66,27 @@ public partial class PlayerController : CharacterBody3D,
|
||||
public ShapeCast3D CeilingDetector;
|
||||
public RayCast3D DirectGroundDetector;
|
||||
public Area3D WeaponHitbox;
|
||||
public AudioStreamPlayer3D SFXPlayer;
|
||||
public AudioStreamPlayer3D SfxPlayer;
|
||||
|
||||
public ShapeCast3D DashDamageDetector;
|
||||
public Area3D SlidingEnemyDetector;
|
||||
|
||||
// Inspector stuff
|
||||
[Export] public Marker3D TutorialWeaponTarget;
|
||||
[Export] public bool TutorialDone { get; set; }
|
||||
|
||||
// Combat stuff
|
||||
[ExportCategory("Combat")]
|
||||
[ExportGroup("Damage")]
|
||||
[Export]
|
||||
public RDamage RDamage { get; set; }
|
||||
[Export] public RDamage RDamage { get; set; }
|
||||
[Export] public RKnockback RKnockback { get; set; }
|
||||
[Export] public RHealth RHealth { get; set; }
|
||||
|
||||
[Export]
|
||||
public RKnockback RKnockback { get; set; }
|
||||
[Export(PropertyHint.Range, "0,20,0.1,or_greater")]
|
||||
public float TargetingDistance { get; set; } = 10.0f;
|
||||
|
||||
[Export]
|
||||
public RHealth RHealth { get; set; }
|
||||
[Export(PropertyHint.Range, "0,20,0.1,or_greater")]
|
||||
public float TargetInRangeDistance { get; set; } = 5.0f;
|
||||
|
||||
// Movement stuff
|
||||
[ExportCategory("Movement")]
|
||||
@@ -310,6 +316,7 @@ public partial class PlayerController : CharacterBody3D,
|
||||
private StateChartState _mantling;
|
||||
private StateChartState _simpleDash;
|
||||
private StateChartState _aimedDash;
|
||||
private StateChartState _weaponDash;
|
||||
private StateChartState _sliding;
|
||||
private StateChartState _groundSliding;
|
||||
private StateChartState _airGliding;
|
||||
@@ -321,7 +328,8 @@ public partial class PlayerController : CharacterBody3D,
|
||||
private StateChartState _onWallHanging;
|
||||
private StateChartState _onWallRunning;
|
||||
|
||||
private Transition _onDashEnded;
|
||||
private StateChartState _attackStandard;
|
||||
private StateChartState _attackDash;
|
||||
|
||||
private Transition _onJumpFromWall;
|
||||
private Transition _onJumpFromWallFalling;
|
||||
@@ -338,9 +346,11 @@ public partial class PlayerController : CharacterBody3D,
|
||||
public float CurrentHealth { get; set; }
|
||||
|
||||
private bool _isInvincible;
|
||||
private bool _canAttack = true;
|
||||
private readonly List<IDamageable> _hitEnemies = new List<IDamageable>();
|
||||
|
||||
private ShapeCast3D _closeEnemyDetector;
|
||||
private Camera3D _camera;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
LoadSettings();
|
||||
@@ -351,6 +361,9 @@ public partial class PlayerController : CharacterBody3D,
|
||||
|
||||
// General use stuff
|
||||
PlayerUi = GetNode<PlayerUi>("UI");
|
||||
_closeEnemyDetector = GetNode<ShapeCast3D>("%CloseEnemyDetector");
|
||||
_closeEnemyDetector.TargetPosition = _closeEnemyDetector.TargetPosition.Normalized() * TargetingDistance;
|
||||
|
||||
// DashIndicator = GetNode<TextureRect>("%DashIndicator");
|
||||
PowerCooldownIndicator = GetNode<ColorRect>("%DashCooldownIndicator");
|
||||
PowerCooldownIndicator.Visible = false;
|
||||
@@ -361,12 +374,12 @@ public partial class PlayerController : CharacterBody3D,
|
||||
DashIndicatorMeshCylinder = DashIndicatorMesh.Mesh as CylinderMesh;
|
||||
DashIndicatorMesh.Visible = false;
|
||||
|
||||
SFXPlayer = GetNode<AudioStreamPlayer3D>("SFXPlayer");
|
||||
_audioStream = SFXPlayer.GetStreamPlayback() as AudioStreamPlaybackInteractive;
|
||||
SfxPlayer = GetNode<AudioStreamPlayer3D>("SFXPlayer");
|
||||
_audioStream = SfxPlayer.GetStreamPlayback() as AudioStreamPlaybackInteractive;
|
||||
|
||||
// Camera stuff
|
||||
HeadSystem = GetNode<HeadSystem>("HeadSystem");
|
||||
Camera3D camera = GetNode<Camera3D>("HeadSystem/CameraSmooth/Camera3D");
|
||||
_camera = GetNode<Camera3D>("HeadSystem/CameraSmooth/Camera3D");
|
||||
Node3D cameraSmooth = GetNode<Node3D>("HeadSystem/CameraSmooth");
|
||||
|
||||
// Movement stuff
|
||||
@@ -381,6 +394,8 @@ public partial class PlayerController : CharacterBody3D,
|
||||
GroundDetector = GetNode<ShapeCast3D>("GroundDetector");
|
||||
CeilingDetector = GetNode<ShapeCast3D>("CeilingDetector");
|
||||
DirectGroundDetector = GetNode<RayCast3D>("DirectGroundDetector");
|
||||
DashDamageDetector = GetNode<ShapeCast3D>("DashDamage");
|
||||
SlidingEnemyDetector = GetNode<Area3D>("SlidingEnemyDetector");
|
||||
RayCast3D stairsBelowRayCast3D = GetNode<RayCast3D>("StairsBelowRayCast3D");
|
||||
RayCast3D stairsAheadRayCast3D = GetNode<RayCast3D>("StairsAheadRayCast3D");
|
||||
_headCollisionDetectors = new RayCast3D[NUM_OF_HEAD_COLLISION_DETECTORS];
|
||||
@@ -413,7 +428,7 @@ public partial class PlayerController : CharacterBody3D,
|
||||
}
|
||||
if (RKnockback != null) CKnockback!.RKnockback = RKnockback;
|
||||
|
||||
CDamageable.DamageTaken += ReduceHealth;
|
||||
CDamageable.DamageTaken += (source, record) => ReduceHealth(source, record);
|
||||
CDamageable.DamageTaken += RegisterKnockback;
|
||||
CHealth.HealthDepleted += Kill;
|
||||
|
||||
@@ -423,6 +438,7 @@ public partial class PlayerController : CharacterBody3D,
|
||||
_aiming = StateChartState.Of(GetNode("StateChart/Root/Aim/On"));
|
||||
_simpleDash = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing/Dash"));
|
||||
_aimedDash = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing/AimedDash"));
|
||||
_weaponDash = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing/ToWeaponDash"));
|
||||
_slamming = StateChartState.Of(GetNode("StateChart/Root/Movement/Slamming"));
|
||||
|
||||
_sliding = StateChartState.Of(GetNode("StateChart/Root/Movement/Sliding"));
|
||||
@@ -432,7 +448,6 @@ public partial class PlayerController : CharacterBody3D,
|
||||
_airGlidingDoubleJump = StateChartState.Of(GetNode("StateChart/Root/Movement/Sliding/AirGlideDoubleJumpEnabled"));
|
||||
_onGroundSlideJump = Transition.Of(GetNode("StateChart/Root/Movement/Sliding/GroundSlide/OnJump"));
|
||||
_onAirGlideDoubleJump = Transition.Of(GetNode("StateChart/Root/Movement/Sliding/AirGlideDoubleJumpEnabled/OnJump"));
|
||||
_onDashEnded = Transition.Of(GetNode("StateChart/Root/Movement/Dashing/OnDashEnded"));
|
||||
|
||||
// _actionHanging = StateChartState.Of(GetNode("StateChart/Root/Actions/Hanging"));
|
||||
_powerExpired = StateChartState.Of(GetNode("StateChart/Root/PowerReserve/Expired"));
|
||||
@@ -456,6 +471,10 @@ public partial class PlayerController : CharacterBody3D,
|
||||
_onLeaveWallFromRun = Transition.Of(GetNode("StateChart/Root/Movement/OnWall/Running/OnLeaveWall"));
|
||||
_onAirborneToGrounded = Transition.Of(GetNode("StateChart/Root/Movement/Airborne/OnGrounded"));
|
||||
|
||||
// Attack states
|
||||
_attackStandard = StateChartState.Of(GetNode("StateChart/Root/Attack/StandardAttack"));
|
||||
_attackDash = StateChartState.Of(GetNode("StateChart/Root/Attack/DashAttack"));
|
||||
|
||||
// State timers
|
||||
_powerCooldownTimer = GetNode<Timer>("PowerCooldown");
|
||||
_timeScaleAimInAirTimer = GetNode<Timer>("TimeScaleAimInAir");
|
||||
@@ -479,8 +498,8 @@ public partial class PlayerController : CharacterBody3D,
|
||||
_gravity = (float)ProjectSettings.GetSetting("physics/3d/default_gravity");
|
||||
MantleSystem.Init();
|
||||
StairsSystem.Init(stairsBelowRayCast3D, stairsAheadRayCast3D, cameraSmooth);
|
||||
DashSystem.Init(HeadSystem, camera);
|
||||
WeaponSystem.Init(HeadSystem, camera);
|
||||
DashSystem.Init(HeadSystem, _camera);
|
||||
WeaponSystem.Init();
|
||||
WallHugSystem.Init();
|
||||
|
||||
EmpoweredActionsLeft = MaxNumberOfEmpoweredActions;
|
||||
@@ -529,6 +548,9 @@ public partial class PlayerController : CharacterBody3D,
|
||||
_aimedDash.StateEntered += OnAimedDashStarted;
|
||||
_aimedDash.StateExited += OnAimedDashFinished;
|
||||
|
||||
_weaponDash.StateExited += OnWeaponDashFinished;
|
||||
|
||||
SlidingEnemyDetector.BodyEntered += EnemyHitWhileSliding;
|
||||
_sliding.StateEntered += SlideStarted;
|
||||
_sliding.StateExited += SlideEnded;
|
||||
_slideCanceled.StateEntered += OnSlideCanceled;
|
||||
@@ -557,12 +579,16 @@ public partial class PlayerController : CharacterBody3D,
|
||||
_onWallRunning.StatePhysicsProcessing += HandleWallRunning;
|
||||
|
||||
_onWallHanging.StateExited += RecoverWeapon;
|
||||
_onDashEnded.Taken += RecoverWeapon;
|
||||
// _onDashEnded.Taken += RecoverWeapon;
|
||||
|
||||
_onJumpFromWall.Taken += OnJumpFromWall;
|
||||
_onJumpFromWallFalling.Taken += OnJumpFromWall;
|
||||
_onLeaveWallFromRun.Taken += OnLeaveWallFromRun;
|
||||
_onAirborneToGrounded.Taken += OnAirborneToGrounded;
|
||||
_onAirborneToGrounded.Taken += OnAirborneToGrounded;
|
||||
|
||||
// Attack states
|
||||
_attackStandard.StateEntered += OnStandardAttackStarted;
|
||||
_attackDash.StateEntered += OnDashAttackStarted;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
@@ -952,7 +978,7 @@ public partial class PlayerController : CharacterBody3D,
|
||||
}
|
||||
public void RecoverChildNode(Node3D node)
|
||||
{
|
||||
GetTree().GetRoot().RemoveChild(node);
|
||||
node.GetParent().RemoveChild(node);
|
||||
AddChild(node);
|
||||
node.SetGlobalPosition(GlobalPosition);
|
||||
}
|
||||
@@ -1337,7 +1363,7 @@ public partial class PlayerController : CharacterBody3D,
|
||||
// Slide management //
|
||||
///////////////////////////
|
||||
|
||||
private bool _isSlideInputDown = false;
|
||||
private bool _isSlideInputDown;
|
||||
|
||||
public void OnInputSlideStarted()
|
||||
{
|
||||
@@ -1354,7 +1380,6 @@ public partial class PlayerController : CharacterBody3D,
|
||||
|
||||
public record SlopeRecord(
|
||||
Vector3 Position,
|
||||
Vector3 Normal,
|
||||
Vector3 Direction,
|
||||
float AngleRadians
|
||||
);
|
||||
@@ -1373,7 +1398,7 @@ public partial class PlayerController : CharacterBody3D,
|
||||
var angle = normal.AngleTo(Vector3.Up);
|
||||
var vectorInPlane = normal.Cross(Vector3.Up).Normalized();
|
||||
var direction = normal.Cross(vectorInPlane).Normalized();
|
||||
return new SlopeRecord(position, normal, direction, angle);
|
||||
return new SlopeRecord(position, direction, angle);
|
||||
}
|
||||
|
||||
public void SetupSlideCollision()
|
||||
@@ -1392,8 +1417,11 @@ public partial class PlayerController : CharacterBody3D,
|
||||
public void SlideStarted()
|
||||
{
|
||||
_targetSpeed = Velocity.Length();
|
||||
SetupSlideCollision();
|
||||
_audioStream!.SwitchToClipByName("glide");
|
||||
SetupSlideCollision();
|
||||
|
||||
SlidingEnemyDetector.Monitoring = true;
|
||||
_isInvincible = true;
|
||||
}
|
||||
|
||||
public bool CanStandUpFromSlide()
|
||||
@@ -1418,7 +1446,7 @@ public partial class PlayerController : CharacterBody3D,
|
||||
var finalSpeed = Mathf.Max(currentVelocity * speedLossRate, minimumVelocity);
|
||||
|
||||
// Going down a slope?
|
||||
var (position, _, slopeDirection, slopeAngleRadians) = GetSlope();
|
||||
var (position, slopeDirection, slopeAngleRadians) = GetSlope();
|
||||
|
||||
// Change velocity based on Input
|
||||
var horizontalVelocity = ComputeHVelocity(delta, AccelerationGroundSlide, DecelerationGroundSlide);
|
||||
@@ -1519,11 +1547,22 @@ public partial class PlayerController : CharacterBody3D,
|
||||
}
|
||||
public void SlideEnded()
|
||||
{
|
||||
_audioStream!.SwitchToClipByName("footsteps");
|
||||
SlidingEnemyDetector.Monitoring = false;
|
||||
_isInvincible = false;
|
||||
|
||||
SetupStandingCollision();
|
||||
_audioStream!.SwitchToClipByName("footsteps");
|
||||
_targetSpeed = WalkSpeed;
|
||||
}
|
||||
|
||||
public void EnemyHitWhileSliding(Node enemy)
|
||||
{
|
||||
if(enemy is not IDamageable damageable)
|
||||
return;
|
||||
_hitEnemies.Add(damageable);
|
||||
TriggerDamage();
|
||||
}
|
||||
|
||||
public void JumpFromGroundSlide()
|
||||
{
|
||||
_jumpStrengthMultiplier = GroundSlideJumpMultiplier + Velocity.Length()*GroundSlideJumpSpeedFactor;
|
||||
@@ -1630,15 +1669,14 @@ public partial class PlayerController : CharacterBody3D,
|
||||
if (!CanPerformEmpoweredAction())
|
||||
return;
|
||||
|
||||
DashSystem.StartPreparingDash();
|
||||
DashIndicatorMesh.Visible = true;
|
||||
// DashIndicatorMesh.Visible = true;
|
||||
if (!isOnFloorCustom())
|
||||
ReduceTimeScaleWhileAiming();
|
||||
}
|
||||
public void HandleAiming(float delta)
|
||||
{
|
||||
DashIndicatorMeshCylinder.Height = DashSystem.PlannedLocation.DistanceTo(GlobalPosition);
|
||||
DashIndicatorNode.LookAt(DashSystem.PlannedLocation);
|
||||
// DashIndicatorMeshCylinder.Height = DashSystem.PlannedLocation.DistanceTo(GlobalPosition);
|
||||
// DashIndicatorNode.LookAt(DashSystem.PlannedLocation);
|
||||
|
||||
if (CanPerformEmpoweredAction())
|
||||
DashSystem.PrepareDash();
|
||||
@@ -1647,7 +1685,7 @@ public partial class PlayerController : CharacterBody3D,
|
||||
{
|
||||
DashSystem.StopPreparingDash();
|
||||
|
||||
DashIndicatorMesh.Visible = false;
|
||||
// DashIndicatorMesh.Visible = false;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
@@ -1678,9 +1716,16 @@ public partial class PlayerController : CharacterBody3D,
|
||||
// feet of the capsule
|
||||
var correction = DashSystem.CollisionNormal == Vector3.Down ? _playerHeight : DashSystem.DashCastRadius;
|
||||
var correctedLocation = DashSystem.PlannedLocation + Vector3.Down * correction;
|
||||
|
||||
|
||||
if (DashSystem.CanDashThroughTarget && DashSystem.CollidedObject is ITargetable targetable)
|
||||
correctedLocation = ComputePositionAfterTargetedDash(targetable.GetTargetGlobalPosition(), DashSystem.CollisionPoint);
|
||||
|
||||
// Start invincibility timer for the duration of the dash and a bit more afterwards
|
||||
OnHitInvincibility();
|
||||
|
||||
_preDashVelocity = Velocity;
|
||||
_dashDirection = (correctedLocation - GlobalPosition).Normalized();
|
||||
SetupDashDamageDetector(correctedLocation);
|
||||
|
||||
var dashTween = CreatePositionTween(correctedLocation, AimedDashTime);
|
||||
// dashTween.TweenMethod(Callable.From<float>(AimedDashTweenOngoing), 0.0f, 1.0f, AimedDashTime);
|
||||
@@ -1690,6 +1735,28 @@ public partial class PlayerController : CharacterBody3D,
|
||||
_customMantleCurve = DashSystem.MantleSystem.MantleCurve;
|
||||
_customMantleStartTransform = DashSystem.MantleSystem.GlobalTransform;
|
||||
}
|
||||
|
||||
public void SetupDashDamageDetector(Vector3 endDashLocation)
|
||||
{
|
||||
RemoveChildNode(DashDamageDetector);
|
||||
DashDamageDetector.SetTargetPosition(DashDamageDetector.ToLocal(endDashLocation));
|
||||
DashDamageDetector.Enabled = true;
|
||||
}
|
||||
|
||||
public void ComputeDashDamage()
|
||||
{
|
||||
for (var i = 0; i < DashDamageDetector.GetCollisionCount(); i++)
|
||||
{
|
||||
var collidedObject = DashDamageDetector.GetCollider(i);
|
||||
if (collidedObject is not IDamageable damageable) continue;
|
||||
_hitEnemies.Add(damageable);
|
||||
}
|
||||
TriggerDamage();
|
||||
|
||||
RecoverChildNode(DashDamageDetector);
|
||||
DashDamageDetector.Enabled = false;
|
||||
}
|
||||
|
||||
public void AimedDashTweenEnded()
|
||||
{
|
||||
var dashEvent = isOnFloorCustom() ? "grounded" : "dash_finished";
|
||||
@@ -1697,9 +1764,17 @@ public partial class PlayerController : CharacterBody3D,
|
||||
}
|
||||
public void OnAimedDashFinished()
|
||||
{
|
||||
var postDashVelocity = _preDashVelocity.Length() > PostDashSpeed ? PostDashSpeed : _preDashVelocity.Length();
|
||||
ManageAttackedEnemyPostDash(DashSystem.CollidedObject as Node);
|
||||
DashSystem.CollidedObject = null;
|
||||
ComputeDashDamage();
|
||||
|
||||
if (_customMantle)
|
||||
{
|
||||
_playerState.SendEvent("mantle");
|
||||
return;
|
||||
}
|
||||
var postDashVelocity = _preDashVelocity.Length() > PostDashSpeed ? _preDashVelocity.Length() : PostDashSpeed;
|
||||
Velocity = _dashDirection * postDashVelocity;
|
||||
if (_customMantle) _playerState.SendEvent("mantle");
|
||||
}
|
||||
|
||||
// Weapon dashing
|
||||
@@ -1716,23 +1791,29 @@ public partial class PlayerController : CharacterBody3D,
|
||||
weaponTargetLocation,
|
||||
DashSystem.HasHit,
|
||||
DashSystem.CollisionPoint,
|
||||
DashSystem.CollisionNormal);
|
||||
DashSystem.CollisionNormal,
|
||||
DashSystem.CollidedObject as Node);
|
||||
}
|
||||
public void RecoverWeapon()
|
||||
{
|
||||
if (WeaponSystem.GetParent() == this) return;
|
||||
|
||||
HeadSystem.ShowWeapon();
|
||||
RecoverChildNode(WeaponSystem);
|
||||
WeaponSystem.ResetWeapon();
|
||||
RecoverChildNode(WeaponSystem);
|
||||
}
|
||||
|
||||
public void DashToFlyingWeapon()
|
||||
{
|
||||
_playerState.SendEvent("cancel_aim");
|
||||
_playerState.SendEvent("weapon_dash");
|
||||
|
||||
PerformEmpoweredAction();
|
||||
_audioStream.SwitchToClipByName("dash");
|
||||
// Start invincibility timer for the duration of the dash and a bit more afterwards
|
||||
OnHitInvincibility();
|
||||
|
||||
SetupDashDamageDetector(WeaponSystem.GlobalPosition);
|
||||
|
||||
DashSystem.ShouldMantle = false;
|
||||
_dashDirection = (WeaponSystem.GlobalPosition - GlobalPosition).Normalized();
|
||||
@@ -1743,6 +1824,7 @@ public partial class PlayerController : CharacterBody3D,
|
||||
public void DashToFlyingWeaponTweenEnded()
|
||||
{
|
||||
RecoverWeapon();
|
||||
ComputeDashDamage();
|
||||
|
||||
var vel = _dashDirection * PostDashSpeed;
|
||||
SetVelocity(vel);
|
||||
@@ -1753,8 +1835,11 @@ public partial class PlayerController : CharacterBody3D,
|
||||
{
|
||||
_playerState.SendEvent("cancel_aim");
|
||||
_playerState.SendEvent("weapon_dash");
|
||||
|
||||
PerformEmpoweredAction();
|
||||
_audioStream.SwitchToClipByName("dash");
|
||||
// Start invincibility timer for the duration of the dash and a bit more afterwards
|
||||
OnHitInvincibility();
|
||||
|
||||
DashSystem.ShouldMantle = false;
|
||||
var dashLocation = WeaponSystem.PlantLocation;
|
||||
@@ -1762,12 +1847,16 @@ public partial class PlayerController : CharacterBody3D,
|
||||
dashLocation += WeaponSystem.PlantNormal * _playerRadius;
|
||||
if (WeaponSystem.IsPlantedUnderPlatform())
|
||||
dashLocation += Vector3.Down * _playerHeight;
|
||||
|
||||
if (WeaponSystem.PlantObject is ITargetable targetable)
|
||||
dashLocation = targetable.GetTargetGlobalPosition();
|
||||
|
||||
_wallHugStartNormal = WeaponSystem.PlantNormal;
|
||||
_currentWallContactPoint = WeaponSystem.PlantLocation;
|
||||
_wallHugStartLocation = dashLocation;
|
||||
_wallHugStartProjectedVelocity = Velocity.Slide(_wallHugStartNormal);
|
||||
|
||||
SetupDashDamageDetector(dashLocation);
|
||||
|
||||
var dashTween = CreatePositionTween(dashLocation, AimedDashTime);
|
||||
dashTween.Finished += DashToPlantedWeaponTweenEnded;
|
||||
}
|
||||
@@ -1776,40 +1865,132 @@ public partial class PlayerController : CharacterBody3D,
|
||||
// Store the weapon state before resetting it
|
||||
var isPlantedOnWall = WeaponSystem.IsPlantedInWall();
|
||||
var isPlantedUnderPlatform = WeaponSystem.IsPlantedUnderPlatform();
|
||||
var shouldDashToHanging = isPlantedOnWall || isPlantedUnderPlatform;
|
||||
|
||||
var isPlantedInTarget = WeaponSystem.PlantObject is ITargetable;
|
||||
var shouldDashToHanging = (isPlantedOnWall || isPlantedUnderPlatform) && !isPlantedInTarget;
|
||||
var resultingEvent = shouldDashToHanging ? "dash_to_planted" : "dash_finished";
|
||||
|
||||
if (!shouldDashToHanging) RecoverWeapon(); // Manually recover weapon before enemy is freed in case it owns the weapon object
|
||||
if (WeaponSystem.PlantObject is ITargetable)
|
||||
{
|
||||
HeadSystem.OnMantle(); // Recycle mantle animation
|
||||
SetVerticalVelocity(PostDashSpeed);
|
||||
}
|
||||
|
||||
ManageAttackedEnemyPostDash(WeaponSystem.PlantObject);
|
||||
WeaponSystem.PlantObject = null;
|
||||
ComputeDashDamage();
|
||||
|
||||
_playerState.SendEvent(resultingEvent);
|
||||
}
|
||||
|
||||
public void ManageAttackedEnemyPostDash(Node enemy)
|
||||
{
|
||||
if (enemy is IDamageable damageable)
|
||||
{
|
||||
_hitEnemies.Add(damageable);
|
||||
TriggerDamage();
|
||||
}
|
||||
if (enemy is IStunnable stunnable)
|
||||
stunnable.Stun();
|
||||
}
|
||||
|
||||
public void OnWeaponDashFinished()
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// Processes //////////////
|
||||
///////////////////////////
|
||||
public override void _PhysicsProcess(double delta)
|
||||
{
|
||||
_spaceState = GetWorld3D().DirectSpaceState;
|
||||
|
||||
if (_currentInputBufferFrames > 0) _currentInputBufferFrames -= 1;
|
||||
|
||||
// Manage head and camera movement
|
||||
LookAround(delta);
|
||||
|
||||
// Manage general movement
|
||||
Velocity += ComputeKnockback();
|
||||
MoveSlideAndHandleStairs((float) delta);
|
||||
MantleSystem.ProcessMantle(_grounded.Active);
|
||||
|
||||
if (WeaponSystem.InHandState.Active && !_aiming.Active && TutorialDone)
|
||||
{
|
||||
DashIndicatorMesh.Visible = false;
|
||||
}
|
||||
if (!WeaponSystem.InHandState.Active && TutorialDone)
|
||||
{
|
||||
DashIndicatorMesh.Visible = true;
|
||||
|
||||
DashIndicatorMeshCylinder.Height = WeaponSystem.GlobalPosition.DistanceTo(GlobalPosition) * 2;
|
||||
DashIndicatorNode.LookAt(WeaponSystem.GlobalPosition);
|
||||
}
|
||||
// Manage gameplay systems
|
||||
MantleSystem.ProcessMantle(_grounded.Active);
|
||||
HandleEnemyTargeting();
|
||||
|
||||
// Manage dash target and tutorial specific stuff
|
||||
// if (WeaponSystem.InHandState.Active && !_aiming.Active && TutorialDone)
|
||||
// {
|
||||
// DashIndicatorMesh.Visible = false;
|
||||
// }
|
||||
// if (!WeaponSystem.InHandState.Active && TutorialDone)
|
||||
// {
|
||||
// DashIndicatorMesh.Visible = true;
|
||||
//
|
||||
// DashIndicatorMeshCylinder.Height = WeaponSystem.GlobalPosition.DistanceTo(GlobalPosition) * 2;
|
||||
// DashIndicatorNode.LookAt(WeaponSystem.GlobalPosition);
|
||||
// }
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// Hit Management ///////
|
||||
///////////////////////////
|
||||
|
||||
private bool _isEnemyInDashAttackRange;
|
||||
private Vector3 _targetHitLocation;
|
||||
private Vector3 _targetLocation;
|
||||
private Object _targetObject;
|
||||
public void HandleEnemyTargeting()
|
||||
{
|
||||
_isEnemyInDashAttackRange = false;
|
||||
_closeEnemyDetector.SetRotation(HeadSystem.GetGlobalLookRotation());
|
||||
var enemyTargetState = PlayerUi.TargetState.NoTarget;
|
||||
var positionOnScreen = Vector2.Zero;
|
||||
|
||||
if (DashSystem.CanDashThroughTarget && DashSystem.CollidedObject is ITargetable dashTarget)
|
||||
{
|
||||
enemyTargetState = PlayerUi.TargetState.TargetDashThrough;
|
||||
_targetLocation = dashTarget.GetTargetGlobalPosition();
|
||||
positionOnScreen = _camera.UnprojectPosition(_targetLocation);
|
||||
PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!_closeEnemyDetector.IsColliding())
|
||||
{
|
||||
PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen));
|
||||
return;
|
||||
}
|
||||
|
||||
_targetHitLocation = _closeEnemyDetector.GetCollisionPoint(0);
|
||||
_targetObject = _closeEnemyDetector.GetCollider(0);
|
||||
if (_targetObject is not ITargetable target)
|
||||
{
|
||||
PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen));
|
||||
return;
|
||||
}
|
||||
|
||||
_targetLocation = target.GetTargetGlobalPosition();
|
||||
// var targetDistance = _targetLocation.DistanceTo(GlobalPosition);
|
||||
positionOnScreen = _camera.UnprojectPosition(_targetLocation);
|
||||
|
||||
_isEnemyInDashAttackRange = true; //targetDistance < TargetInRangeDistance; // Removing the "almost dash" UI
|
||||
if (_isEnemyInDashAttackRange)
|
||||
{
|
||||
enemyTargetState = PlayerUi.TargetState.TargetDashThrough;
|
||||
if (_targetObject is IDamageable damageable and IHealthable healthable)
|
||||
{
|
||||
var wouldBeDamage = damageable.ComputeDamage(new DamageRecord(this, RDamage));
|
||||
if (wouldBeDamage.Damage.DamageDealt < healthable.CurrentHealth)
|
||||
enemyTargetState = PlayerUi.TargetState.TargetInRange;
|
||||
}
|
||||
}
|
||||
else enemyTargetState = PlayerUi.TargetState.TargetTooFar;
|
||||
|
||||
PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen));
|
||||
}
|
||||
|
||||
public DamageRecord TakeDamage(DamageRecord damageRecord)
|
||||
{
|
||||
if (_isInvincible)
|
||||
@@ -1826,37 +2007,97 @@ public partial class PlayerController : CharacterBody3D,
|
||||
return finalDamage;
|
||||
}
|
||||
|
||||
public DamageRecord ComputeDamage(DamageRecord damageRecord)
|
||||
{
|
||||
return CDamageable.ComputeDamage(damageRecord);
|
||||
}
|
||||
|
||||
public void OnHitInvincibility()
|
||||
{
|
||||
_isInvincible = true;
|
||||
_invincibilityTimer.Start();
|
||||
}
|
||||
|
||||
public void OnStandardAttackStarted()
|
||||
{
|
||||
_attackCooldown.Start();
|
||||
HeadSystem.OnHit();
|
||||
_audioStream!.SwitchToClipByName("attacks");
|
||||
}
|
||||
|
||||
private PhysicsDirectSpaceState3D _spaceState;
|
||||
public void OnDashAttackStarted()
|
||||
{
|
||||
_audioStream!.SwitchToClipByName("attacks");
|
||||
|
||||
_isInvincible = true;
|
||||
|
||||
var plannedDashLocation = _targetLocation + Vector3.Down*HeadSystem.Position.Y;
|
||||
|
||||
var query = PhysicsRayQueryParameters3D.Create(HeadSystem.GlobalPosition, plannedDashLocation, DashSystem.DashCast3D.CollisionMask);
|
||||
var result = _spaceState.IntersectRay(query);
|
||||
if (result.Count > 0)
|
||||
{
|
||||
plannedDashLocation = (Vector3) result["position"];
|
||||
}
|
||||
|
||||
var travel = plannedDashLocation - GlobalPosition;
|
||||
_preDashVelocity = Velocity;
|
||||
_dashDirection = travel.Normalized();
|
||||
var dashTween = CreatePositionTween(plannedDashLocation, AimedDashTime);
|
||||
dashTween.Finished += OnDashAttackEnded;
|
||||
}
|
||||
|
||||
public void OnDashAttackEnded()
|
||||
{
|
||||
if (_targetObject is IDamageable damageable)
|
||||
{
|
||||
_hitEnemies.Add(damageable);
|
||||
TriggerDamage();
|
||||
}
|
||||
|
||||
if (_targetObject is IStunnable stunnable)
|
||||
{
|
||||
stunnable.Stun();
|
||||
}
|
||||
|
||||
var shouldKnockback = _targetObject is IHealthable { CurrentHealth: > 0 };
|
||||
if (shouldKnockback)
|
||||
{
|
||||
Velocity = -_dashDirection*RKnockback.Modifier;
|
||||
}
|
||||
else
|
||||
{
|
||||
GlobalPosition = ComputePositionAfterTargetedDash(_targetLocation, _targetHitLocation);
|
||||
var postDashVelocity = _preDashVelocity.Length() > PostDashSpeed ? _preDashVelocity.Length() : PostDashSpeed;
|
||||
Velocity = _dashDirection * postDashVelocity;
|
||||
}
|
||||
_isInvincible = false;
|
||||
_playerState.SendEvent("attack_finished");
|
||||
}
|
||||
|
||||
public static Vector3 ComputePositionAfterTargetedDash(Vector3 targetLocation, Vector3 targetHitLocation)
|
||||
{
|
||||
return targetLocation + (targetLocation - targetHitLocation);
|
||||
}
|
||||
|
||||
public void OnInputHitPressed()
|
||||
{
|
||||
if (_aiming.Active && WeaponSystem.InHandState.Active)
|
||||
{
|
||||
ThrowWeapon();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WeaponSystem.InHandState.Active) return;
|
||||
if (!_canAttack) return;
|
||||
|
||||
_canAttack = false;
|
||||
_attackCooldown.Start();
|
||||
PerformHit();
|
||||
var attackToDo = _isEnemyInDashAttackRange ? "dash_attack" : "standard_attack";
|
||||
_playerState.SendEvent(attackToDo);
|
||||
}
|
||||
|
||||
public void ResetAttackCooldown()
|
||||
{
|
||||
_canAttack = true;
|
||||
_playerState.SendEvent("attack_finished");
|
||||
}
|
||||
|
||||
public void PerformHit()
|
||||
{
|
||||
HeadSystem.OnHit();
|
||||
_audioStream!.SwitchToClipByName("attacks");
|
||||
}
|
||||
|
||||
public void OnHitboxActivated()
|
||||
{
|
||||
@@ -1898,10 +2139,12 @@ public partial class PlayerController : CharacterBody3D,
|
||||
{
|
||||
ResetTimeScale();
|
||||
}
|
||||
public void ReduceHealth(IDamageable source, DamageRecord damageRecord)
|
||||
public HealthChangedRecord ReduceHealth(IDamageable source, DamageRecord damageRecord)
|
||||
{
|
||||
CHealth.ReduceHealth(source, damageRecord);
|
||||
HealthChanged?.Invoke(this, CHealth.CurrentHealth);
|
||||
GD.Print("That's NOT fine");
|
||||
var record = CHealth.ReduceHealth(source, damageRecord);
|
||||
HealthChanged?.Invoke(this, record);
|
||||
return record;
|
||||
}
|
||||
public void RegisterKnockback(IDamageable source, DamageRecord damageRecord)
|
||||
{
|
||||
@@ -1910,7 +2153,8 @@ public partial class PlayerController : CharacterBody3D,
|
||||
|
||||
public Vector3 ComputeKnockback()
|
||||
{
|
||||
return CKnockback.ComputeKnockback();
|
||||
var kb = CKnockback.ComputeKnockback();
|
||||
return kb;
|
||||
}
|
||||
|
||||
public void Kill(IHealthable source)
|
||||
|
||||
@@ -15,7 +15,7 @@ warnings/check_invalid_track_paths=false
|
||||
[application]
|
||||
|
||||
config/name="Movement tests"
|
||||
run/main_scene="uid://vm22i5sv3p3s"
|
||||
run/main_scene="uid://q7uc1h2jpbd2"
|
||||
config/features=PackedStringArray("4.5", "C#", "Forward Plus")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
@@ -37,6 +37,10 @@ window/size/viewport_height=1080
|
||||
|
||||
project/assembly_name="Movement tests"
|
||||
|
||||
[editor]
|
||||
|
||||
movie_writer/movie_file="D:/Godot/Projects/movement-tests/communication/movie.avi"
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/godot_state_charts/plugin.cfg", "res://addons/guide/plugin.cfg", "res://addons/maaacks_game_template/plugin.cfg", "res://addons/shaker/plugin.cfg")
|
||||
@@ -155,6 +159,7 @@ locale/translations=PackedStringArray("res://addons/maaacks_game_template/base/t
|
||||
3d_physics/layer_3="3"
|
||||
3d_physics/layer_4="4"
|
||||
3d_physics/layer_5="enemies"
|
||||
3d_physics/layer_6="InteractiveGeo"
|
||||
3d_physics/layer_9="terrain"
|
||||
3d_physics/layer_17="weapon"
|
||||
|
||||
|
||||
31
scenes/FixedDashTarget/FixedDashthroughTarget.cs
Normal file
31
scenes/FixedDashTarget/FixedDashthroughTarget.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using Movementtests.interfaces;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class FixedDashthroughTarget : AnimatableBody3D, ITargetable, IStunnable
|
||||
{
|
||||
public Vector3 GetTargetGlobalPosition()
|
||||
{
|
||||
return GlobalPosition;
|
||||
}
|
||||
|
||||
private uint _defaultCollisionMask;
|
||||
public override void _Ready()
|
||||
{
|
||||
_defaultCollisionMask = CollisionMask;
|
||||
}
|
||||
|
||||
public bool IsStunned { get; set; }
|
||||
public float StunDuration { get; set; } = 0.1f;
|
||||
public void Stun()
|
||||
{
|
||||
_defaultCollisionMask = 0;
|
||||
GetTree().CreateTimer(StunDuration).Timeout += Unstun;
|
||||
}
|
||||
|
||||
public void Unstun()
|
||||
{
|
||||
_defaultCollisionMask = CollisionMask;
|
||||
}
|
||||
}
|
||||
1
scenes/FixedDashTarget/FixedDashthroughTarget.cs.uid
Normal file
1
scenes/FixedDashTarget/FixedDashthroughTarget.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c10qfkvmrm6uq
|
||||
30
scenes/FixedDashTarget/fixed_dashthrough_target.tscn
Normal file
30
scenes/FixedDashTarget/fixed_dashthrough_target.tscn
Normal file
@@ -0,0 +1,30 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://qup00a7x2sji"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c10qfkvmrm6uq" path="res://scenes/FixedDashTarget/FixedDashthroughTarget.cs" id="1_r0j7a"]
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_nkm8n"]
|
||||
radius = 1.0
|
||||
|
||||
[sub_resource type="SphereMesh" id="SphereMesh_r0j7a"]
|
||||
radius = 1.0
|
||||
height = 2.0
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_kgb3i"]
|
||||
albedo_color = Color(5.1018596e-06, 0.6818665, 0.7627612, 1)
|
||||
metallic = 0.8
|
||||
metallic_specular = 0.6
|
||||
roughness = 0.1
|
||||
emission_enabled = true
|
||||
emission = Color(0, 0.68968636, 0.7473501, 1)
|
||||
|
||||
[node name="FixedDashthroughTarget" type="AnimatableBody3D"]
|
||||
collision_layer = 288
|
||||
collision_mask = 0
|
||||
script = ExtResource("1_r0j7a")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
shape = SubResource("SphereShape3D_nkm8n")
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||
mesh = SubResource("SphereMesh_r0j7a")
|
||||
surface_material_override/0 = SubResource("StandardMaterial3D_kgb3i")
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using Godot;
|
||||
using Movementtests.interfaces;
|
||||
using Movementtests.systems;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class Enemy : CharacterBody3D,
|
||||
@@ -10,47 +11,53 @@ public partial class Enemy : CharacterBody3D,
|
||||
IKillable,
|
||||
IMoveable,
|
||||
ISpawnable,
|
||||
IKnockbackable
|
||||
IKnockbackable,
|
||||
ITargetable,
|
||||
IStunnable
|
||||
{
|
||||
// Signals and events
|
||||
public event Action<IDamageable, DamageRecord> DamageTaken;
|
||||
public event Action<IHealthable, float> HealthChanged;
|
||||
public event Action<IHealthable, HealthChangedRecord> HealthChanged;
|
||||
public event Action<IHealthable> HealthDepleted;
|
||||
|
||||
// Public export components
|
||||
[Export]
|
||||
public Node3D Target { get; set; }
|
||||
[Export]
|
||||
public float EnemyHeight { get; set; } = 1f;
|
||||
|
||||
[ExportGroup("Health")]
|
||||
[Export]
|
||||
public Node CHealth { get; set; }
|
||||
[Export]
|
||||
public RHealth RHealth { get; set; }
|
||||
|
||||
[Export]
|
||||
public RDeathEffect[] DeathEffects { get; set; }
|
||||
public IHealthable CHealth { get; set; }
|
||||
|
||||
[ExportGroup("Damage")]
|
||||
[Export]
|
||||
public Node CDamage { get; set; }
|
||||
[Export]
|
||||
public RDamage RDamage { get; set; }
|
||||
[Export]
|
||||
public Node CKnockback { get; set; }
|
||||
public IDamageable CDamageable { get; set; }
|
||||
|
||||
[Export]
|
||||
public RKnockback RKnockback { get; set; }
|
||||
public IKnockbackable CKnockback { get; set; }
|
||||
|
||||
[ExportGroup("Movement")]
|
||||
[Export]
|
||||
public Node CMovement { get; set; }
|
||||
[Export]
|
||||
public RMovement RMovement { get; set; }
|
||||
public IMoveable CMovement { get; set; }
|
||||
|
||||
// Public stuff
|
||||
public float CurrentHealth { get; set; }
|
||||
public float CurrentHealth
|
||||
{
|
||||
get => CHealth.CurrentHealth;
|
||||
set => CHealth.CurrentHealth = value;
|
||||
}
|
||||
|
||||
// Private stuff
|
||||
private Area3D _damageBox;
|
||||
private Node3D _target;
|
||||
private CHealthbar _healthbar;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
@@ -61,30 +68,41 @@ public partial class Enemy : CharacterBody3D,
|
||||
public void Initialize()
|
||||
{
|
||||
_damageBox = GetNode<Area3D>("DamageBox");
|
||||
_target = GetNode<Node3D>("CTarget");
|
||||
|
||||
if (CMovement is IMoveable moveable && RMovement != null) moveable.RMovement = RMovement;
|
||||
if (CHealth is IHealthable healthable && RHealth != null)
|
||||
CDamageable = GetNode<Node>("CDamageable") as IDamageable;
|
||||
CMovement = GetNode<Node>("CMovement") as IMoveable;
|
||||
CHealth = GetNode<Node>("CHealth") as IHealthable;
|
||||
CKnockback = GetNode<Node>("CKnockback") as IKnockbackable;
|
||||
if (CDamageable is null) GD.PrintErr("This node needs a 'CDamage' child of type IDamageable!");
|
||||
if (CMovement is null) GD.PrintErr("This node needs a 'CMovement' child of type IMoveable!");
|
||||
if (CHealth is null) GD.PrintErr("This node needs a 'CHealth' child of type IHealthable!");
|
||||
if (CKnockback is null) GD.PrintErr("This node needs a 'CKnockback' child of type IKnockbackable!");
|
||||
|
||||
_healthbar = GetNode<CHealthbar>("CHealthBar");
|
||||
|
||||
if (RMovement != null) CMovement!.RMovement = RMovement;
|
||||
if (RHealth != null)
|
||||
{
|
||||
healthable.RHealth = RHealth;
|
||||
healthable.CurrentHealth = RHealth.StartingHealth;
|
||||
CHealth!.RHealth = RHealth;
|
||||
CHealth.CurrentHealth = RHealth.StartingHealth;
|
||||
}
|
||||
if (CKnockback is IKnockbackable knockbackable && RKnockback != null) knockbackable.RKnockback = RKnockback;
|
||||
if (RKnockback != null) CKnockback!.RKnockback = RKnockback;
|
||||
}
|
||||
|
||||
public void SetupSignals()
|
||||
{
|
||||
if (CDamage is IDamageable damageable)
|
||||
{
|
||||
damageable.DamageTaken += ReduceHealth;
|
||||
damageable.DamageTaken += RegisterKnockback;
|
||||
}
|
||||
if (CHealth is IHealthable healthable) healthable.HealthDepleted += Kill;
|
||||
// Anonymous function call to erase return values of ReduceHealth
|
||||
CDamageable.DamageTaken += (source, record) => ReduceHealth(source, record);
|
||||
CDamageable.DamageTaken += RegisterKnockback;
|
||||
CHealth.HealthDepleted += Kill;
|
||||
HealthChanged += (source, record) => _healthbar.OnHealthChanged(record);
|
||||
}
|
||||
|
||||
public override void _PhysicsProcess(double delta)
|
||||
{
|
||||
// Only trigger gameplay related effects 4 times per second
|
||||
if(Engine.GetPhysicsFrames() % 15 == 0) ProcessGameplay(delta);
|
||||
// Only trigger gameplay related effects on specific frames
|
||||
if(Engine.GetPhysicsFrames() % 10 == 0) ProcessGameplay(delta);
|
||||
|
||||
var targetPlanar = new Vector3(Target.GlobalPosition.X, GlobalPosition.Y, Target.GlobalPosition.Z);
|
||||
LookAt(targetPlanar);
|
||||
@@ -103,6 +121,8 @@ public partial class Enemy : CharacterBody3D,
|
||||
|
||||
public void ProcessGameplay(double delta)
|
||||
{
|
||||
if (IsStunned) return;
|
||||
|
||||
var bodies = _damageBox.GetOverlappingBodies();
|
||||
foreach (var body in bodies)
|
||||
{
|
||||
@@ -113,45 +133,87 @@ public partial class Enemy : CharacterBody3D,
|
||||
|
||||
public Vector3 ComputeVelocity(MovementInputs inputs)
|
||||
{
|
||||
if (CMovement is not IMoveable movement) return Vector3.Zero;
|
||||
return movement!.ComputeVelocity(inputs);
|
||||
if (CMovement is null) return Vector3.Zero;
|
||||
return CMovement.ComputeVelocity(inputs);
|
||||
}
|
||||
|
||||
public DamageRecord TakeDamage(DamageRecord damageRecord)
|
||||
{
|
||||
if (CDamage is not IDamageable damageable)
|
||||
if (CDamageable is null)
|
||||
return damageRecord with { Damage = new RDamage(0, damageRecord.Damage.DamageType) };
|
||||
|
||||
var finalDamage = damageable.TakeDamage(damageRecord);
|
||||
var finalDamage = CDamageable.TakeDamage(damageRecord);
|
||||
DamageTaken?.Invoke(this, finalDamage);
|
||||
return finalDamage;
|
||||
}
|
||||
|
||||
public void ReduceHealth(IDamageable source, DamageRecord damageRecord)
|
||||
public DamageRecord ComputeDamage(DamageRecord damageRecord)
|
||||
{
|
||||
if (CHealth is not IHealthable healthable) return;
|
||||
healthable.ReduceHealth(source, damageRecord);
|
||||
HealthChanged?.Invoke(this, healthable.CurrentHealth);
|
||||
if (CDamageable is null)
|
||||
return damageRecord with { Damage = new RDamage(0, damageRecord.Damage.DamageType) };
|
||||
|
||||
return CDamageable.ComputeDamage(damageRecord);
|
||||
}
|
||||
|
||||
public HealthChangedRecord ReduceHealth(IDamageable source, DamageRecord damageRecord)
|
||||
{
|
||||
if (CHealth is null) return new HealthChangedRecord(0, 0, 0);
|
||||
var record = CHealth.ReduceHealth(source, damageRecord);
|
||||
HealthChanged?.Invoke(this, record);
|
||||
return record;
|
||||
}
|
||||
|
||||
public void Kill(IHealthable source)
|
||||
{
|
||||
// Remove weapon that might be planted there
|
||||
foreach (var child in GetChildren())
|
||||
{
|
||||
if (child is WeaponSystem system)
|
||||
{
|
||||
CallDeferred(Node.MethodName.RemoveChild, system);
|
||||
GetTree().GetRoot().CallDeferred(Node.MethodName.AddChild, system);
|
||||
system.CallDeferred(Node3D.MethodName.SetGlobalPosition, GlobalPosition + Vector3.Up*EnemyHeight);
|
||||
system.CallDeferred(WeaponSystem.MethodName.RethrowWeapon);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var killable in DeathEffects.ToIKillables())
|
||||
{
|
||||
killable.Kill(source);
|
||||
}
|
||||
QueueFree();
|
||||
CallDeferred(Node.MethodName.QueueFree);
|
||||
}
|
||||
|
||||
public void RegisterKnockback(IDamageable source, DamageRecord damageRecord)
|
||||
{
|
||||
if (CKnockback is not IKnockbackable knockbackable) return;
|
||||
knockbackable.RegisterKnockback(source, damageRecord);
|
||||
if (CKnockback is null) return;
|
||||
CKnockback.RegisterKnockback(source, damageRecord);
|
||||
}
|
||||
|
||||
public Vector3 ComputeKnockback()
|
||||
{
|
||||
if (CKnockback is not IKnockbackable knockbackable) return Vector3.Zero;
|
||||
return knockbackable.ComputeKnockback();
|
||||
if (CKnockback is null) return Vector3.Zero;
|
||||
return CKnockback.ComputeKnockback();
|
||||
}
|
||||
|
||||
public Vector3 GetTargetGlobalPosition()
|
||||
{
|
||||
if (_target is null) return GlobalPosition;
|
||||
return _target.GlobalPosition;
|
||||
}
|
||||
|
||||
// Stun management
|
||||
public bool IsStunned { get; set; } = false;
|
||||
|
||||
[Export(PropertyHint.Range, "0.1, 2, 0.1, or_greater")]
|
||||
public float StunDuration { get; set; } = 1f;
|
||||
public void Stun()
|
||||
{
|
||||
IsStunned = true;
|
||||
GetTree().CreateTimer(StunDuration).Timeout += Unstun;
|
||||
}
|
||||
public void Unstun()
|
||||
{
|
||||
IsStunned = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=20 format=3 uid="uid://cmlud1hwkd6sv"]
|
||||
[gd_scene load_steps=21 format=3 uid="uid://cmlud1hwkd6sv"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bn7sc6id7n166" path="res://scenes/enemies/Enemy.cs" id="1_q8l7o"]
|
||||
[ext_resource type="Script" uid="uid://b6y3ugfydvch0" path="res://components/damage/RDamageModifier.cs" id="2_1bsgx"]
|
||||
@@ -7,6 +7,7 @@
|
||||
[ext_resource type="Resource" uid="uid://bwqjaom4k7rc3" path="res://scenes/enemies/flying_enemy/flying_enemy_movement.tres" id="4_dejyg"]
|
||||
[ext_resource type="Script" uid="uid://bjwrpv3jpsc1e" path="res://components/health/CHealth.cs" id="4_ys4jv"]
|
||||
[ext_resource type="PackedScene" uid="uid://dmw5ibwrb483f" path="res://components/movement/CFlyingMovement.tscn" id="7_vaeds"]
|
||||
[ext_resource type="PackedScene" uid="uid://bwx2um43k0ou4" path="res://components/health/CHealthbar.tscn" id="7_ykkxn"]
|
||||
[ext_resource type="Script" uid="uid://dtpxijlnb2c5" path="res://components/movement/RMovement.cs" id="8_on7rt"]
|
||||
[ext_resource type="Script" uid="uid://b0u23nkpaimyc" path="res://components/damage/CDamageable.cs" id="8_uotso"]
|
||||
[ext_resource type="PackedScene" uid="uid://bctpe34ddamg5" path="res://components/knockback/CKnockback.tscn" id="10_dejyg"]
|
||||
@@ -42,19 +43,16 @@ albedo_color = Color(0.06469653, 0.06469653, 0.06469653, 1)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_4yfjf"]
|
||||
|
||||
[node name="FlyingEnemy" type="CharacterBody3D" node_paths=PackedStringArray("CHealth", "CDamage", "CKnockback", "CMovement")]
|
||||
[node name="FlyingEnemy" type="CharacterBody3D"]
|
||||
collision_layer = 16
|
||||
collision_mask = 273
|
||||
motion_mode = 1
|
||||
script = ExtResource("1_q8l7o")
|
||||
CHealth = NodePath("CHealth")
|
||||
EnemyHeight = 0.5
|
||||
RHealth = ExtResource("2_ma2bq")
|
||||
DeathEffects = Array[Object]([])
|
||||
CDamage = NodePath("CDamageable")
|
||||
RDamage = ExtResource("2_on7rt")
|
||||
CKnockback = NodePath("CKnockback")
|
||||
RKnockback = ExtResource("11_mpa2u")
|
||||
CMovement = NodePath("CFlyingMovement")
|
||||
RMovement = ExtResource("4_dejyg")
|
||||
|
||||
[node name="CHealth" type="Node" parent="."]
|
||||
@@ -62,18 +60,23 @@ script = ExtResource("4_ys4jv")
|
||||
RHealth = ExtResource("2_ma2bq")
|
||||
metadata/_custom_type_script = "uid://bjwrpv3jpsc1e"
|
||||
|
||||
[node name="CHealthBar" parent="." instance=ExtResource("7_ykkxn")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.70000005, 0)
|
||||
|
||||
[node name="CDamageable" type="Node" parent="."]
|
||||
script = ExtResource("8_uotso")
|
||||
DamageModifiers = Array[Object]([SubResource("Resource_jnv07"), SubResource("Resource_53j1c")])
|
||||
metadata/_custom_type_script = "uid://b0u23nkpaimyc"
|
||||
|
||||
[node name="CFlyingMovement" parent="." instance=ExtResource("7_vaeds")]
|
||||
[node name="CMovement" parent="." instance=ExtResource("7_vaeds")]
|
||||
RMovement = SubResource("Resource_on7rt")
|
||||
TerrainCollision = 256
|
||||
|
||||
[node name="CKnockback" parent="." instance=ExtResource("10_dejyg")]
|
||||
RKnockback = ExtResource("11_mpa2u")
|
||||
|
||||
[node name="CTarget" type="Marker3D" parent="."]
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
shape = SubResource("SphereShape3D_b46rq")
|
||||
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_jht15")
|
||||
StartingHealth = 50.0
|
||||
StartingHealth = 10.0
|
||||
metadata/_custom_type_script = "uid://baiapod3csndf"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=19 format=3 uid="uid://dxt0e2ugmttqq"]
|
||||
[gd_scene load_steps=20 format=3 uid="uid://dxt0e2ugmttqq"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bn7sc6id7n166" path="res://scenes/enemies/Enemy.cs" id="1_r6506"]
|
||||
[ext_resource type="Resource" uid="uid://otfc2snh8umc" path="res://scenes/enemies/grounded_enemy/grounded_enemy_damage.tres" id="2_bn56u"]
|
||||
@@ -7,6 +7,7 @@
|
||||
[ext_resource type="Resource" uid="uid://bohbojc68j7y1" path="res://scenes/enemies/grounded_enemy/grounded_enemy_health.tres" id="2_w4lm8"]
|
||||
[ext_resource type="Resource" uid="uid://bqq6uukbdfysr" path="res://scenes/enemies/grounded_enemy/grounded_enemy_movement.tres" id="4_na24f"]
|
||||
[ext_resource type="Script" uid="uid://b0u23nkpaimyc" path="res://components/damage/CDamageable.cs" id="7_1tw73"]
|
||||
[ext_resource type="PackedScene" uid="uid://bwx2um43k0ou4" path="res://components/health/CHealthbar.tscn" id="7_18xwy"]
|
||||
[ext_resource type="PackedScene" uid="uid://dbr7ioio158ew" path="res://components/movement/CGroundedMovement.tscn" id="7_qyswd"]
|
||||
[ext_resource type="Script" uid="uid://dtpxijlnb2c5" path="res://components/movement/RMovement.cs" id="8_6d4gl"]
|
||||
[ext_resource type="PackedScene" uid="uid://bctpe34ddamg5" path="res://components/knockback/CKnockback.tscn" id="10_jqqi6"]
|
||||
@@ -14,7 +15,7 @@
|
||||
|
||||
[sub_resource type="Resource" id="Resource_qj0ob"]
|
||||
script = ExtResource("2_r3cnf")
|
||||
Modifier = 3.0
|
||||
Modifier = 1.0
|
||||
metadata/_custom_type_script = "uid://b6y3ugfydvch0"
|
||||
|
||||
[sub_resource type="Resource" id="Resource_6d4gl"]
|
||||
@@ -38,18 +39,15 @@ albedo_color = Color(0.06469653, 0.06469653, 0.06469653, 1)
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_4yfjf"]
|
||||
size = Vector3(1, 2, 1.5)
|
||||
|
||||
[node name="GroundedEnemy" type="CharacterBody3D" node_paths=PackedStringArray("CHealth", "CDamage", "CKnockback", "CMovement")]
|
||||
[node name="GroundedEnemy" type="CharacterBody3D"]
|
||||
collision_layer = 16
|
||||
collision_mask = 273
|
||||
script = ExtResource("1_r6506")
|
||||
CHealth = NodePath("CHealth")
|
||||
EnemyHeight = 2.0
|
||||
RHealth = ExtResource("2_w4lm8")
|
||||
DeathEffects = Array[Object]([])
|
||||
CDamage = NodePath("CDamageable")
|
||||
RDamage = ExtResource("2_bn56u")
|
||||
CKnockback = NodePath("CKnockback")
|
||||
RKnockback = ExtResource("11_8k3xb")
|
||||
CMovement = NodePath("CGroundedMovement")
|
||||
RMovement = ExtResource("4_na24f")
|
||||
|
||||
[node name="CHealth" type="Node" parent="."]
|
||||
@@ -57,17 +55,23 @@ script = ExtResource("2_gsmti")
|
||||
RHealth = ExtResource("2_w4lm8")
|
||||
metadata/_custom_type_script = "uid://bjwrpv3jpsc1e"
|
||||
|
||||
[node name="CHealthBar" parent="." instance=ExtResource("7_18xwy")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.2, 0)
|
||||
|
||||
[node name="CDamageable" type="Node" parent="."]
|
||||
script = ExtResource("7_1tw73")
|
||||
DamageModifiers = Array[Object]([SubResource("Resource_qj0ob")])
|
||||
metadata/_custom_type_script = "uid://b0u23nkpaimyc"
|
||||
|
||||
[node name="CGroundedMovement" parent="." node_paths=PackedStringArray("WallInFrontRayCast") instance=ExtResource("7_qyswd")]
|
||||
[node name="CMovement" parent="." node_paths=PackedStringArray("WallInFrontRayCast") instance=ExtResource("7_qyswd")]
|
||||
RMovement = SubResource("Resource_6d4gl")
|
||||
WallInFrontRayCast = NodePath("../WallInFrontRayCast")
|
||||
|
||||
[node name="CKnockback" parent="." instance=ExtResource("10_jqqi6")]
|
||||
|
||||
[node name="CTarget" type="Marker3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
|
||||
shape = SubResource("CapsuleShape3D_62kkh")
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_h6jgd")
|
||||
StartingHealth = 10.0
|
||||
metadata/_custom_type_script = "uid://baiapod3csndf"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using Godot;
|
||||
using Movementtests.interfaces;
|
||||
|
||||
namespace Movementtests.systems;
|
||||
|
||||
public partial class DashSystem: Node3D
|
||||
{
|
||||
public record DashLocation(bool HasHit, Vector3 TargetLocation, Vector3 CollisionPoint, Vector3 CollisionNormal);
|
||||
public record DashLocation(bool HasHit, Vector3 TargetLocation, Vector3 CollisionPoint, Vector3 CollisionNormal, GodotObject HitObject = null);
|
||||
|
||||
|
||||
[Export(PropertyHint.Range, "0,0.2,0.01,or_greater")]
|
||||
@@ -13,17 +14,19 @@ public partial class DashSystem: Node3D
|
||||
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 Node3D _head;
|
||||
private ShapeCast3D _dashCast3D;
|
||||
private HeadSystem _head;
|
||||
public ShapeCast3D DashCast3D;
|
||||
private Camera3D _camera;
|
||||
private Vector3 _dashDirection = Vector3.Zero;
|
||||
|
||||
@@ -49,10 +52,10 @@ public partial class DashSystem: Node3D
|
||||
|
||||
public float DashCastRadius { get; set; }
|
||||
|
||||
public void Init(Node3D head, Camera3D camera)
|
||||
public void Init(HeadSystem head, Camera3D camera)
|
||||
{
|
||||
_dashCast3D = GetNode<ShapeCast3D>("DashCast3D");
|
||||
var dashShape = _dashCast3D.GetShape() as SphereShape3D;
|
||||
DashCast3D = GetNode<ShapeCast3D>("DashCast3D");
|
||||
var dashShape = DashCast3D.GetShape() as SphereShape3D;
|
||||
DashCastRadius = dashShape!.Radius;
|
||||
|
||||
_dashCastDrop = GetNode<ShapeCast3D>("DashCastDrop");
|
||||
@@ -75,33 +78,36 @@ public partial class DashSystem: Node3D
|
||||
|
||||
private DashLocation ComputeDashLocation()
|
||||
{
|
||||
var targetLocation = _dashCast3D.ToGlobal(_dashCast3D.TargetPosition);
|
||||
var hasHit = _dashCast3D.IsColliding();
|
||||
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 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);
|
||||
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(new Vector3(
|
||||
_camera.Rotation.X,
|
||||
_head.Rotation.Y,
|
||||
_camera.Rotation.Z));
|
||||
DashCast3D.SetRotation(_head.GetGlobalLookRotation());
|
||||
|
||||
(HasHit, PlannedLocation, CollisionPoint, CollisionNormal) = ComputeDashLocation();
|
||||
(HasHit, PlannedLocation, CollisionPoint, CollisionNormal, CollidedObject) = ComputeDashLocation();
|
||||
CanDashThroughTarget = false;
|
||||
if (CollidedObject is ITargetable targetable)
|
||||
{
|
||||
_dashTarget.SetVisible(false);
|
||||
CanDashThroughTarget = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Position mantle system to planned location, aligned with ground planned and facing the same way as the dash
|
||||
// Then query it being careful when dashing underneath a platform and such
|
||||
MantleSystem.SetGlobalPosition(PlannedLocation);
|
||||
MantleSystem.SetRotation(new Vector3(
|
||||
MantleSystem.Rotation.X,
|
||||
@@ -118,6 +124,7 @@ public partial class DashSystem: Node3D
|
||||
_dashTarget.SetVisible(true);
|
||||
var targetLocation = ShouldMantle ? MantleSystem.FirstMantleProfilePoint : PlannedLocation;
|
||||
_dashTarget.SetGlobalPosition(targetLocation);
|
||||
return;
|
||||
|
||||
var shouldShowDropIndicator = !HasHit && !ShouldMantle;
|
||||
_dashDropIndicator.SetVisible(shouldShowDropIndicator);
|
||||
@@ -129,7 +136,7 @@ public partial class DashSystem: Node3D
|
||||
|
||||
// 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);
|
||||
var endDropLocation = hasDropLocationHit ? _dashCastDrop.GetCollisionPoint(0) : _dashCastDrop.ToGlobal(DashCast3D.TargetPosition);
|
||||
|
||||
// Only show drop location indicator if drop cast has hit
|
||||
_dashDropLocationIndicator.SetVisible(hasDropLocationHit);
|
||||
@@ -144,13 +151,9 @@ public partial class DashSystem: Node3D
|
||||
|
||||
public void StopPreparingDash()
|
||||
{
|
||||
CanDashThroughTarget = false;
|
||||
_dashTarget.SetVisible(false);
|
||||
_dashDropIndicator.SetVisible(false);
|
||||
_dashDropLocationIndicator.SetVisible(false);
|
||||
}
|
||||
|
||||
public void StartPreparingDash()
|
||||
{
|
||||
_dashTarget.SetVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ 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 = 256
|
||||
collision_mask = 304
|
||||
debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1)
|
||||
|
||||
[node name="DashCastDrop" type="ShapeCast3D" parent="."]
|
||||
@@ -36,7 +36,7 @@ transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0, 1
|
||||
shape = SubResource("SphereShape3D_jngg2")
|
||||
target_position = Vector3(0, 0, -50)
|
||||
max_results = 1
|
||||
collision_mask = 256
|
||||
collision_mask = 304
|
||||
debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1)
|
||||
|
||||
[node name="DashTarget" type="MeshInstance3D" parent="."]
|
||||
|
||||
@@ -310,6 +310,14 @@ public partial class HeadSystem : Node3D
|
||||
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);
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using Godot;
|
||||
using GodotStateCharts;
|
||||
using Movementtests.interfaces;
|
||||
using Movementtests.systems.damage;
|
||||
|
||||
namespace Movementtests.systems;
|
||||
|
||||
public partial class WeaponSystem : RigidBody3D
|
||||
public partial class WeaponSystem : RigidBody3D, IDamageDealer
|
||||
{
|
||||
[Signal]
|
||||
public delegate void WeaponThrownEventHandler();
|
||||
@@ -12,6 +14,8 @@ public partial class WeaponSystem : RigidBody3D
|
||||
[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")]
|
||||
@@ -22,27 +26,23 @@ public partial class WeaponSystem : RigidBody3D
|
||||
public StateChartState FlyingState;
|
||||
public StateChartState PlantedState;
|
||||
|
||||
private Node3D _head;
|
||||
private ShapeCast3D _dashCast3D;
|
||||
private Camera3D _camera;
|
||||
private TweenQueueSystem _tweenQueueSystem;
|
||||
|
||||
private Transform3D _startTransform;
|
||||
private Transform3D _startMeshTransform;
|
||||
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(Node3D head, Camera3D camera)
|
||||
public void Init()
|
||||
{
|
||||
_head = head;
|
||||
_camera = camera;
|
||||
|
||||
_weaponState = StateChart.Of(GetNode("StateChart"));
|
||||
InHandState = StateChartState.Of(GetNode("StateChart/Root/InHand"));
|
||||
FlyingState = StateChartState.Of(GetNode("StateChart/Root/Flying"));
|
||||
@@ -53,7 +53,7 @@ public partial class WeaponSystem : RigidBody3D
|
||||
WeaponLocationIndicatorMaterial = WeaponLocationIndicator.GetActiveMaterial(0) as StandardMaterial3D;
|
||||
|
||||
WeaponMesh = GetNode<MeshInstance3D>("Weapon");
|
||||
_startMeshTransform = WeaponMesh.Transform;
|
||||
_startMeshRotation = WeaponMesh.Rotation;
|
||||
|
||||
_tweenQueueSystem = GetNode<TweenQueueSystem>("TweenQueueSystem");
|
||||
_tweenQueueSystem.Init(this);
|
||||
@@ -90,7 +90,7 @@ public partial class WeaponSystem : RigidBody3D
|
||||
PlantLocation = location;
|
||||
}
|
||||
|
||||
public void ThrowWeapon(Vector3 end, bool hasHit, Vector3 collisionLocation, Vector3 collisionNormal)
|
||||
public void ThrowWeapon(Vector3 end, bool hasHit, Vector3 collisionLocation, Vector3 collisionNormal, Node collidedObject)
|
||||
{
|
||||
_weaponState.SendEvent("throw");
|
||||
|
||||
@@ -103,11 +103,32 @@ public partial class WeaponSystem : RigidBody3D
|
||||
|
||||
var tween = _tweenQueueSystem.TweenToLocation(new TweenQueueSystem.TweenInputs(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(this, RDamage));
|
||||
}
|
||||
}
|
||||
|
||||
public void RethrowWeapon()
|
||||
{
|
||||
_weaponState.SendEvent("throw");
|
||||
_throwDirection = Vector3.Up;
|
||||
ThrowWeaponOnCurve();
|
||||
}
|
||||
|
||||
public void ThrowWeaponOnCurve()
|
||||
{
|
||||
Freeze = false;
|
||||
@@ -118,16 +139,21 @@ public partial class WeaponSystem : RigidBody3D
|
||||
{
|
||||
_weaponState.SendEvent("plant");
|
||||
|
||||
// WeaponLocationIndicatorMaterial.StencilColor = new Color(1f, 0.2f, 0.2f);
|
||||
|
||||
Freeze = true;
|
||||
GlobalPosition = PlantLocation;
|
||||
WeaponMesh.Transform = _startMeshTransform;
|
||||
LookAt(GlobalTransform.Origin + PlantNormal, Vector3.Up, 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();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[gd_scene load_steps=12 format=3 uid="uid://ckm3d6k08a72u"]
|
||||
[gd_scene load_steps=14 format=3 uid="uid://ckm3d6k08a72u"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://iii3wfto4t5b" path="res://systems/weapon/WeaponSystem.cs" id="1_csqwk"]
|
||||
[ext_resource type="Script" uid="uid://jitubgv6judn" path="res://components/damage/RDamage.cs" id="2_m0v1h"]
|
||||
[ext_resource type="PackedScene" uid="uid://dbe5f0p6lvqtr" path="res://systems/tween_queue/tween_queue_system.tscn" id="2_x1nha"]
|
||||
[ext_resource type="Script" uid="uid://couw105c3bde4" path="res://addons/godot_state_charts/state_chart.gd" id="3_5owyf"]
|
||||
[ext_resource type="ArrayMesh" uid="uid://cho5fixitrbds" path="res://assets/swords/resources/sword23.tres" id="3_svc06"]
|
||||
@@ -8,6 +9,11 @@
|
||||
[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
|
||||
@@ -38,11 +44,12 @@ material = SubResource("StandardMaterial3D_m0v1h")
|
||||
|
||||
[node name="Weapon" type="RigidBody3D"]
|
||||
collision_layer = 65536
|
||||
collision_mask = 256
|
||||
collision_mask = 304
|
||||
continuous_cd = true
|
||||
contact_monitor = true
|
||||
max_contacts_reported = 1
|
||||
script = ExtResource("1_csqwk")
|
||||
RDamage = SubResource("Resource_jpdh0")
|
||||
|
||||
[node name="TweenQueueSystem" parent="." instance=ExtResource("2_x1nha")]
|
||||
|
||||
@@ -54,6 +61,9 @@ shape = SubResource("CylinderShape3D_avini")
|
||||
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="."]
|
||||
mesh = SubResource("SphereMesh_jpdh0")
|
||||
|
||||
[node name="StateChart" type="Node" parent="."]
|
||||
script = ExtResource("3_5owyf")
|
||||
metadata/_custom_type_script = "uid://couw105c3bde4"
|
||||
@@ -89,11 +99,14 @@ delay_in_seconds = "0.0"
|
||||
[node name="Planted" type="Node" parent="StateChart/Root"]
|
||||
script = ExtResource("5_m0v1h")
|
||||
|
||||
[node name="ToFlying" type="Node" parent="StateChart/Root/Planted"]
|
||||
script = ExtResource("6_jpdh0")
|
||||
to = NodePath("../../Flying")
|
||||
event = &"throw"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="ToHand" type="Node" parent="StateChart/Root/Planted"]
|
||||
script = ExtResource("6_jpdh0")
|
||||
to = NodePath("../../InHand")
|
||||
event = &"recover"
|
||||
delay_in_seconds = "0.0"
|
||||
|
||||
[node name="WeaponLocationIndicator" type="MeshInstance3D" parent="."]
|
||||
mesh = SubResource("SphereMesh_jpdh0")
|
||||
|
||||
Reference in New Issue
Block a user