Fix standard enemy logic

This commit is contained in:
2025-10-27 19:41:03 -07:00
parent 2d55ae9cc4
commit eed50bc04e
18 changed files with 106 additions and 88 deletions

View File

@@ -65,18 +65,19 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
_enemyLogic.Set(_player); _enemyLogic.Set(_player);
SetPhysicsProcess(true); SetPhysicsProcess(true);
EnemyModelView.HitPlayer += EnemyModelView_HitPlayer; EnemyModelView.HitPlayer += EnemyModelView_HitPlayer;
}
public void OnResolved()
{
EnemyBinding = _enemyLogic.Bind(); EnemyBinding = _enemyLogic.Bind();
EnemyBinding EnemyBinding
.Handle((in EnemyLogic.Output.Activate _) => .Handle((in EnemyLogic.Output.Activate _) =>
{ {
if (!_activated) if (!_activated)
{
Activate(); Activate();
_activated = true; _activated = true;
if (this is IHaveFollowBehavior)
_enemyLogic.Input(new EnemyLogic.Input.Follow());
}
}) })
.Handle((in EnemyLogic.Output.Idle _) => .Handle((in EnemyLogic.Output.Idle _) =>
{ {
@@ -99,7 +100,6 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
public virtual void Activate() public virtual void Activate()
{ {
} }
public virtual void Idle() public virtual void Idle()
@@ -114,7 +114,7 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
public virtual void PerformAction() public virtual void PerformAction()
{ {
PerformAction(); EnemyModelView.PlayPrimaryAttackAnimation();
} }
public virtual void ReturnToDefaultState() public virtual void ReturnToDefaultState()

View File

@@ -25,12 +25,16 @@ public partial class Sproingy : Enemy2D, IHavePatrolBehavior, IHaveEngagePlayerB
FollowBehavior.OnVelocityComputed += OnVelocityComputed; FollowBehavior.OnVelocityComputed += OnVelocityComputed;
EngagePlayerBehavior.TakeAction += EngagePlayerBehavior_TakeAction; EngagePlayerBehavior.TakeAction += EngagePlayerBehavior_TakeAction;
EngagePlayerBehavior.AcquireTarget += EngagePlayerBehavior_AcquireTarget; EngagePlayerBehavior.AcquireTarget += EngagePlayerBehavior_AcquireTarget;
_enemyLogic.Input(new EnemyLogic.Input.Patrol());
PlayerDetector.BodyEntered += PlayerDetector_BodyEntered; PlayerDetector.BodyEntered += PlayerDetector_BodyEntered;
PlayerDetector.BodyExited += PlayerDetector_BodyExited; PlayerDetector.BodyExited += PlayerDetector_BodyExited;
SetPhysicsProcess(true); SetPhysicsProcess(true);
} }
public void OnResolved()
{
_enemyLogic.Input(new EnemyLogic.Input.Patrol());
}
public override void _ExitTree() public override void _ExitTree()
{ {
PatrolBehavior.OnVelocityComputed -= OnVelocityComputed; PatrolBehavior.OnVelocityComputed -= OnVelocityComputed;

View File

@@ -26,6 +26,7 @@ material = SubResource("StandardMaterial3D_p4gkk")
top_radius = 0.0 top_radius = 0.0
[sub_resource type="CylinderShape3D" id="CylinderShape3D_drfkj"] [sub_resource type="CylinderShape3D" id="CylinderShape3D_drfkj"]
radius = 1.0
[node name="Sproingy" type="CharacterBody3D"] [node name="Sproingy" type="CharacterBody3D"]
process_mode = 1 process_mode = 1
@@ -81,8 +82,6 @@ shape = SubResource("CylinderShape3D_drfkj")
[node name="EnemyModelView" parent="Visual" instance=ExtResource("4_o3b7p")] [node name="EnemyModelView" parent="Visual" instance=ExtResource("4_o3b7p")]
unique_name_in_owner = true unique_name_in_owner = true
_upperThreshold = 0.5
_lowerThreshold = -0.5
[node name="Components" type="Node3D" parent="."] [node name="Components" type="Node3D" parent="."]

View File

@@ -25,9 +25,13 @@ public partial class Michael : Enemy2D, IHavePatrolBehavior, IHaveEngagePlayerBe
FollowBehavior.OnVelocityComputed += OnVelocityComputed; FollowBehavior.OnVelocityComputed += OnVelocityComputed;
EngagePlayerBehavior.TakeAction += EngagePlayerBehavior_TakeAction; EngagePlayerBehavior.TakeAction += EngagePlayerBehavior_TakeAction;
EngagePlayerBehavior.AcquireTarget += EngagePlayerBehavior_AcquireTarget; EngagePlayerBehavior.AcquireTarget += EngagePlayerBehavior_AcquireTarget;
_enemyLogic.Input(new EnemyLogic.Input.Patrol());
PlayerDetector.BodyEntered += PlayerDetector_BodyEntered; PlayerDetector.BodyEntered += PlayerDetector_BodyEntered;
PlayerDetector.BodyExited += PlayerDetector_BodyExited; PlayerDetector.BodyExited += PlayerDetector_BodyExited;
SetPhysicsProcess(true); SetPhysicsProcess(true);
} }
public void OnResolved()
{
_enemyLogic.Input(new EnemyLogic.Input.Patrol());
}
} }

View File

@@ -1,6 +1,8 @@
using Chickensoft.AutoInject; using Chickensoft.AutoInject;
using Chickensoft.Introspection; using Chickensoft.Introspection;
using Godot; using Godot;
using System;
using System.Collections.Generic;
namespace Zennysoft.Game.Ma; namespace Zennysoft.Game.Ma;
@@ -9,6 +11,10 @@ public partial class FilthEater : Enemy2D, IHavePatrolBehavior, IHaveEngagePlaye
{ {
public override void _Notification(int what) => this.Notify(what); public override void _Notification(int what) => this.Notify(what);
[Export] private float PrimaryAttackChance { get; set; } = 0.75f;
[Export] private float SecondaryAttackChance { get; set; } = 0.25f;
[Node] public NavigationAgent3D NavigationAgent { get; set; } [Node] public NavigationAgent3D NavigationAgent { get; set; }
[Node] public PatrolBehavior PatrolBehavior { get; set; } = default!; [Node] public PatrolBehavior PatrolBehavior { get; set; } = default!;
[Node] public FollowBehavior FollowBehavior { get; set; } = default!; [Node] public FollowBehavior FollowBehavior { get; set; } = default!;
@@ -25,13 +31,23 @@ public partial class FilthEater : Enemy2D, IHavePatrolBehavior, IHaveEngagePlaye
FollowBehavior.OnVelocityComputed += OnVelocityComputed; FollowBehavior.OnVelocityComputed += OnVelocityComputed;
EngagePlayerBehavior.TakeAction += PerformAction; EngagePlayerBehavior.TakeAction += PerformAction;
EngagePlayerBehavior.AcquireTarget += EngagePlayerBehavior_AcquireTarget; EngagePlayerBehavior.AcquireTarget += EngagePlayerBehavior_AcquireTarget;
_enemyLogic.Input(new EnemyLogic.Input.Patrol());
PlayerDetector.BodyEntered += PlayerDetector_BodyEntered; PlayerDetector.BodyEntered += PlayerDetector_BodyEntered;
PlayerDetector.BodyExited += PlayerDetector_BodyExited; PlayerDetector.BodyExited += PlayerDetector_BodyExited;
SetPhysicsProcess(true); SetPhysicsProcess(true);
} }
public override void PerformAction() => EnemyModelView.PlaySecondaryAttackAnimation(); public void OnResolved()
{
_enemyLogic.Input(new EnemyLogic.Input.Patrol());
}
public override void PerformAction()
{
var rng = new RandomNumberGenerator();
var options = new List<Action>() { EnemyModelView.PlayPrimaryAttackAnimation, EnemyModelView.PlaySecondaryAttackAnimation };
var selection = rng.RandWeighted([PrimaryAttackChance, SecondaryAttackChance]);
options[(int)selection].Invoke();
}
public override void _ExitTree() public override void _ExitTree()
{ {

View File

@@ -2658,45 +2658,6 @@ animations = [{
[sub_resource type="SphereShape3D" id="SphereShape3D_kct8n"] [sub_resource type="SphereShape3D" id="SphereShape3D_kct8n"]
[sub_resource type="Animation" id="Animation_8qeb2"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("..:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("../ProjectileHitbox:monitoring")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath(".:visible")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
[sub_resource type="Animation" id="Animation_xrn7e"] [sub_resource type="Animation" id="Animation_xrn7e"]
resource_name = "fire" resource_name = "fire"
tracks/0/type = "value" tracks/0/type = "value"
@@ -2751,6 +2712,45 @@ tracks/3/keys = {
"values": [false, true, false] "values": [false, true, false]
} }
[sub_resource type="Animation" id="Animation_8qeb2"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("..:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("../ProjectileHitbox:monitoring")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath(".:visible")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_q8n6h"] [sub_resource type="AnimationLibrary" id="AnimationLibrary_q8n6h"]
_data = { _data = {
&"Fire": SubResource("Animation_xrn7e"), &"Fire": SubResource("Animation_xrn7e"),

View File

@@ -30,12 +30,16 @@ public partial class Sara : Enemy2D, IHavePatrolBehavior, IHaveEngagePlayerBehav
FollowBehavior.OnVelocityComputed += OnVelocityComputed; FollowBehavior.OnVelocityComputed += OnVelocityComputed;
EngagePlayerBehavior.TakeAction += EngagePlayerBehavior_TakeAction; EngagePlayerBehavior.TakeAction += EngagePlayerBehavior_TakeAction;
EngagePlayerBehavior.AcquireTarget += EngagePlayerBehavior_AcquireTarget; EngagePlayerBehavior.AcquireTarget += EngagePlayerBehavior_AcquireTarget;
_enemyLogic.Input(new EnemyLogic.Input.Patrol());
PlayerDetector.BodyEntered += PlayerDetector_BodyEntered; PlayerDetector.BodyEntered += PlayerDetector_BodyEntered;
PlayerDetector.BodyExited += PlayerDetector_BodyExited; PlayerDetector.BodyExited += PlayerDetector_BodyExited;
SetPhysicsProcess(true); SetPhysicsProcess(true);
} }
public void OnResolved()
{
_enemyLogic.Input(new EnemyLogic.Input.Patrol());
}
public override void PerformAction() public override void PerformAction()
{ {
var rng = new RandomNumberGenerator(); var rng = new RandomNumberGenerator();

View File

@@ -30,12 +30,16 @@ public partial class Ballos : Enemy2D, IHavePatrolBehavior, IHaveEngagePlayerBeh
FollowBehavior.OnVelocityComputed += OnVelocityComputed; FollowBehavior.OnVelocityComputed += OnVelocityComputed;
EngagePlayerBehavior.TakeAction += EngagePlayerBehavior_TakeAction; EngagePlayerBehavior.TakeAction += EngagePlayerBehavior_TakeAction;
EngagePlayerBehavior.AcquireTarget += EngagePlayerBehavior_AcquireTarget; EngagePlayerBehavior.AcquireTarget += EngagePlayerBehavior_AcquireTarget;
_enemyLogic.Input(new EnemyLogic.Input.Patrol());
PlayerDetector.BodyEntered += PlayerDetector_BodyEntered; PlayerDetector.BodyEntered += PlayerDetector_BodyEntered;
PlayerDetector.BodyExited += PlayerDetector_BodyExited; PlayerDetector.BodyExited += PlayerDetector_BodyExited;
SetPhysicsProcess(true); SetPhysicsProcess(true);
} }
public void OnResolved()
{
_enemyLogic.Input(new EnemyLogic.Input.Patrol());
}
public override void PerformAction() public override void PerformAction()
{ {
var rng = new RandomNumberGenerator(); var rng = new RandomNumberGenerator();

View File

@@ -36,6 +36,11 @@ public partial class Chariot : Enemy2D, IHavePatrolBehavior, IHaveEngagePlayerBe
SetPhysicsProcess(true); SetPhysicsProcess(true);
} }
public void OnResolved()
{
_enemyLogic.Input(new EnemyLogic.Input.Patrol());
}
public override void Activate() public override void Activate()
{ {
EnemyModelView.PlayActivateAnimation(); EnemyModelView.PlayActivateAnimation();

View File

@@ -54,12 +54,6 @@ public partial class Chinthe : Enemy2D, IHaveEngagePlayerBehavior, IHaveFollowBe
EnemyModelView.PlayActivateAnimation(); EnemyModelView.PlayActivateAnimation();
} }
public override void Idle()
{
EnemyModelView.PlayIdleAnimation();
EnemyModelView.PlayIdleAnimation();
}
private void Teleport(object sender, EventArgs e) private void Teleport(object sender, EventArgs e)
{ {
var targetPosition = _player.GlobalBasis.Z; var targetPosition = _player.GlobalBasis.Z;

View File

@@ -3004,7 +3004,7 @@ tracks/0/keys = {
"times": PackedFloat32Array(0), "times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1), "transitions": PackedFloat32Array(1),
"update": 1, "update": 1,
"values": [23] "values": [0]
} }
[sub_resource type="AnimationLibrary" id="AnimationLibrary_yuosm"] [sub_resource type="AnimationLibrary" id="AnimationLibrary_yuosm"]
@@ -3294,7 +3294,6 @@ modulate = Color(1, 1, 1, 0.788235)
billboard = 1 billboard = 1
texture_filter = 0 texture_filter = 0
sprite_frames = SubResource("SpriteFrames_ie7uh") sprite_frames = SubResource("SpriteFrames_ie7uh")
frame = 23
[node name="Attack 2 VFX" type="AnimatedSprite3D" parent="VFX Animation Player"] [node name="Attack 2 VFX" type="AnimatedSprite3D" parent="VFX Animation Player"]
sprite_frames = SubResource("SpriteFrames_lgwan") sprite_frames = SubResource("SpriteFrames_lgwan")

View File

@@ -9,18 +9,9 @@ public partial class EnemyLogic
{ {
[Meta, Id("enemy_logic_state_activated")] [Meta, Id("enemy_logic_state_activated")]
public partial record Activated : Alive, public partial record Activated : Alive,
IGet<ReachedPlayer>,
IGet<Patrol>,
IGet<Follow>,
IGet<Reset> IGet<Reset>
{ {
public Activated() => OnAttach(() => Output(new Output.Activate())); public Activated() => OnAttach(() => Output(new Output.Activate()));
} }
public Transition On(in ReachedPlayer input) => To<EngagePlayer>();
public Transition On(in Patrol _) => To<Patrolling>();
public Transition On(in Follow _) => To<FollowPlayer>();
} }
} }

View File

@@ -11,6 +11,9 @@ public partial class EnemyLogic
public abstract partial record Alive : State, public abstract partial record Alive : State,
IGet<Input.Idle>, IGet<Input.Idle>,
IGet<Move>, IGet<Move>,
IGet<Patrol>,
IGet<Follow>,
IGet<ReachedPlayer>,
IGet<Input.Defeated> IGet<Input.Defeated>
{ {
public Transition On(in Reset input) public Transition On(in Reset input)
@@ -21,11 +24,13 @@ public partial class EnemyLogic
public Transition On(in Input.Defeated input) => To<Defeated>(); public Transition On(in Input.Defeated input) => To<Defeated>();
public Transition On(in Input.Idle input) public Transition On(in Input.Idle input) => To<Idle>();
{
Output(new Output.Idle()); public Transition On(in Follow _) => To<FollowPlayer>();
return ToSelf();
} public Transition On(in ReachedPlayer input) => To<EngagePlayer>();
public Transition On(in Patrol _) => To<Patrolling>();
public Transition On(in Move input) public Transition On(in Move input)
{ {

View File

@@ -8,7 +8,7 @@ public partial class EnemyLogic
public partial record State public partial record State
{ {
[Meta, Id("enemy_logic_state_engage_player")] [Meta, Id("enemy_logic_state_engage_player")]
public partial record EngagePlayer : Activated public partial record EngagePlayer : Alive
{ {
public EngagePlayer() public EngagePlayer()
{ {
@@ -18,7 +18,6 @@ public partial class EnemyLogic
if (enemy is IHaveEngagePlayerBehavior engagePlayerEnemy) if (enemy is IHaveEngagePlayerBehavior engagePlayerEnemy)
{ {
engagePlayerEnemy.EngagePlayerBehavior.Engage(); engagePlayerEnemy.EngagePlayerBehavior.Engage();
Input(new Input.Idle());
} }
}); });
OnDetach(() => OnDetach(() =>
@@ -27,7 +26,6 @@ public partial class EnemyLogic
if (enemy is IHaveEngagePlayerBehavior engagePlayerEnemy) if (enemy is IHaveEngagePlayerBehavior engagePlayerEnemy)
{ {
engagePlayerEnemy.EngagePlayerBehavior.Disengage(); engagePlayerEnemy.EngagePlayerBehavior.Disengage();
Input(new Input.Idle());
} }
}); });
} }

View File

@@ -8,7 +8,7 @@ public partial class EnemyLogic
public partial record State public partial record State
{ {
[Meta, Id("enemy_logic_state_followplayer")] [Meta, Id("enemy_logic_state_followplayer")]
public partial record FollowPlayer : Activated, IGet<Input.LoseTrackOfTarget> public partial record FollowPlayer : Alive, IGet<Input.LoseTrackOfTarget>
{ {
public FollowPlayer() public FollowPlayer()
{ {
@@ -18,7 +18,6 @@ public partial class EnemyLogic
if (enemy is IHaveFollowBehavior followEnemy) if (enemy is IHaveFollowBehavior followEnemy)
{ {
followEnemy.FollowBehavior.StartFollow(followEnemy.NavigationAgent); followEnemy.FollowBehavior.StartFollow(followEnemy.NavigationAgent);
Input(new Input.Move());
} }
}); });
OnDetach(() => OnDetach(() =>
@@ -27,7 +26,6 @@ public partial class EnemyLogic
if (enemy is IHaveFollowBehavior followEnemy) if (enemy is IHaveFollowBehavior followEnemy)
{ {
followEnemy.FollowBehavior.StopFollow(); followEnemy.FollowBehavior.StopFollow();
Input(new Input.Idle());
} }
}); });
} }

View File

@@ -7,7 +7,7 @@ public partial class EnemyLogic
public partial record State public partial record State
{ {
[Meta, Id("enemy_logic_state_idle")] [Meta, Id("enemy_logic_state_idle")]
public partial record Idle : Activated public partial record Idle : Alive
{ {
public Idle() => OnAttach(() => Output(new Output.Idle())); public Idle() => OnAttach(() => Output(new Output.Idle()));
} }

View File

@@ -1,5 +1,4 @@
using Chickensoft.Introspection; using Chickensoft.Introspection;
using Godot;
using Zennysoft.Ma.Adapter.Entity; using Zennysoft.Ma.Adapter.Entity;
namespace Zennysoft.Game.Ma; namespace Zennysoft.Game.Ma;
@@ -9,7 +8,7 @@ public partial class EnemyLogic
public partial record State public partial record State
{ {
[Meta, Id("enemy_logic_state_patrolling")] [Meta, Id("enemy_logic_state_patrolling")]
public partial record Patrolling : Activated public partial record Patrolling : Alive
{ {
public Patrolling() public Patrolling()
{ {
@@ -19,7 +18,6 @@ public partial class EnemyLogic
if (enemy is IHavePatrolBehavior patrolEnemy) if (enemy is IHavePatrolBehavior patrolEnemy)
{ {
patrolEnemy.PatrolBehavior.StartPatrol(); patrolEnemy.PatrolBehavior.StartPatrol();
Input(new Input.Move());
} }
}); });
OnDetach(() => OnDetach(() =>
@@ -28,7 +26,6 @@ public partial class EnemyLogic
if (enemy is IHavePatrolBehavior patrolEnemy) if (enemy is IHavePatrolBehavior patrolEnemy)
{ {
patrolEnemy.PatrolBehavior.StopPatrol(); patrolEnemy.PatrolBehavior.StopPatrol();
Input(new Input.Idle());
} }
}); });
} }

View File

@@ -80,7 +80,7 @@ unique_name_in_owner = true
script = ExtResource("2_00xd7") script = ExtResource("2_00xd7")
FolderName = "SetAFloors" FolderName = "SetAFloors"
FloorOdds = Array[float]([0.0, 1.0]) FloorOdds = Array[float]([0.0, 1.0])
Chinthe = 1.0 Sproingy = 1.0
[node name="Overworld" type="Node" parent="MapOrder"] [node name="Overworld" type="Node" parent="MapOrder"]
script = ExtResource("3_v14r0") script = ExtResource("3_v14r0")