diff --git a/Cirno.sln.DotSettings.user b/Cirno.sln.DotSettings.user
index 99e56389..30725965 100644
--- a/Cirno.sln.DotSettings.user
+++ b/Cirno.sln.DotSettings.user
@@ -1,2 +1,5 @@
- ForceIncluded
\ No newline at end of file
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
\ No newline at end of file
diff --git a/Scenes/Actors/Enemy_Base.tscn b/Scenes/Actors/Enemy_Base.tscn
new file mode 100644
index 00000000..3c7df8af
--- /dev/null
+++ b/Scenes/Actors/Enemy_Base.tscn
@@ -0,0 +1,84 @@
+[gd_scene load_steps=11 format=3 uid="uid://b2gnndqesf4kb"]
+
+[ext_resource type="Script" path="res://Scripts/Enemy.cs" id="1_h0ey4"]
+[ext_resource type="Texture2D" uid="uid://b4ynnb14mb4uq" path="res://Sprites/Reisen.png" id="2_ocghb"]
+[ext_resource type="PackedScene" uid="uid://crry0rgk7a8sm" path="res://Scenes/Weapons/BaseWeapon.tscn" id="3_ihce0"]
+[ext_resource type="Script" path="res://Scripts/Components/ProximityPlayerDetection.cs" id="3_udny0"]
+[ext_resource type="PackedScene" uid="uid://cuixq5ex0j40h" path="res://Scenes/enemyBullet.tscn" id="4_iis8b"]
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_2brqc"]
+atlas = ExtResource("2_ocghb")
+region = Rect2(0, 0, 8, 16)
+
+[sub_resource type="CircleShape2D" id="CircleShape2D_8gtts"]
+radius = 7.0
+
+[sub_resource type="CircleShape2D" id="CircleShape2D_cacb5"]
+radius = 4.0
+
+[sub_resource type="CircleShape2D" id="CircleShape2D_v711r"]
+radius = 85.0529
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_m1rsg"]
+size = Vector2(8, 12)
+
+[node name="Enemy" type="CharacterBody2D" node_paths=PackedStringArray("EquippedWeapon") groups=["Destroyable"]]
+collision_layer = 16
+collision_mask = 9
+script = ExtResource("1_h0ey4")
+EquippedWeapon = NodePath("Weapon")
+NavigationEnabled = true
+metadata/_edit_group_ = true
+
+[node name="Sprite2D" type="Sprite2D" parent="."]
+texture = SubResource("AtlasTexture_2brqc")
+
+[node name="Damage_HitBox" type="CollisionShape2D" parent="."]
+visible = false
+shape = SubResource("CircleShape2D_8gtts")
+
+[node name="RigidBody2D" type="RigidBody2D" parent="."]
+collision_layer = 16
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="RigidBody2D"]
+visible = false
+position = Vector2(0, 5)
+shape = SubResource("CircleShape2D_cacb5")
+
+[node name="PlayerDetection" type="Area2D" parent="."]
+visible = false
+collision_layer = 16
+collision_mask = 2
+script = ExtResource("3_udny0")
+
+[node name="PlayerDetectionArea" type="CollisionShape2D" parent="PlayerDetection"]
+shape = SubResource("CircleShape2D_v711r")
+
+[node name="ShootTimer" type="Timer" parent="."]
+wait_time = 0.4
+one_shot = true
+
+[node name="Weapon" parent="." instance=ExtResource("3_ihce0")]
+BulletScene = ExtResource("4_iis8b")
+BulletCapacity = 4
+BulletSpeed = 50.0
+
+[node name="NavigationAgent2D" type="NavigationAgent2D" parent="."]
+target_desired_distance = 64.0
+path_max_distance = 800.0
+path_postprocessing = 1
+avoidance_enabled = true
+debug_enabled = true
+debug_path_custom_color = Color(1, 0, 0, 1)
+
+[node name="DamageHitbox" type="Area2D" parent="."]
+collision_layer = 16
+collision_mask = 9
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="DamageHitbox"]
+shape = SubResource("RectangleShape2D_m1rsg")
+
+[connection signal="area_entered" from="PlayerDetection" to="PlayerDetection" method="_on_area_entered"]
+[connection signal="area_exited" from="PlayerDetection" to="." method="_on_area_exited"]
+[connection signal="velocity_computed" from="NavigationAgent2D" to="." method="_on_navigation_agent_2d_velocity_computed"]
+[connection signal="area_entered" from="DamageHitbox" to="." method="_on_damage_hitbox_area_entered"]
diff --git a/Scenes/Enemy.tscn b/Scenes/Enemy.tscn
index 2bf0e438..d51de564 100644
--- a/Scenes/Enemy.tscn
+++ b/Scenes/Enemy.tscn
@@ -1,8 +1,9 @@
-[gd_scene load_steps=10 format=3 uid="uid://v8s3kubgb2qg"]
+[gd_scene load_steps=11 format=3 uid="uid://v8s3kubgb2qg"]
[ext_resource type="Texture2D" uid="uid://b4ynnb14mb4uq" path="res://Sprites/Reisen.png" id="1_4w8mj"]
[ext_resource type="Script" path="res://Scripts/Enemy.cs" id="1_lpwdj"]
[ext_resource type="PackedScene" uid="uid://cuixq5ex0j40h" path="res://Scenes/enemyBullet.tscn" id="2_ogldd"]
+[ext_resource type="Script" path="res://Scripts/Components/ProximityPlayerDetection.cs" id="3_1nqn5"]
[ext_resource type="PackedScene" uid="uid://crry0rgk7a8sm" path="res://Scenes/Weapons/BaseWeapon.tscn" id="4_2k1dv"]
[sub_resource type="AtlasTexture" id="AtlasTexture_2brqc"]
@@ -21,11 +22,12 @@ radius = 85.0529
[sub_resource type="RectangleShape2D" id="RectangleShape2D_m1rsg"]
size = Vector2(8, 12)
-[node name="Enemy" type="CharacterBody2D" node_paths=PackedStringArray("EquippedWeapon") groups=["Destroyable"]]
+[node name="Enemy" type="CharacterBody2D" node_paths=PackedStringArray("EquippedWeapon", "_playerDetection") groups=["Destroyable"]]
collision_layer = 16
collision_mask = 9
script = ExtResource("1_lpwdj")
EquippedWeapon = NodePath("Weapon")
+_playerDetection = NodePath("PlayerDetection")
NavigationEnabled = true
metadata/_edit_group_ = true
@@ -48,6 +50,7 @@ shape = SubResource("CircleShape2D_cacb5")
visible = false
collision_layer = 16
collision_mask = 2
+script = ExtResource("3_1nqn5")
[node name="PlayerDetectionArea" type="CollisionShape2D" parent="PlayerDetection"]
shape = SubResource("CircleShape2D_v711r")
@@ -76,7 +79,7 @@ collision_mask = 9
[node name="CollisionShape2D" type="CollisionShape2D" parent="DamageHitbox"]
shape = SubResource("RectangleShape2D_m1rsg")
-[connection signal="area_entered" from="PlayerDetection" to="." method="_on_player_detection_area_entered"]
-[connection signal="area_exited" from="PlayerDetection" to="." method="_on_player_detection_area_exited"]
+[connection signal="area_entered" from="PlayerDetection" to="PlayerDetection" method="_on_area_entered"]
+[connection signal="area_exited" from="PlayerDetection" to="PlayerDetection" method="_on_area_exited"]
[connection signal="velocity_computed" from="NavigationAgent2D" to="." method="_on_navigation_agent_2d_velocity_computed"]
[connection signal="area_entered" from="DamageHitbox" to="." method="_on_damage_hitbox_area_entered"]
diff --git a/Scenes/HUD/HUD.tscn b/Scenes/HUD/HUD.tscn
index dd7e4d00..5e6cb120 100644
--- a/Scenes/HUD/HUD.tscn
+++ b/Scenes/HUD/HUD.tscn
@@ -26,8 +26,10 @@ animations = [{
"speed": 5.0
}]
-[node name="HUD" type="CanvasLayer"]
+[node name="HUD" type="CanvasLayer" node_paths=PackedStringArray("_healthLabel", "_itemsContainer")]
script = ExtResource("1_m0hb0")
+_healthLabel = NodePath("VBoxContainer/HealthLabel")
+_itemsContainer = NodePath("VBoxContainer/ItemsContainer")
[node name="GameOver" type="Label" parent="."]
visible = false
diff --git a/Scenes/player.tscn b/Scenes/player.tscn
index 78c2f6dc..b8973852 100644
--- a/Scenes/player.tscn
+++ b/Scenes/player.tscn
@@ -185,6 +185,7 @@ animation = &"walk_left"
z_index = 100
[node name="HitboxSprite" type="Sprite2D" parent="Smoothing2D"]
+visible = false
texture = ExtResource("7_msn8i")
[node name="InteractionController" type="Area2D" parent="."]
diff --git a/Scripts/Components/PlayerDetection.cs b/Scripts/Components/PlayerDetection.cs
new file mode 100644
index 00000000..912f1c22
--- /dev/null
+++ b/Scripts/Components/PlayerDetection.cs
@@ -0,0 +1,17 @@
+using Godot;
+using Godot.Collections;
+
+namespace Cirno.Scripts.Components;
+
+public partial class PlayerDetection : Area2D
+{
+ public InteractionController CachedPlayer => _cachedPlayer;
+
+ protected InteractionController _cachedPlayer;
+ public virtual bool IsPlayerInRange { get; set; }
+
+ public virtual bool IsPlayerInSight(uint collisionMask)
+ {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Components/ProximityPlayerDetection.cs b/Scripts/Components/ProximityPlayerDetection.cs
new file mode 100644
index 00000000..1958daea
--- /dev/null
+++ b/Scripts/Components/ProximityPlayerDetection.cs
@@ -0,0 +1,45 @@
+using System.Diagnostics;
+using Godot;
+using Godot.Collections;
+
+namespace Cirno.Scripts.Components;
+
+public partial class ProximityPlayerDetection : PlayerDetection
+{
+ public override bool IsPlayerInRange { get; set; }
+
+ public override bool IsPlayerInSight(uint collisionMask)
+ {
+ if (_cachedPlayer == null) return false;
+
+ var spaceState = GetWorld2D().DirectSpaceState;
+
+ // I have no idea why I need to use the parent's collision mask instead of the local one but it doesn't detect the player otherwise
+
+ var query = PhysicsRayQueryParameters2D.Create(this.GlobalPosition, _cachedPlayer.GlobalPosition, collisionMask, new Array { GetRid() });
+
+ // var query = PhysicsRayQueryParameters2D.Create(this.GlobalPosition, _cachedPlayer.GlobalPosition, CollisionMask, new Array { GetRid() });
+ var result = spaceState.IntersectRay(query);
+
+ // If count is 0 then the player is in sight, otherwise there is level geometry in the way
+ return result.Count == 0;
+ }
+
+ private void _on_area_entered(Area2D area)
+ {
+ // Assume area is player for now
+ if (area is not InteractionController player) return;
+
+ Debug.WriteLine("Enemy detection area Entered by interaction controller");
+
+ _cachedPlayer = player;
+
+ IsPlayerInRange = true;
+ }
+
+ private void _on_area_exited(Area2D area)
+ {
+ if (area is not InteractionController player) return;
+ IsPlayerInRange = false;
+ }
+}
\ No newline at end of file
diff --git a/Scripts/Enemy.cs b/Scripts/Enemy.cs
index 1ccf6c68..9c9aed05 100644
--- a/Scripts/Enemy.cs
+++ b/Scripts/Enemy.cs
@@ -2,6 +2,8 @@ using Cirno.Scripts;
using Godot;
using System;
using System.Diagnostics;
+using Cirno.Scripts.Components;
+using Godot.Collections;
public partial class Enemy : CharacterBody2D
{
@@ -21,10 +23,13 @@ public partial class Enemy : CharacterBody2D
private bool _isDestroyed = false;
private NavigationAgent2D _navigationAgent;
-
- private bool _isPlayerInRange = false;
-
+
+ private bool IsPlayerInRange => _playerDetection is { IsPlayerInRange: true };
+
private Vector2? _lastPlayerPosition = null;
+
+ [Export]
+ private PlayerDetection _playerDetection;
[Export] public bool NavigationEnabled { get; set; } = false;
@@ -35,6 +40,10 @@ public partial class Enemy : CharacterBody2D
_navigationAgent = GetNode("NavigationAgent2D");
+ //var asdf = GetNode("PlayerDetection");
+
+ //_playerDetection = GetNode("PlayerDetection");
+
//CallDeferred("Setup");
}
@@ -67,15 +76,19 @@ public partial class Enemy : CharacterBody2D
switch (_currentState)
{
case EnemyState.Idle:
- HandlePlayerDetection();
+ if (_playerDetection != null && _playerDetection.IsPlayerInSight(CollisionMask))
+ {
+ _currentState = EnemyState.Alert;
+ }
+ //HandlePlayerDetection();
break;
case EnemyState.Alert:
// Update last known player position if it's in range
- if (_isPlayerInRange)
+ if (IsPlayerInRange)
{
- _lastPlayerPosition = _cachedPlayer.GlobalPosition;
+ _lastPlayerPosition = _playerDetection.CachedPlayer.GlobalPosition;
}
if (_lastPlayerPosition.HasValue)
@@ -127,25 +140,25 @@ public partial class Enemy : CharacterBody2D
}
- private void HandlePlayerDetection()
- {
- if (_cachedPlayer == null)
- {
- return;
- }
-
- if (IsPlayerInSight())
- {
- // Update player position only if player is in sight
- // if (NavigationEnabled)
- // {
- // _navigationAgent.SetTargetPosition(_cachedPlayer.GlobalPosition);
- // }
- //Shoot();
-
- _currentState = EnemyState.Alert;
- }
- }
+ // private void HandlePlayerDetection()
+ // {
+ // if (_cachedPlayer == null)
+ // {
+ // return;
+ // }
+ //
+ // if (IsPlayerInSight())
+ // {
+ // // Update player position only if player is in sight
+ // // if (NavigationEnabled)
+ // // {
+ // // _navigationAgent.SetTargetPosition(_cachedPlayer.GlobalPosition);
+ // // }
+ // //Shoot();
+ //
+ // _currentState = EnemyState.Alert;
+ // }
+ // }
private void Shoot()
{
@@ -178,45 +191,45 @@ public partial class Enemy : CharacterBody2D
// }
}
- private bool IsPlayerInSight()
- {
- var spaceState = GetWorld2D().DirectSpaceState;
- var query = PhysicsRayQueryParameters2D.Create(this.GlobalPosition, _cachedPlayer.GlobalPosition, CollisionMask, new Godot.Collections.Array { GetRid() });
- var result = spaceState.IntersectRay(query);
+ // private bool IsPlayerInSight()
+ // {
+ // var spaceState = GetWorld2D().DirectSpaceState;
+ // var query = PhysicsRayQueryParameters2D.Create(this.GlobalPosition, _cachedPlayer.GlobalPosition, CollisionMask, new Godot.Collections.Array { GetRid() });
+ // var result = spaceState.IntersectRay(query);
+ //
+ // // If count is 0 then the player is in sight, otherwise there is level geometry in the way
+ // return result.Count == 0;
+ //
+ // // if (result.Count > 0)
+ // // GD.Print("Hit at point: ", result["position"]);
+ // }
- // If count is 0 then the player is in sight, otherwise there is level geometry in the way
- return result.Count == 0;
-
- // if (result.Count > 0)
- // GD.Print("Hit at point: ", result["position"]);
- }
-
- private void _on_player_detection_area_entered(Area2D area)
- {
- // Assume area is player for now
- if (area is InteractionController player)
- {
- Debug.WriteLine("Enemy detection area Entered by interaction controller");
-
- _cachedPlayer = player;
-
- _isPlayerInRange = true;
- // if (_currentState is EnemyState.Idle)
- // {
- // _currentState = EnemyState.Primed;
- // }
- }
- }
-
- private void _on_player_detection_area_exited(Area2D area)
- {
- _isPlayerInRange = false;
-
- // if (_currentState is EnemyState.Primed)
- // {
- // _currentState = EnemyState.Idle;
- // }
- }
+ // private void _on_player_detection_area_entered(Area2D area)
+ // {
+ // // Assume area is player for now
+ // if (area is InteractionController player)
+ // {
+ // Debug.WriteLine("Enemy detection area Entered by interaction controller");
+ //
+ // _cachedPlayer = player;
+ //
+ // _isPlayerInRange = true;
+ // // if (_currentState is EnemyState.Idle)
+ // // {
+ // // _currentState = EnemyState.Primed;
+ // // }
+ // }
+ // }
+ //
+ // private void _on_player_detection_area_exited(Area2D area)
+ // {
+ // _isPlayerInRange = false;
+ //
+ // // if (_currentState is EnemyState.Primed)
+ // // {
+ // // _currentState = EnemyState.Idle;
+ // // }
+ // }
private void _on_damage_hitbox_area_entered(Area2D area)
{