Fix spawn point for player, add flee behavior for gold sproingy

This commit is contained in:
2025-10-29 11:03:07 -07:00
parent 21d8c4770d
commit 575a565a2c
13 changed files with 176 additions and 7 deletions

View File

@@ -1,4 +1,4 @@
<Project Sdk="Godot.NET.Sdk/4.4.1">
<Project Sdk="Godot.NET.Sdk/4.4.0">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>

View File

@@ -0,0 +1,38 @@
<Project Sdk="Godot.NET.Sdk/4.4.1">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
<WarningsAsErrors>CS9057</WarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Chickensoft.AutoInject" Version="2.5.0" />
<PackageReference Include="Chickensoft.GodotNodeInterfaces" Version="2.4.0" />
<PackageReference Include="Chickensoft.Introspection" Version="2.2.0" />
<PackageReference Include="Chickensoft.Introspection.Generator" Version="2.2.0" />
<PackageReference Include="Chickensoft.LogicBlocks" Version="5.16.0" />
<PackageReference Include="Chickensoft.LogicBlocks.DiagramGenerator" Version="5.16.0" />
<PackageReference Include="Chickensoft.SaveFileBuilder" Version="1.1.0" />
<PackageReference Include="Chickensoft.Serialization.Godot" Version="0.7.6" />
<PackageReference Include="GodotSharp.SourceGenerators" Version="2.6.0-250131-2115.Release" />
<PackageReference Include="SimpleInjector" Version="5.5.0" />
<PackageReference Include="SSH.NET" Version="2024.2.0" />
<PackageReference Include="System.IO.Abstractions" Version="22.0.11" />
<PackageReference Include="Zeroconf" Version="3.7.16" />
</ItemGroup>
<ItemGroup>
<None Include=".editorconfig" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Zennysoft.Game.Godot.Implementation\Zennysoft.Game.Implementation.csproj" />
<ProjectReference Include="..\Zennysoft.Game.Ma.Implementation\Zennysoft.Ma.Adapter.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="Godot.SourceGenerators" Version="4.4.0-dev.2" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="GodotSharp" Version="4.4.0-dev.2" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="GodotSharpEditor" Version="4.4.0-dev.2" />
</ItemGroup>
</Project>

View File

@@ -79,6 +79,8 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
if (this is IHaveFollowBehavior)
_enemyLogic.Input(new EnemyLogic.Input.Follow());
if (this is IHaveFleeBehavior)
_enemyLogic.Input(new EnemyLogic.Input.Flee());
}
})
.Handle((in EnemyLogic.Output.Idle _) =>

View File

@@ -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<IGame>();
[Dependency] public IMap _map => this.DependOn<IMap>();
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<MonsterRoom>(rooms.OfType<MonsterRoom>());
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);
}
}

View File

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

View File

@@ -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

View File

@@ -0,0 +1,10 @@
using Godot;
namespace Zennysoft.Game.Ma;
public interface IHaveFleeBehavior
{
public FleeBehavior FleeBehavior { get; }
public NavigationAgent3D NavigationAgent { get; }
}

View File

@@ -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());

View File

@@ -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

View File

@@ -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;

View File

@@ -13,6 +13,7 @@ public partial class EnemyLogic
IGet<Move>,
IGet<Patrol>,
IGet<Follow>,
IGet<Flee>,
IGet<ReachedPlayer>,
IGet<Input.LoseTrackOfTarget>,
IGet<Input.Defeated>
@@ -27,6 +28,8 @@ public partial class EnemyLogic
public Transition On(in Follow _) => To<FollowPlayer>();
public Transition On(in Flee _) => To<FleePlayer>();
public Transition On(in LoseTrackOfTarget input)
{
Output(new Output.ReturnToDefaultState());

View File

@@ -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<IEnemy>();
if (enemy is IHaveFleeBehavior fleeEnemy)
{
fleeEnemy.FleeBehavior.StartFlee(fleeEnemy.NavigationAgent);
Output(new Output.Move());
}
});
OnDetach(() =>
{
var enemy = Get<IEnemy>();
if (enemy is IHaveFleeBehavior fleeEnemy)
{
fleeEnemy.FleeBehavior.StopFlee();
}
});
}
}
}
}

View File

@@ -134,6 +134,7 @@ public partial class Game : Node3D, IGame
_instantiator = new Instantiator(GetTree());
_player = _instantiator.LoadAndInstantiate<Player>("res://src/player/Player.tscn");
_map = _instantiator.LoadAndInstantiate<Map>("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)));