Compare commits

..

4 Commits

Author SHA1 Message Date
18c8b741dd can plant weapon in targetables, dash towards it, jump in the air.
Some checks failed
Create tag and build when new code gets to main / BumpTag (push) Successful in 28s
Create tag and build when new code gets to main / Export (push) Failing after 1m47s
2026-01-24 15:22:16 +01:00
b84b7e4dd5 aim dashing through targetable entities now possible 2026-01-24 13:49:16 +01:00
4d419b9010 basic healthbars for enemies 2026-01-23 13:31:11 +01:00
8b2bf3e32e fixed a going through wall issue 2026-01-21 17:31:24 +01:00
20 changed files with 351 additions and 129 deletions

View File

@@ -1,7 +1,9 @@
<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"> <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_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_003ACharacterBody3D_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fe56b84c3fa498fb86fc1eba376f62f482127e3fe80415c5fb2acde2bf6d89793_003FCharacterBody3D_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACharacterBody3D_002Ecs_002Fl_003AC_0021_003FUsers_003FMinimata_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fe56b84c3fa498fb86fc1eba376f62f482127e3fe80415c5fb2acde2bf6d89793_003FCharacterBody3D_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_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_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: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> <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

Binary file not shown.

View 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

View File

@@ -5,7 +5,7 @@ using Movementtests.interfaces;
[GlobalClass] [GlobalClass]
public partial class CHealth : Node, IHealthable public partial class CHealth : Node, IHealthable
{ {
public event Action<IHealthable, float> HealthChanged; public event Action<IHealthable, HealthChangedRecord> HealthChanged;
public event Action<IHealthable> HealthDepleted; public event Action<IHealthable> HealthDepleted;
[Export] [Export]
@@ -18,15 +18,18 @@ public partial class CHealth : Node, IHealthable
CurrentHealth = RHealth.StartingHealth; CurrentHealth = RHealth.StartingHealth;
} }
public void ReduceHealth(IDamageable source, DamageRecord damageRecord) public HealthChangedRecord ReduceHealth(IDamageable source, DamageRecord damageRecord)
{ {
var previousHealth = CurrentHealth;
CurrentHealth -= damageRecord.Damage.DamageDealt; CurrentHealth -= damageRecord.Damage.DamageDealt;
HealthChanged?.Invoke(this, CurrentHealth); var record = new HealthChangedRecord(CurrentHealth, previousHealth, RHealth.StartingHealth);
HealthChanged?.Invoke(this, record);
if (CurrentHealth <= 0) if (CurrentHealth <= 0)
{ {
CurrentHealth = 0; CurrentHealth = 0;
HealthDepleted?.Invoke(this); HealthDepleted?.Invoke(this);
} }
return record;
} }
} }

View 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);
}
}

View File

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

View 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")

View File

@@ -8,6 +8,7 @@ public record DamageRecord(Node3D Source, RDamage Damage);
public interface IDamageable public interface IDamageable
{ {
event Action<IDamageable, DamageRecord> DamageTaken; event Action<IDamageable, DamageRecord> DamageTaken;
DamageRecord TakeDamage(DamageRecord damageRecord); DamageRecord TakeDamage(DamageRecord damageRecord);
DamageRecord ComputeDamage(DamageRecord damageRecord); DamageRecord ComputeDamage(DamageRecord damageRecord);
} }

View File

@@ -3,14 +3,16 @@ using Godot;
namespace Movementtests.interfaces; namespace Movementtests.interfaces;
public record HealthChangedRecord(float CurrentHealth, float PreviousHealth, float MaxHealth);
public interface IHealthable public interface IHealthable
{ {
event Action<IHealthable, float> HealthChanged; event Action<IHealthable, HealthChangedRecord> HealthChanged;
event Action<IHealthable> HealthDepleted; event Action<IHealthable> HealthDepleted;
[Export] RHealth RHealth { get; set; } [Export] RHealth RHealth { get; set; }
float CurrentHealth { get; set; } float CurrentHealth { get; set; }
void ReduceHealth(IDamageable source, DamageRecord damageRecord); HealthChangedRecord ReduceHealth(IDamageable source, DamageRecord damageRecord);
} }

View File

