From 575a565a2cf9695415daa2af160bff0a5f9615f4 Mon Sep 17 00:00:00 2001 From: Zenny Date: Wed, 29 Oct 2025 11:03:07 -0700 Subject: [PATCH] Fix spawn point for player, add flee behavior for gold sproingy --- Zennysoft.Game.Ma/Ma.csproj | 2 +- Zennysoft.Game.Ma/Ma.csproj.old.3 | 38 ++++++++++++ Zennysoft.Game.Ma/src/enemy/Enemy.cs | 2 + .../src/enemy/behaviors/FleeBehavior.cs | 58 +++++++++++++++++++ .../src/enemy/behaviors/FleeBehavior.cs.uid | 1 + .../src/enemy/behaviors/FleeBehavior.tscn | 7 +++ .../src/enemy/behaviors/IHaveFleeBehavior.cs | 10 ++++ .../13. gold sproingy/GoldSproingy.cs | 16 ++++- .../13. gold sproingy/GoldSproingy.tscn | 6 +- .../src/enemy/state/EnemyLogic.Input.cs | 2 + .../state/states/EnemyLogic.State.Alive.cs | 3 + .../state/states/EnemyLogic.State.Flee.cs | 35 +++++++++++ Zennysoft.Game.Ma/src/game/Game.cs | 3 +- 13 files changed, 176 insertions(+), 7 deletions(-) create mode 100644 Zennysoft.Game.Ma/Ma.csproj.old.3 create mode 100644 Zennysoft.Game.Ma/src/enemy/behaviors/FleeBehavior.cs create mode 100644 Zennysoft.Game.Ma/src/enemy/behaviors/FleeBehavior.cs.uid create mode 100644 Zennysoft.Game.Ma/src/enemy/behaviors/FleeBehavior.tscn create mode 100644 Zennysoft.Game.Ma/src/enemy/behaviors/IHaveFleeBehavior.cs create mode 100644 Zennysoft.Game.Ma/src/enemy/state/states/EnemyLogic.State.Flee.cs diff --git a/Zennysoft.Game.Ma/Ma.csproj b/Zennysoft.Game.Ma/Ma.csproj index 0ca2470c..853d610d 100644 --- a/Zennysoft.Game.Ma/Ma.csproj +++ b/Zennysoft.Game.Ma/Ma.csproj @@ -1,4 +1,4 @@ - + net8.0 true diff --git a/Zennysoft.Game.Ma/Ma.csproj.old.3 b/Zennysoft.Game.Ma/Ma.csproj.old.3 new file mode 100644 index 00000000..0ca2470c --- /dev/null +++ b/Zennysoft.Game.Ma/Ma.csproj.old.3 @@ -0,0 +1,38 @@ + + + net8.0 + true + CS9057 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Zennysoft.Game.Ma/src/enemy/Enemy.cs b/Zennysoft.Game.Ma/src/enemy/Enemy.cs index b6c66464..bdddee91 100644 --- a/Zennysoft.Game.Ma/src/enemy/Enemy.cs +++ b/Zennysoft.Game.Ma/src/enemy/Enemy.cs @@ -79,6 +79,8 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide diff --git a/Zennysoft.Game.Ma/src/enemy/behaviors/FleeBehavior.cs b/Zennysoft.Game.Ma/src/enemy/behaviors/FleeBehavior.cs new file mode 100644 index 00000000..33cda195 --- /dev/null +++ b/Zennysoft.Game.Ma/src/enemy/behaviors/FleeBehavior.cs @@ -0,0 +1,58 @@ +using Chickensoft.AutoInject; +using Chickensoft.Introspection; +using Godot; +using System.Linq; +using Zennysoft.Game.Abstractions.Entity; + +namespace Zennysoft.Game.Ma; + +[Meta(typeof(IAutoNode))] +public partial class FleeBehavior : Node3D, IBehavior +{ + public override void _Notification(int what) => this.Notify(what); + + [Export] private double _fleeSpeed { get; set; } = 300f; + + [Export] private double _thinkTime { get; set; } = 2f; + + [Signal] public delegate void OnVelocityComputedEventHandler(Vector3 safeVelocity); + + [Dependency] public IGame _game => this.DependOn(); + [Dependency] public IMap _map => this.DependOn(); + + private NavigationAgent3D _navigationAgent; + + + public void Init(NavigationAgent3D navigationAgent) + { + _navigationAgent = navigationAgent; + } + + public void OnReady() + { + SetPhysicsProcess(false); + } + + public void StartFlee(NavigationAgent3D navigationAgent) + { + var currentRoom = _map.GetPlayersCurrentRoom(); + var rooms = _game.CurrentFloor.Rooms; + var validRooms = new Godot.Collections.Array(rooms.OfType()); + var randomRoom = validRooms.PickRandom(); + _navigationAgent.TargetPosition = randomRoom.PlayerSpawn.GlobalPosition; + SetPhysicsProcess(true); + } + + public void StopFlee() + { + SetPhysicsProcess(false); + } + + public void OnPhysicsProcess(double delta) + { + var nextVelocity = _navigationAgent.GetNextPathPosition(); + var parent = GetParent() as Node3D; + var velocity = parent.GlobalPosition.DirectionTo(nextVelocity) * (float)_fleeSpeed * (float)delta; + EmitSignal(SignalName.OnVelocityComputed, velocity); + } +} diff --git a/Zennysoft.Game.Ma/src/enemy/behaviors/FleeBehavior.cs.uid b/Zennysoft.Game.Ma/src/enemy/behaviors/FleeBehavior.cs.uid new file mode 100644 index 00000000..5ab5f073 --- /dev/null +++ b/Zennysoft.Game.Ma/src/enemy/behaviors/FleeBehavior.cs.uid @@ -0,0 +1 @@ +uid://drur3hx4p4du4 diff --git a/Zennysoft.Game.Ma/src/enemy/behaviors/FleeBehavior.tscn b/Zennysoft.Game.Ma/src/enemy/behaviors/FleeBehavior.tscn new file mode 100644 index 00000000..58692773 --- /dev/null +++ b/Zennysoft.Game.Ma/src/enemy/behaviors/FleeBehavior.tscn @@ -0,0 +1,7 @@ +[gd_scene load_steps=2 format=3 uid="uid://g4cupevu280j"] + +[ext_resource type="Script" uid="uid://drur3hx4p4du4" path="res://src/enemy/behaviors/FleeBehavior.cs" id="1_cty3c"] + +[node name="NavigationAgent" type="Node3D"] +script = ExtResource("1_cty3c") +_thinkTime = 0.8 diff --git a/Zennysoft.Game.Ma/src/enemy/behaviors/IHaveFleeBehavior.cs b/Zennysoft.Game.Ma/src/enemy/behaviors/IHaveFleeBehavior.cs new file mode 100644 index 00000000..8406ac3e --- /dev/null +++ b/Zennysoft.Game.Ma/src/enemy/behaviors/IHaveFleeBehavior.cs @@ -0,0 +1,10 @@ +using Godot; + +namespace Zennysoft.Game.Ma; + +public interface IHaveFleeBehavior +{ + public FleeBehavior FleeBehavior { get; } + + public NavigationAgent3D NavigationAgent { get; } +} diff --git a/Zennysoft.Game.Ma/src/enemy/enemy_types/13. gold sproingy/GoldSproingy.cs b/Zennysoft.Game.Ma/src/enemy/enemy_types/13. gold sproingy/GoldSproingy.cs index 409def64..33e722f9 100644 --- a/Zennysoft.Game.Ma/src/enemy/enemy_types/13. gold sproingy/GoldSproingy.cs +++ b/Zennysoft.Game.Ma/src/enemy/enemy_types/13. gold sproingy/GoldSproingy.cs @@ -1,28 +1,38 @@ using Chickensoft.AutoInject; using Chickensoft.Introspection; using Godot; +using System; using Zennysoft.Game.Ma; +using Zennysoft.Ma.Adapter; [Meta(typeof(IAutoNode))] -public partial class GoldSproingy : Enemy2D, IHavePatrolBehavior +public partial class GoldSproingy : Enemy2D, IHavePatrolBehavior, IHaveFleeBehavior { public override void _Notification(int what) => this.Notify(what); [Node] public NavigationAgent3D NavigationAgent { get; set; } [Node] public PatrolBehavior PatrolBehavior { get; set; } = default!; + [Node] public FleeBehavior FleeBehavior { get; set; } = default!; [Node] public Area3D PlayerDetector { get; set; } = default!; public void OnReady() { PatrolBehavior.Init(NavigationAgent); + FleeBehavior.Init(NavigationAgent); PatrolBehavior.HomePosition = GlobalPosition; PatrolBehavior.OnVelocityComputed += OnVelocityComputed; - PlayerDetector.BodyEntered += PlayerDetector_BodyEntered; - PlayerDetector.BodyExited += PlayerDetector_BodyExited; + FleeBehavior.OnVelocityComputed += OnVelocityComputed; + PlayerDetector.BodyEntered += GoldSproingyFlee; SetPhysicsProcess(true); } + private void GoldSproingyFlee(Node3D body) + { + if (body is IPlayer) + _enemyLogic.Input(new EnemyLogic.Input.Flee()); + } + public void OnResolved() { _enemyLogic.Input(new EnemyLogic.Input.Patrol()); diff --git a/Zennysoft.Game.Ma/src/enemy/enemy_types/13. gold sproingy/GoldSproingy.tscn b/Zennysoft.Game.Ma/src/enemy/enemy_types/13. gold sproingy/GoldSproingy.tscn index 84cc11ca..a2258be0 100644 --- a/Zennysoft.Game.Ma/src/enemy/enemy_types/13. gold sproingy/GoldSproingy.tscn +++ b/Zennysoft.Game.Ma/src/enemy/enemy_types/13. gold sproingy/GoldSproingy.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=10 format=3 uid="uid://c5ugpasira53m"] +[gd_scene load_steps=11 format=3 uid="uid://c5ugpasira53m"] [ext_resource type="Script" uid="uid://jjulhqd5g3be" path="res://src/enemy/enemy_types/13. gold sproingy/GoldSproingy.cs" id="1_o1o4d"] [ext_resource type="PackedScene" uid="uid://dobiqowi8mhfi" path="res://src/enemy/enemy_types/13. gold sproingy/GoldSproingyModelView.tscn" id="2_o1o4d"] [ext_resource type="PackedScene" uid="uid://2nkvacxsd46b" path="res://src/enemy/behaviors/PatrolBehavior.tscn" id="3_dxqkk"] +[ext_resource type="PackedScene" uid="uid://g4cupevu280j" path="res://src/enemy/behaviors/FleeBehavior.tscn" id="4_58d4o"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_cwfph"] radius = 0.106078 @@ -86,6 +87,9 @@ unique_name_in_owner = true [node name="PatrolBehavior" parent="Components" instance=ExtResource("3_dxqkk")] unique_name_in_owner = true +[node name="FleeBehavior" parent="Components" instance=ExtResource("4_58d4o")] +unique_name_in_owner = true + [node name="NavigationAgent" type="NavigationAgent3D" parent="Components"] unique_name_in_owner = true avoidance_enabled = true diff --git a/Zennysoft.Game.Ma/src/enemy/state/EnemyLogic.Input.cs b/Zennysoft.Game.Ma/src/enemy/state/EnemyLogic.Input.cs index 6fbf81b8..df9a60f0 100644 --- a/Zennysoft.Game.Ma/src/enemy/state/EnemyLogic.Input.cs +++ b/Zennysoft.Game.Ma/src/enemy/state/EnemyLogic.Input.cs @@ -15,6 +15,8 @@ public partial class EnemyLogic public readonly record struct Patrol; + public readonly record struct Flee; + public readonly record struct Follow; public readonly record struct Move; diff --git a/Zennysoft.Game.Ma/src/enemy/state/states/EnemyLogic.State.Alive.cs b/Zennysoft.Game.Ma/src/enemy/state/states/EnemyLogic.State.Alive.cs index 4e7252d9..a13f6fa5 100644 --- a/Zennysoft.Game.Ma/src/enemy/state/states/EnemyLogic.State.Alive.cs +++ b/Zennysoft.Game.Ma/src/enemy/state/states/EnemyLogic.State.Alive.cs @@ -13,6 +13,7 @@ public partial class EnemyLogic IGet, IGet, IGet, + IGet, IGet, IGet, IGet @@ -27,6 +28,8 @@ public partial class EnemyLogic public Transition On(in Follow _) => To(); + public Transition On(in Flee _) => To(); + public Transition On(in LoseTrackOfTarget input) { Output(new Output.ReturnToDefaultState()); diff --git a/Zennysoft.Game.Ma/src/enemy/state/states/EnemyLogic.State.Flee.cs b/Zennysoft.Game.Ma/src/enemy/state/states/EnemyLogic.State.Flee.cs new file mode 100644 index 00000000..35e5226f --- /dev/null +++ b/Zennysoft.Game.Ma/src/enemy/state/states/EnemyLogic.State.Flee.cs @@ -0,0 +1,35 @@ +using Chickensoft.Introspection; +using Zennysoft.Ma.Adapter.Entity; + +namespace Zennysoft.Game.Ma; + +public partial class EnemyLogic +{ + public partial record State + { + [Meta, Id("enemy_logic_state_fleeplayer")] + public partial record FleePlayer : Alive + { + public FleePlayer() + { + OnAttach(() => + { + var enemy = Get(); + if (enemy is IHaveFleeBehavior fleeEnemy) + { + fleeEnemy.FleeBehavior.StartFlee(fleeEnemy.NavigationAgent); + Output(new Output.Move()); + } + }); + OnDetach(() => + { + var enemy = Get(); + if (enemy is IHaveFleeBehavior fleeEnemy) + { + fleeEnemy.FleeBehavior.StopFlee(); + } + }); + } + } + } +} diff --git a/Zennysoft.Game.Ma/src/game/Game.cs b/Zennysoft.Game.Ma/src/game/Game.cs index 83c72b9c..59a0ada1 100644 --- a/Zennysoft.Game.Ma/src/game/Game.cs +++ b/Zennysoft.Game.Ma/src/game/Game.cs @@ -134,6 +134,7 @@ public partial class Game : Node3D, IGame _instantiator = new Instantiator(GetTree()); _player = _instantiator.LoadAndInstantiate("res://src/player/Player.tscn"); _map = _instantiator.LoadAndInstantiate("res://src/map/Map.tscn"); + _map.SpawnPointCreated += MovePlayer; PauseContainer.AddChild((Player)_player); PauseContainer.AddChild((Map)_map); } @@ -167,8 +168,6 @@ public partial class Game : Node3D, IGame GameRepo.IsPaused.Sync += IsPaused_Sync; InGameUI.PlayerInfoUI.Activate(); - - _map.SpawnPointCreated += MovePlayer; } public void LoadExistingGame() => SaveFile.Load().ContinueWith((_) => CallDeferred(nameof(FinishedLoadingSaveFile)));