@@ -1,13 +1,12 @@
[gd_scene load_steps=25 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="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="Material" uid="uid://31aulub2nqov" path="res://assets/greybox/m_greybox.tres" id="2_3uydm"]
[ext_resource type="PackedScene" uid="uid://dxt0e2ugmttqq" path="res://scenes/enemies/grounded_enemy/grounded_enemy.tscn" id="3_3uydm"] [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="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="Script" uid="uid://b44cse62qru7j" path="res://components/knockback/RKnockback.cs" id="6_1hrkh"] [ext_resource type="Script" uid="uid://b44cse62qru7j" path="res://components/knockback/RKnockback.cs" id="6_1hrkh"]
[ext_resource type="PackedScene" uid="uid://c305mfrtumcyq" path="res://scenes/spawners/spawner.tscn" id="6_7m3bq"] [ext_resource type="PackedScene" uid="uid://c305mfrtumcyq" path="res://scenes/spawners/spawner.tscn" id="6_7m3bq"]
[ext_resource type="Script" uid="uid://dtpxijlnb2c5" path="res://components/movement/RMovement.cs" id="6_ybosk"]
[ext_resource type="Resource" uid="uid://bqq6uukbdfysr" path="res://scenes/enemies/grounded_enemy/grounded_enemy_movement.tres" id="7_caohq"] [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"] [ext_resource type="Script" uid="uid://baiapod3csndf" path="res://components/health/RHealth.cs" id="9_2e4ci"]
[ext_resource type="Resource" uid="uid://otfc2snh8umc" path="res://scenes/enemies/grounded_enemy/grounded_enemy_damage.tres" id="9_dmw1t"] [ext_resource type="Resource" uid="uid://otfc2snh8umc" path="res://scenes/enemies/grounded_enemy/grounded_enemy_damage.tres" id="9_dmw1t"]
@@ -38,27 +37,13 @@ ssil_radius = 8.4
sdfgi_use_occlusion = true sdfgi_use_occlusion = true
glow_enabled = 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_q21h6"] [sub_resource type="Resource" id="Resource_q21h6"]
script = ExtResource("6_1hrkh") script = ExtResource("6_1hrkh")
metadata/_custom_type_script = "uid://b44cse62qru7j" metadata/_custom_type_script = "uid://b44cse62qru7j"
[sub_resource type="Resource" id="Resource_5fa36"] [sub_resource type="Resource" id="Resource_5fa36"]
script = ExtResource("6_ybosk") script = ExtResource("5_ybosk")
GravityModifier = 1.0 GravityModifier = 5.0
metadata/_custom_type_script = "uid://dtpxijlnb2c5"
[sub_resource type="Resource" id="Resource_blhrq"]
script = ExtResource("6_ybosk")
GravityModifier = 1.0
metadata/_custom_type_script = "uid://dtpxijlnb2c5"
[sub_resource type="Resource" id="Resource_1hrkh"]
script = ExtResource("6_ybosk")
TargetHeight = 5.0
metadata/_custom_type_script = "uid://dtpxijlnb2c5" metadata/_custom_type_script = "uid://dtpxijlnb2c5"
[sub_resource type="Resource" id="Resource_ybosk"] [sub_resource type="Resource" id="Resource_ybosk"]
@@ -108,6 +93,12 @@ use_collision = true
size = Vector3(6.5, 4, 17) size = Vector3(6.5, 4, 17)
material = ExtResource("2_3uydm") 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"] [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) transform = Transform3D(0.81915206, 0, 0.57357645, 0, 1, 0, -0.57357645, 0, 0.81915206, -7.3460007, 0, -3.9585)
use_collision = true use_collision = true
@@ -138,34 +129,34 @@ use_collision = true
size = Vector3(6.5, 11, 5.5) size = Vector3(6.5, 11, 5.5)
material = ExtResource("2_3uydm") 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")] [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") Target = NodePath("../Player")
DeathEffects = Array[Object]([SubResource("Resource_sysok")])
RKnockback = SubResource("Resource_q21h6") RKnockback = SubResource("Resource_q21h6")
RMovement = SubResource("Resource_5fa36") RMovement = SubResource("Resource_5fa36")
[node name="Enemy2" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("3_3uydm")] [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") Target = NodePath("../Player")
RKnockback = SubResource("Resource_q21h6") RMovement = SubResource("Resource_5fa36")
RMovement = SubResource("Resource_blhrq")
[node name="Enemy3" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("3_3uydm")] [node name="Enemy3" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("3_3uydm")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7, 0, 0.16319084) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 14, 4, -3.3368092)
Target = NodePath("../Player") Target = NodePath("../Player")
RKnockback = SubResource("Resource_q21h6")
RMovement = SubResource("Resource_5fa36") RMovement = SubResource("Resource_5fa36")
[node name="FlyingEnemy" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("5_8fd2t")] [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) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8, 7, -16)
Target = NodePath("../Player") Target = NodePath("../Player")
RMovement = SubResource("Resource_1hrkh") RMovement = SubResource("Resource_5fa36")
[node name="FlyingEnemy2" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("5_8fd2t")] [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) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 7, -16)
Target = NodePath("../Player") Target = NodePath("../Player")
RMovement = SubResource("Resource_1hrkh") RMovement = SubResource("Resource_5fa36")
[node name="GroundedSpawner" parent="." node_paths=PackedStringArray("Target") instance=ExtResource("6_7m3bq")] [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) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 2.5, -15)
@@ -184,6 +175,3 @@ HealthInputs = ExtResource("11_2e4ci")
DamageInputs = ExtResource("9_gp7s3") DamageInputs = ExtResource("9_gp7s3")
Target = NodePath("../Player") Target = NodePath("../Player")
IsActiveOnStart = false IsActiveOnStart = false
[node name="FixedDashthroughTarget" parent="." instance=ExtResource("15_5fa36")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.5, 3.5, 0)

View File

@@ -54,7 +54,7 @@
[sub_resource type="Resource" id="Resource_cb2lu"] [sub_resource type="Resource" id="Resource_cb2lu"]
script = ExtResource("2_x835q") script = ExtResource("2_x835q")
DamageDealt = 3.0 DamageDealt = 30.0
metadata/_custom_type_script = "uid://jitubgv6judn" metadata/_custom_type_script = "uid://jitubgv6judn"
[sub_resource type="Resource" id="Resource_abfq8"] [sub_resource type="Resource" id="Resource_abfq8"]
@@ -105,6 +105,7 @@ script = ExtResource("1_poq2x")
RDamage = SubResource("Resource_cb2lu") RDamage = SubResource("Resource_cb2lu")
RKnockback = SubResource("Resource_abfq8") RKnockback = SubResource("Resource_abfq8")
RHealth = SubResource("Resource_ue7xq") RHealth = SubResource("Resource_ue7xq")
TargetingDistance = 5.0
WalkSpeed = 7.5 WalkSpeed = 7.5
AccelerationFloor = 4.0 AccelerationFloor = 4.0
DecelerationFloor = 3.0 DecelerationFloor = 3.0

View File

@@ -41,7 +41,7 @@ public partial class PlayerController : CharacterBody3D,
/////////////////////////// ///////////////////////////
public event Action<IDamageable, DamageRecord> DamageTaken; public event Action<IDamageable, DamageRecord> DamageTaken;
public event Action<IHealthable, float> HealthChanged; public event Action<IHealthable, HealthChangedRecord> HealthChanged;
public event Action<IHealthable> HealthDepleted; public event Action<IHealthable> HealthDepleted;
/////////////////////////// ///////////////////////////
@@ -313,6 +313,7 @@ public partial class PlayerController : CharacterBody3D,
private StateChartState _mantling; private StateChartState _mantling;
private StateChartState _simpleDash; private StateChartState _simpleDash;
private StateChartState _aimedDash; private StateChartState _aimedDash;
private StateChartState _weaponDash;
private StateChartState _sliding; private StateChartState _sliding;
private StateChartState _groundSliding; private StateChartState _groundSliding;
private StateChartState _airGliding; private StateChartState _airGliding;
@@ -426,7 +427,7 @@ public partial class PlayerController : CharacterBody3D,
} }
if (RKnockback != null) CKnockback!.RKnockback = RKnockback; if (RKnockback != null) CKnockback!.RKnockback = RKnockback;
CDamageable.DamageTaken += ReduceHealth; CDamageable.DamageTaken += (source, record) => ReduceHealth(source, record);
CDamageable.DamageTaken += RegisterKnockback; CDamageable.DamageTaken += RegisterKnockback;
CHealth.HealthDepleted += Kill; CHealth.HealthDepleted += Kill;
@@ -436,6 +437,7 @@ public partial class PlayerController : CharacterBody3D,
_aiming = StateChartState.Of(GetNode("StateChart/Root/Aim/On")); _aiming = StateChartState.Of(GetNode("StateChart/Root/Aim/On"));
_simpleDash = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing/Dash")); _simpleDash = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing/Dash"));
_aimedDash = StateChartState.Of(GetNode("StateChart/Root/Movement/Dashing/AimedDash")); _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")); _slamming = StateChartState.Of(GetNode("StateChart/Root/Movement/Slamming"));
_sliding = StateChartState.Of(GetNode("StateChart/Root/Movement/Sliding")); _sliding = StateChartState.Of(GetNode("StateChart/Root/Movement/Sliding"));
@@ -499,7 +501,7 @@ public partial class PlayerController : CharacterBody3D,
MantleSystem.Init(); MantleSystem.Init();
StairsSystem.Init(stairsBelowRayCast3D, stairsAheadRayCast3D, cameraSmooth); StairsSystem.Init(stairsBelowRayCast3D, stairsAheadRayCast3D, cameraSmooth);
DashSystem.Init(HeadSystem, _camera); DashSystem.Init(HeadSystem, _camera);
WeaponSystem.Init(HeadSystem, _camera); WeaponSystem.Init();
WallHugSystem.Init(); WallHugSystem.Init();
EmpoweredActionsLeft = MaxNumberOfEmpoweredActions; EmpoweredActionsLeft = MaxNumberOfEmpoweredActions;
@@ -548,6 +550,8 @@ public partial class PlayerController : CharacterBody3D,
_aimedDash.StateEntered += OnAimedDashStarted; _aimedDash.StateEntered += OnAimedDashStarted;
_aimedDash.StateExited += OnAimedDashFinished; _aimedDash.StateExited += OnAimedDashFinished;
_weaponDash.StateExited += OnWeaponDashFinished;
_sliding.StateEntered += SlideStarted; _sliding.StateEntered += SlideStarted;
_sliding.StateExited += SlideEnded; _sliding.StateExited += SlideEnded;
_slideCanceled.StateEntered += OnSlideCanceled; _slideCanceled.StateEntered += OnSlideCanceled;
@@ -576,7 +580,7 @@ public partial class PlayerController : CharacterBody3D,
_onWallRunning.StatePhysicsProcessing += HandleWallRunning; _onWallRunning.StatePhysicsProcessing += HandleWallRunning;
_onWallHanging.StateExited += RecoverWeapon; _onWallHanging.StateExited += RecoverWeapon;
_onDashEnded.Taken += RecoverWeapon; // _onDashEnded.Taken += RecoverWeapon;
_onJumpFromWall.Taken += OnJumpFromWall; _onJumpFromWall.Taken += OnJumpFromWall;
_onJumpFromWallFalling.Taken += OnJumpFromWall; _onJumpFromWallFalling.Taken += OnJumpFromWall;
@@ -975,7 +979,7 @@ public partial class PlayerController : CharacterBody3D,
} }
public void RecoverChildNode(Node3D node) public void RecoverChildNode(Node3D node)
{ {
GetTree().GetRoot().RemoveChild(node); node.GetParent().RemoveChild(node);
AddChild(node); AddChild(node);
node.SetGlobalPosition(GlobalPosition); node.SetGlobalPosition(GlobalPosition);
} }
@@ -1653,15 +1657,14 @@ public partial class PlayerController : CharacterBody3D,
if (!CanPerformEmpoweredAction()) if (!CanPerformEmpoweredAction())
return; return;
DashSystem.StartPreparingDash(); // DashIndicatorMesh.Visible = true;
DashIndicatorMesh.Visible = true;
if (!isOnFloorCustom()) if (!isOnFloorCustom())
ReduceTimeScaleWhileAiming(); ReduceTimeScaleWhileAiming();
} }
public void HandleAiming(float delta) public void HandleAiming(float delta)
{ {
DashIndicatorMeshCylinder.Height = DashSystem.PlannedLocation.DistanceTo(GlobalPosition); // DashIndicatorMeshCylinder.Height = DashSystem.PlannedLocation.DistanceTo(GlobalPosition);
DashIndicatorNode.LookAt(DashSystem.PlannedLocation); // DashIndicatorNode.LookAt(DashSystem.PlannedLocation);
if (CanPerformEmpoweredAction()) if (CanPerformEmpoweredAction())
DashSystem.PrepareDash(); DashSystem.PrepareDash();
@@ -1670,7 +1673,7 @@ public partial class PlayerController : CharacterBody3D,
{ {
DashSystem.StopPreparingDash(); DashSystem.StopPreparingDash();
DashIndicatorMesh.Visible = false; // DashIndicatorMesh.Visible = false;
} }
/////////////////////////// ///////////////////////////
@@ -1701,7 +1704,12 @@ public partial class PlayerController : CharacterBody3D,
// feet of the capsule // feet of the capsule
var correction = DashSystem.CollisionNormal == Vector3.Down ? _playerHeight : DashSystem.DashCastRadius; var correction = DashSystem.CollisionNormal == Vector3.Down ? _playerHeight : DashSystem.DashCastRadius;
var correctedLocation = DashSystem.PlannedLocation + Vector3.Down * correction; 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; _preDashVelocity = Velocity;
_dashDirection = (correctedLocation - GlobalPosition).Normalized(); _dashDirection = (correctedLocation - GlobalPosition).Normalized();
@@ -1720,6 +1728,9 @@ public partial class PlayerController : CharacterBody3D,
} }
public void OnAimedDashFinished() public void OnAimedDashFinished()
{ {
ManageAttackedEnemyPostDash(DashSystem.CollidedObject as Node);
DashSystem.CollidedObject = null;
if (_customMantle) if (_customMantle)
{ {
_playerState.SendEvent("mantle"); _playerState.SendEvent("mantle");
@@ -1743,23 +1754,27 @@ public partial class PlayerController : CharacterBody3D,
weaponTargetLocation, weaponTargetLocation,
DashSystem.HasHit, DashSystem.HasHit,
DashSystem.CollisionPoint, DashSystem.CollisionPoint,
DashSystem.CollisionNormal); DashSystem.CollisionNormal,
DashSystem.CollidedObject as Node);
} }
public void RecoverWeapon() public void RecoverWeapon()
{ {
if (WeaponSystem.GetParent() == this) return; if (WeaponSystem.GetParent() == this) return;
HeadSystem.ShowWeapon(); HeadSystem.ShowWeapon();
RecoverChildNode(WeaponSystem);
WeaponSystem.ResetWeapon(); WeaponSystem.ResetWeapon();
RecoverChildNode(WeaponSystem);
} }
public void DashToFlyingWeapon() public void DashToFlyingWeapon()
{ {
_playerState.SendEvent("cancel_aim"); _playerState.SendEvent("cancel_aim");
_playerState.SendEvent("weapon_dash"); _playerState.SendEvent("weapon_dash");
PerformEmpoweredAction(); PerformEmpoweredAction();
_audioStream.SwitchToClipByName("dash"); _audioStream.SwitchToClipByName("dash");
// Start invincibility timer for the duration of the dash and a bit more afterwards
OnHitInvincibility();
DashSystem.ShouldMantle = false; DashSystem.ShouldMantle = false;
_dashDirection = (WeaponSystem.GlobalPosition - GlobalPosition).Normalized(); _dashDirection = (WeaponSystem.GlobalPosition - GlobalPosition).Normalized();
@@ -1780,8 +1795,11 @@ public partial class PlayerController : CharacterBody3D,
{ {
_playerState.SendEvent("cancel_aim"); _playerState.SendEvent("cancel_aim");
_playerState.SendEvent("weapon_dash"); _playerState.SendEvent("weapon_dash");
PerformEmpoweredAction(); PerformEmpoweredAction();
_audioStream.SwitchToClipByName("dash"); _audioStream.SwitchToClipByName("dash");
// Start invincibility timer for the duration of the dash and a bit more afterwards
OnHitInvincibility();
DashSystem.ShouldMantle = false; DashSystem.ShouldMantle = false;
var dashLocation = WeaponSystem.PlantLocation; var dashLocation = WeaponSystem.PlantLocation;
@@ -1789,7 +1807,9 @@ public partial class PlayerController : CharacterBody3D,
dashLocation += WeaponSystem.PlantNormal * _playerRadius; dashLocation += WeaponSystem.PlantNormal * _playerRadius;
if (WeaponSystem.IsPlantedUnderPlatform()) if (WeaponSystem.IsPlantedUnderPlatform())
dashLocation += Vector3.Down * _playerHeight; dashLocation += Vector3.Down * _playerHeight;
if (WeaponSystem.PlantObject is ITargetable targetable)
dashLocation = targetable.GetTargetGlobalPosition();
_wallHugStartNormal = WeaponSystem.PlantNormal; _wallHugStartNormal = WeaponSystem.PlantNormal;
_currentWallContactPoint = WeaponSystem.PlantLocation; _currentWallContactPoint = WeaponSystem.PlantLocation;
_wallHugStartLocation = dashLocation; _wallHugStartLocation = dashLocation;
@@ -1803,17 +1823,45 @@ public partial class PlayerController : CharacterBody3D,
// Store the weapon state before resetting it // Store the weapon state before resetting it
var isPlantedOnWall = WeaponSystem.IsPlantedInWall(); var isPlantedOnWall = WeaponSystem.IsPlantedInWall();
var isPlantedUnderPlatform = WeaponSystem.IsPlantedUnderPlatform(); 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"; 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 targetable)
{
HeadSystem.OnMantle(); // Recycle mantle animation
SetVerticalVelocity(PostDashSpeed);
}
ManageAttackedEnemyPostDash(WeaponSystem.PlantObject);
WeaponSystem.PlantObject = null;
_playerState.SendEvent(resultingEvent); _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 ////////////// // Processes //////////////
/////////////////////////// ///////////////////////////
public override void _PhysicsProcess(double delta) public override void _PhysicsProcess(double delta)
{ {
_spaceState = GetWorld3D().DirectSpaceState;
if (_currentInputBufferFrames > 0) _currentInputBufferFrames -= 1; if (_currentInputBufferFrames > 0) _currentInputBufferFrames -= 1;
// Manage head and camera movement // Manage head and camera movement
@@ -1827,20 +1875,18 @@ public partial class PlayerController : CharacterBody3D,
MantleSystem.ProcessMantle(_grounded.Active); MantleSystem.ProcessMantle(_grounded.Active);
HandleEnemyTargeting(); HandleEnemyTargeting();
if (_closeEnemyDetector.IsColliding())
// Manage dash target and tutorial specific stuff // Manage dash target and tutorial specific stuff
if (WeaponSystem.InHandState.Active && !_aiming.Active && TutorialDone) // if (WeaponSystem.InHandState.Active && !_aiming.Active && TutorialDone)
{ // {
DashIndicatorMesh.Visible = false; // DashIndicatorMesh.Visible = false;
} // }
if (!WeaponSystem.InHandState.Active && TutorialDone) // if (!WeaponSystem.InHandState.Active && TutorialDone)
{ // {
DashIndicatorMesh.Visible = true; // DashIndicatorMesh.Visible = true;
//
DashIndicatorMeshCylinder.Height = WeaponSystem.GlobalPosition.DistanceTo(GlobalPosition) * 2; // DashIndicatorMeshCylinder.Height = WeaponSystem.GlobalPosition.DistanceTo(GlobalPosition) * 2;
DashIndicatorNode.LookAt(WeaponSystem.GlobalPosition); // DashIndicatorNode.LookAt(WeaponSystem.GlobalPosition);
} // }
} }
/////////////////////////// ///////////////////////////
@@ -1855,9 +1901,19 @@ public partial class PlayerController : CharacterBody3D,
{ {
_isEnemyInDashAttackRange = false; _isEnemyInDashAttackRange = false;
_closeEnemyDetector.SetRotation(HeadSystem.GetGlobalLookRotation()); _closeEnemyDetector.SetRotation(HeadSystem.GetGlobalLookRotation());
var enemyTargetState = PlayerUi.TargetState.NoTarget; var enemyTargetState = PlayerUi.TargetState.NoTarget;
var positionOnScreen = Vector2.Zero; 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()) if (!_closeEnemyDetector.IsColliding())
{ {
PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen)); PlayerUi.SetEnemyTargetProperties(new PlayerUi.TargetProperties(enemyTargetState, positionOnScreen));
@@ -1875,8 +1931,8 @@ public partial class PlayerController : CharacterBody3D,
_targetLocation = target.GetTargetGlobalPosition(); _targetLocation = target.GetTargetGlobalPosition();
var targetDistance = _targetLocation.DistanceTo(GlobalPosition); var targetDistance = _targetLocation.DistanceTo(GlobalPosition);
positionOnScreen = _camera.UnprojectPosition(_targetLocation); positionOnScreen = _camera.UnprojectPosition(_targetLocation);
_isEnemyInDashAttackRange = targetDistance < TargetInRangeDistance; _isEnemyInDashAttackRange = true; //targetDistance < TargetInRangeDistance; // Removing the "almost dash" UI
if (_isEnemyInDashAttackRange) if (_isEnemyInDashAttackRange)
{ {
enemyTargetState = PlayerUi.TargetState.TargetDashThrough; enemyTargetState = PlayerUi.TargetState.TargetDashThrough;
@@ -1926,17 +1982,26 @@ public partial class PlayerController : CharacterBody3D,
_audioStream!.SwitchToClipByName("attacks"); _audioStream!.SwitchToClipByName("attacks");
} }
private PhysicsDirectSpaceState3D _spaceState;
public void OnDashAttackStarted() public void OnDashAttackStarted()
{ {
_audioStream!.SwitchToClipByName("attacks"); _audioStream!.SwitchToClipByName("attacks");
_isInvincible = true; _isInvincible = true;
var actualDashLocation = _targetLocation + Vector3.Down*HeadSystem.Position.Y; var plannedDashLocation = _targetLocation + Vector3.Down*HeadSystem.Position.Y;
var travel = actualDashLocation - GlobalPosition;
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; _preDashVelocity = Velocity;
_dashDirection = travel.Normalized(); _dashDirection = travel.Normalized();
var dashTween = CreatePositionTween(actualDashLocation, AimedDashTime); var dashTween = CreatePositionTween(plannedDashLocation, AimedDashTime);
dashTween.Finished += OnDashAttackEnded; dashTween.Finished += OnDashAttackEnded;
} }
@@ -1965,20 +2030,25 @@ public partial class PlayerController : CharacterBody3D,
} }
else else
{ {
var locationOtherSide = _targetLocation + (_targetLocation - _targetHitLocation); GlobalPosition = ComputePositionAfterTargetedDash(_targetLocation, _targetHitLocation);
GlobalPosition = locationOtherSide;
var postDashVelocity = _preDashVelocity.Length() > PostDashSpeed ? _preDashVelocity.Length() : PostDashSpeed; var postDashVelocity = _preDashVelocity.Length() > PostDashSpeed ? _preDashVelocity.Length() : PostDashSpeed;
Velocity = _dashDirection * postDashVelocity; Velocity = _dashDirection * postDashVelocity;
} }
_isInvincible = false; _isInvincible = false;
_playerState.SendEvent("attack_finished"); _playerState.SendEvent("attack_finished");
} }
public Vector3 ComputePositionAfterTargetedDash(Vector3 targetLocation, Vector3 targetHitLocation)
{
return targetLocation + (targetLocation - targetHitLocation);
}
public void OnInputHitPressed() public void OnInputHitPressed()
{ {
if (_aiming.Active && WeaponSystem.InHandState.Active) if (_aiming.Active && WeaponSystem.InHandState.Active)
{ {
ThrowWeapon(); ThrowWeapon();
return;
} }
var attackToDo = _isEnemyInDashAttackRange ? "dash_attack" : "standard_attack"; var attackToDo = _isEnemyInDashAttackRange ? "dash_attack" : "standard_attack";
@@ -2031,11 +2101,12 @@ public partial class PlayerController : CharacterBody3D,
{ {
ResetTimeScale(); ResetTimeScale();
} }
public void ReduceHealth(IDamageable source, DamageRecord damageRecord) public HealthChangedRecord ReduceHealth(IDamageable source, DamageRecord damageRecord)
{ {
GD.Print("That's NOT fine"); GD.Print("That's NOT fine");
CHealth.ReduceHealth(source, damageRecord); var record = CHealth.ReduceHealth(source, damageRecord);
HealthChanged?.Invoke(this, CHealth.CurrentHealth); HealthChanged?.Invoke(this, record);
return record;
} }
public void RegisterKnockback(IDamageable source, DamageRecord damageRecord) public void RegisterKnockback(IDamageable source, DamageRecord damageRecord)
{ {

View File

@@ -1,6 +1,7 @@
using System; using System;
using Godot; using Godot;
using Movementtests.interfaces; using Movementtests.interfaces;
using Movementtests.systems;
[GlobalClass] [GlobalClass]
public partial class Enemy : CharacterBody3D, public partial class Enemy : CharacterBody3D,
@@ -16,12 +17,14 @@ public partial class Enemy : CharacterBody3D,
{ {
// Signals and events // Signals and events
public event Action<IDamageable, DamageRecord> DamageTaken; public event Action<IDamageable, DamageRecord> DamageTaken;
public event Action<IHealthable, float> HealthChanged; public event Action<IHealthable, HealthChangedRecord> HealthChanged;
public event Action<IHealthable> HealthDepleted; public event Action<IHealthable> HealthDepleted;
// Public export components // Public export components
[Export] [Export]
public Node3D Target { get; set; } public Node3D Target { get; set; }
[Export]
public float EnemyHeight { get; set; } = 1f;
[ExportGroup("Health")] [ExportGroup("Health")]
[Export] [Export]
@@ -54,6 +57,7 @@ public partial class Enemy : CharacterBody3D,
// Private stuff // Private stuff
private Area3D _damageBox; private Area3D _damageBox;
private Node3D _target; private Node3D _target;
private CHealthbar _healthbar;
public override void _Ready() public override void _Ready()
{ {
@@ -75,6 +79,8 @@ public partial class Enemy : CharacterBody3D,
if (CHealth is null) GD.PrintErr("This node needs a 'CHealth' child of type IHealthable!"); 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!"); 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 (RMovement != null) CMovement!.RMovement = RMovement;
if (RHealth != null) if (RHealth != null)
{ {
@@ -86,9 +92,11 @@ public partial class Enemy : CharacterBody3D,
public void SetupSignals() public void SetupSignals()
{ {
CDamageable.DamageTaken += ReduceHealth; // Anonymous function call to erase return values of ReduceHealth
CDamageable.DamageTaken += (source, record) => ReduceHealth(source, record);
CDamageable.DamageTaken += RegisterKnockback; CDamageable.DamageTaken += RegisterKnockback;
CHealth.HealthDepleted += Kill; CHealth.HealthDepleted += Kill;
HealthChanged += (source, record) => _healthbar.OnHealthChanged(record);
} }
public override void _PhysicsProcess(double delta) public override void _PhysicsProcess(double delta)
@@ -147,20 +155,33 @@ public partial class Enemy : CharacterBody3D,
return CDamageable.ComputeDamage(damageRecord); return CDamageable.ComputeDamage(damageRecord);
} }
public void ReduceHealth(IDamageable source, DamageRecord damageRecord) public HealthChangedRecord ReduceHealth(IDamageable source, DamageRecord damageRecord)
{ {
if (CHealth is null) return; if (CHealth is null) return new HealthChangedRecord(0, 0, 0);
CHealth.ReduceHealth(source, damageRecord); var record = CHealth.ReduceHealth(source, damageRecord);
HealthChanged?.Invoke(this, CHealth.CurrentHealth); HealthChanged?.Invoke(this, record);
return record;
} }
public void Kill(IHealthable source) 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()) foreach (var killable in DeathEffects.ToIKillables())
{ {
killable.Kill(source); killable.Kill(source);
} }
QueueFree(); CallDeferred(Node.MethodName.QueueFree);
} }
public void RegisterKnockback(IDamageable source, DamageRecord damageRecord) public void RegisterKnockback(IDamageable source, DamageRecord damageRecord)

View File

@@ -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://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"] [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="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="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://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://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="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"] [ext_resource type="PackedScene" uid="uid://bctpe34ddamg5" path="res://components/knockback/CKnockback.tscn" id="10_dejyg"]
@@ -47,6 +48,7 @@ collision_layer = 16
collision_mask = 273 collision_mask = 273
motion_mode = 1 motion_mode = 1
script = ExtResource("1_q8l7o") script = ExtResource("1_q8l7o")
EnemyHeight = 0.5
RHealth = ExtResource("2_ma2bq") RHealth = ExtResource("2_ma2bq")
DeathEffects = Array[Object]([]) DeathEffects = Array[Object]([])
RDamage = ExtResource("2_on7rt") RDamage = ExtResource("2_on7rt")
@@ -58,6 +60,9 @@ script = ExtResource("4_ys4jv")
RHealth = ExtResource("2_ma2bq") RHealth = ExtResource("2_ma2bq")
metadata/_custom_type_script = "uid://bjwrpv3jpsc1e" 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="."] [node name="CDamageable" type="Node" parent="."]
script = ExtResource("8_uotso") script = ExtResource("8_uotso")
DamageModifiers = Array[Object]([SubResource("Resource_jnv07"), SubResource("Resource_53j1c")]) DamageModifiers = Array[Object]([SubResource("Resource_jnv07"), SubResource("Resource_53j1c")])

View File

@@ -4,5 +4,5 @@
[resource] [resource]
script = ExtResource("1_jht15") script = ExtResource("1_jht15")
StartingHealth = 50.0 StartingHealth = 10.0
metadata/_custom_type_script = "uid://baiapod3csndf" metadata/_custom_type_script = "uid://baiapod3csndf"

View File

@@ -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="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"] [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://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="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="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="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="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"] [ext_resource type="PackedScene" uid="uid://bctpe34ddamg5" path="res://components/knockback/CKnockback.tscn" id="10_jqqi6"]
@@ -42,6 +43,7 @@ size = Vector3(1, 2, 1.5)
collision_layer = 16 collision_layer = 16
collision_mask = 273 collision_mask = 273
script = ExtResource("1_r6506") script = ExtResource("1_r6506")
EnemyHeight = 2.0
RHealth = ExtResource("2_w4lm8") RHealth = ExtResource("2_w4lm8")
DeathEffects = Array[Object]([]) DeathEffects = Array[Object]([])
RDamage = ExtResource("2_bn56u") RDamage = ExtResource("2_bn56u")
@@ -53,6 +55,9 @@ script = ExtResource("2_gsmti")
RHealth = ExtResource("2_w4lm8") RHealth = ExtResource("2_w4lm8")
metadata/_custom_type_script = "uid://bjwrpv3jpsc1e" 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="."] [node name="CDamageable" type="Node" parent="."]
script = ExtResource("7_1tw73") script = ExtResource("7_1tw73")
DamageModifiers = Array[Object]([SubResource("Resource_qj0ob")]) DamageModifiers = Array[Object]([SubResource("Resource_qj0ob")])

View File

@@ -1,10 +1,11 @@
using Godot; using Godot;
using Movementtests.interfaces;
namespace Movementtests.systems; namespace Movementtests.systems;
public partial class DashSystem: Node3D 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")] [Export(PropertyHint.Range, "0,0.2,0.01,or_greater")]
@@ -13,9 +14,11 @@ public partial class DashSystem: Node3D
public float PostDashSpeed { get; set; } = 0f; public float PostDashSpeed { get; set; } = 0f;
public bool HasHit { get; set; } public bool HasHit { get; set; }
public bool CanDashThroughTarget { get; set; }
public Vector3 TargetLocation { get; set; } public Vector3 TargetLocation { get; set; }
public Vector3 CollisionPoint { get; set; } public Vector3 CollisionPoint { get; set; }
public Vector3 CollisionNormal { get; set; } public Vector3 CollisionNormal { get; set; }
public GodotObject CollidedObject { get; set; }
public Vector3 PlannedLocation { get; set; } public Vector3 PlannedLocation { get; set; }
public bool ShouldMantle { get; set; } public bool ShouldMantle { get; set; }
@@ -23,7 +26,7 @@ public partial class DashSystem: Node3D
public MantleSystem MantleSystem { get; set; } public MantleSystem MantleSystem { get; set; }
private HeadSystem _head; private HeadSystem _head;
private ShapeCast3D _dashCast3D; public ShapeCast3D DashCast3D;
private Camera3D _camera; private Camera3D _camera;
private Vector3 _dashDirection = Vector3.Zero; private Vector3 _dashDirection = Vector3.Zero;
@@ -51,8 +54,8 @@ public partial class DashSystem: Node3D
public void Init(HeadSystem head, Camera3D camera) public void Init(HeadSystem head, Camera3D camera)
{ {
_dashCast3D = GetNode<ShapeCast3D>("DashCast3D"); DashCast3D = GetNode<ShapeCast3D>("DashCast3D");
var dashShape = _dashCast3D.GetShape() as SphereShape3D; var dashShape = DashCast3D.GetShape() as SphereShape3D;
DashCastRadius = dashShape!.Radius; DashCastRadius = dashShape!.Radius;
_dashCastDrop = GetNode<ShapeCast3D>("DashCastDrop"); _dashCastDrop = GetNode<ShapeCast3D>("DashCastDrop");
@@ -75,30 +78,36 @@ public partial class DashSystem: Node3D
private DashLocation ComputeDashLocation() private DashLocation ComputeDashLocation()
{ {
var targetLocation = _dashCast3D.ToGlobal(_dashCast3D.TargetPosition); var targetLocation = DashCast3D.ToGlobal(DashCast3D.TargetPosition);
var hasHit = _dashCast3D.IsColliding(); var hasHit = DashCast3D.IsColliding();
if (!hasHit) if (!hasHit)
{ {
return new DashLocation(false, targetLocation, Vector3.Zero, Vector3.Zero); return new DashLocation(false, targetLocation, Vector3.Zero, Vector3.Zero);
} }
var collisionPoint = _dashCast3D.GetCollisionPoint(0); var collisionPoint = DashCast3D.GetCollisionPoint(0);
var collisionNormal = _dashCast3D.GetCollisionNormal(0); var collisionNormal = DashCast3D.GetCollisionNormal(0);
var collidedObject = DashCast3D.GetCollider(0);
var fraction = _dashCast3D.GetClosestCollisionSafeFraction(); var fraction = DashCast3D.GetClosestCollisionSafeFraction();
var globalSweepPath = targetLocation - _dashCast3D.GlobalPosition; var globalSweepPath = targetLocation - DashCast3D.GlobalPosition;
var locationAlongPath = _dashCast3D.GlobalPosition + globalSweepPath * fraction; var locationAlongPath = DashCast3D.GlobalPosition + globalSweepPath * fraction;
return new DashLocation(true, locationAlongPath, collisionPoint, collisionNormal); return new DashLocation(true, locationAlongPath, collisionPoint, collisionNormal, collidedObject);
} }
public void PrepareDash() public void PrepareDash()
{ {
_dashCast3D.SetRotation(_head.GetGlobalLookRotation()); 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.SetGlobalPosition(PlannedLocation);
MantleSystem.SetRotation(new Vector3( MantleSystem.SetRotation(new Vector3(
MantleSystem.Rotation.X, MantleSystem.Rotation.X,
@@ -115,6 +124,7 @@ public partial class DashSystem: Node3D
_dashTarget.SetVisible(true); _dashTarget.SetVisible(true);
var targetLocation = ShouldMantle ? MantleSystem.FirstMantleProfilePoint : PlannedLocation; var targetLocation = ShouldMantle ? MantleSystem.FirstMantleProfilePoint : PlannedLocation;
_dashTarget.SetGlobalPosition(targetLocation); _dashTarget.SetGlobalPosition(targetLocation);
return;
var shouldShowDropIndicator = !HasHit && !ShouldMantle; var shouldShowDropIndicator = !HasHit && !ShouldMantle;
_dashDropIndicator.SetVisible(shouldShowDropIndicator); _dashDropIndicator.SetVisible(shouldShowDropIndicator);
@@ -126,7 +136,7 @@ public partial class DashSystem: Node3D
// End of the drop is either max cast distance or first collision // End of the drop is either max cast distance or first collision
var hasDropLocationHit = _dashCastDrop.IsColliding(); 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 // Only show drop location indicator if drop cast has hit
_dashDropLocationIndicator.SetVisible(hasDropLocationHit); _dashDropLocationIndicator.SetVisible(hasDropLocationHit);
@@ -141,13 +151,9 @@ public partial class DashSystem: Node3D
public void StopPreparingDash() public void StopPreparingDash()
{ {
CanDashThroughTarget = false;
_dashTarget.SetVisible(false); _dashTarget.SetVisible(false);
_dashDropIndicator.SetVisible(false); _dashDropIndicator.SetVisible(false);
_dashDropLocationIndicator.SetVisible(false); _dashDropLocationIndicator.SetVisible(false);
} }
public void StartPreparingDash()
{
_dashTarget.SetVisible(true);
}
} }

View File

@@ -28,7 +28,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6, 0)
shape = SubResource("SphereShape3D_jngg2") shape = SubResource("SphereShape3D_jngg2")
target_position = Vector3(0, 0, -12) target_position = Vector3(0, 0, -12)
max_results = 1 max_results = 1
collision_mask = 256 collision_mask = 304
debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1) debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1)
[node name="DashCastDrop" type="ShapeCast3D" parent="."] [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") shape = SubResource("SphereShape3D_jngg2")
target_position = Vector3(0, 0, -50) target_position = Vector3(0, 0, -50)
max_results = 1 max_results = 1
collision_mask = 256 collision_mask = 304
debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1) debug_shape_custom_color = Color(0.911631, 0.11884, 0.656218, 1)
[node name="DashTarget" type="MeshInstance3D" parent="."] [node name="DashTarget" type="MeshInstance3D" parent="."]

View File

@@ -22,27 +22,23 @@ public partial class WeaponSystem : RigidBody3D
public StateChartState FlyingState; public StateChartState FlyingState;
public StateChartState PlantedState; public StateChartState PlantedState;
private Node3D _head;
private ShapeCast3D _dashCast3D; private ShapeCast3D _dashCast3D;
private Camera3D _camera;
private TweenQueueSystem _tweenQueueSystem; private TweenQueueSystem _tweenQueueSystem;
private Transform3D _startTransform; private Transform3D _startTransform;
private Transform3D _startMeshTransform; private Vector3 _startMeshRotation;
private Vector3 _throwDirection; private Vector3 _throwDirection;
public Vector3 PlantLocation { get; set; } public Vector3 PlantLocation { get; set; }
public Vector3 PlantNormal { get; set; } public Vector3 PlantNormal { get; set; }
public Node PlantObject { get; set; }
public MeshInstance3D WeaponLocationIndicator { get; set; } public MeshInstance3D WeaponLocationIndicator { get; set; }
public StandardMaterial3D WeaponLocationIndicatorMaterial { get; set; } public StandardMaterial3D WeaponLocationIndicatorMaterial { get; set; }
public MeshInstance3D WeaponMesh { 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")); _weaponState = StateChart.Of(GetNode("StateChart"));
InHandState = StateChartState.Of(GetNode("StateChart/Root/InHand")); InHandState = StateChartState.Of(GetNode("StateChart/Root/InHand"));
FlyingState = StateChartState.Of(GetNode("StateChart/Root/Flying")); FlyingState = StateChartState.Of(GetNode("StateChart/Root/Flying"));
@@ -53,7 +49,7 @@ public partial class WeaponSystem : RigidBody3D
WeaponLocationIndicatorMaterial = WeaponLocationIndicator.GetActiveMaterial(0) as StandardMaterial3D; WeaponLocationIndicatorMaterial = WeaponLocationIndicator.GetActiveMaterial(0) as StandardMaterial3D;
WeaponMesh = GetNode<MeshInstance3D>("Weapon"); WeaponMesh = GetNode<MeshInstance3D>("Weapon");
_startMeshTransform = WeaponMesh.Transform; _startMeshRotation = WeaponMesh.Rotation;
_tweenQueueSystem = GetNode<TweenQueueSystem>("TweenQueueSystem"); _tweenQueueSystem = GetNode<TweenQueueSystem>("TweenQueueSystem");
_tweenQueueSystem.Init(this); _tweenQueueSystem.Init(this);
@@ -90,7 +86,7 @@ public partial class WeaponSystem : RigidBody3D
PlantLocation = location; 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"); _weaponState.SendEvent("throw");
@@ -103,11 +99,21 @@ public partial class WeaponSystem : RigidBody3D
var tween = _tweenQueueSystem.TweenToLocation(new TweenQueueSystem.TweenInputs(end, StraightThrowDuration)); var tween = _tweenQueueSystem.TweenToLocation(new TweenQueueSystem.TweenInputs(end, StraightThrowDuration));
if (hasHit) if (hasHit)
{
PlantObject = collidedObject;
tween.Finished += PlantWeaponInWall; tween.Finished += PlantWeaponInWall;
}
else else
tween.Finished += ThrowWeaponOnCurve; tween.Finished += ThrowWeaponOnCurve;
} }
public void RethrowWeapon()
{
_weaponState.SendEvent("throw");
_throwDirection = Vector3.Up;
ThrowWeaponOnCurve();
}
public void ThrowWeaponOnCurve() public void ThrowWeaponOnCurve()
{ {
Freeze = false; Freeze = false;
@@ -118,16 +124,22 @@ public partial class WeaponSystem : RigidBody3D
{ {
_weaponState.SendEvent("plant"); _weaponState.SendEvent("plant");
// WeaponLocationIndicatorMaterial.StencilColor = new Color(1f, 0.2f, 0.2f);
Freeze = true; Freeze = true;
GlobalPosition = PlantLocation; WeaponMesh.Rotation = _startMeshRotation;
WeaponMesh.Transform = _startMeshTransform;
LookAt(GlobalTransform.Origin + PlantNormal, Vector3.Up, true); // WeaponLocationIndicatorMaterial.StencilColor = new Color(1f, 0.2f, 0.2f);
if (PlantObject is Node3D node)
{
GetTree().GetRoot().CallDeferred(Node.MethodName.RemoveChild, this);
node.CallDeferred(Node.MethodName.AddChild, this);
}
CallDeferred(Node3D.MethodName.SetGlobalPosition, PlantLocation);
CallDeferred(Node3D.MethodName.LookAt, GlobalTransform.Origin + PlantNormal, Vector3.Up, true);
} }
public void OnThrownWeaponReachesGround(Node other) public void OnThrownWeaponReachesGround(Node other)
{ {
PlantObject = other;
PlantWeaponInWall(); PlantWeaponInWall();
} }

View File

@@ -38,7 +38,7 @@ material = SubResource("StandardMaterial3D_m0v1h")
[node name="Weapon" type="RigidBody3D"] [node name="Weapon" type="RigidBody3D"]
collision_layer = 65536 collision_layer = 65536
collision_mask = 256 collision_mask = 304
continuous_cd = true continuous_cd = true
contact_monitor = true contact_monitor = true
max_contacts_reported = 1 max_contacts_reported = 1
@@ -54,6 +54,9 @@ shape = SubResource("CylinderShape3D_avini")
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0.8673003) transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 0, 0.8673003)
mesh = ExtResource("3_svc06") mesh = ExtResource("3_svc06")
[node name="WeaponLocationIndicator" type="MeshInstance3D" parent="."]
mesh = SubResource("SphereMesh_jpdh0")
[node name="StateChart" type="Node" parent="."] [node name="StateChart" type="Node" parent="."]
script = ExtResource("3_5owyf") script = ExtResource("3_5owyf")
metadata/_custom_type_script = "uid://couw105c3bde4" metadata/_custom_type_script = "uid://couw105c3bde4"
@@ -89,11 +92,14 @@ delay_in_seconds = "0.0"
[node name="Planted" type="Node" parent="StateChart/Root"] [node name="Planted" type="Node" parent="StateChart/Root"]
script = ExtResource("5_m0v1h") 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"] [node name="ToHand" type="Node" parent="StateChart/Root/Planted"]
script = ExtResource("6_jpdh0") script = ExtResource("6_jpdh0")
to = NodePath("../../InHand") to = NodePath("../../InHand")
event = &"recover" event = &"recover"
delay_in_seconds = "0.0" delay_in_seconds = "0.0"
[node name="WeaponLocationIndicator" type="MeshInstance3D" parent="."]
mesh = SubResource("SphereMesh_jpdh0")