feat(enemy): RushEngagement——两个耦合 flag 合并为 RushExit 语义枚举
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8dc9b46f90ca9734e85831dd4fc0299c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using BaseGames.AI;
|
||||
using BaseGames.Enemies.Abilities;
|
||||
|
||||
namespace BaseGames.Enemies
|
||||
{
|
||||
/// <summary>接触冲锋:一个能力包办追击与伤害。冲锋能力自己管方向、速度、动画与命中。</summary>
|
||||
[Serializable]
|
||||
public sealed class RushEngagement : IEngagementModule
|
||||
{
|
||||
public const string Rush = "Rush";
|
||||
|
||||
[Tooltip("冲锋能力")]
|
||||
[SerializeField] AbilityRef _ability;
|
||||
[Tooltip("脱战语义:OnLostTarget=追不到就放弃;Committed=起手即锁定,打完才脱战")]
|
||||
[SerializeField] RushExit _exit = RushExit.OnLostTarget;
|
||||
|
||||
// 惰性缓存:[SerializeReference] 反序列化不保证走构造函数,不能在 ctor 里预计算。
|
||||
[NonSerialized] Func<IAiContext, bool> _canEngage;
|
||||
|
||||
public RushEngagement() { }
|
||||
public RushEngagement(AbilityRef ability, RushExit exit = RushExit.OnLostTarget)
|
||||
{ _ability = ability; _exit = exit; }
|
||||
|
||||
public string EntryState => Rush;
|
||||
|
||||
public string EngageLabel => _exit == RushExit.Committed ? "InChaseZone+offCD" : "InChaseZone";
|
||||
|
||||
public Func<IAiContext, bool> CanEngage
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_canEngage == null)
|
||||
{
|
||||
string id = RequireAbilityId();
|
||||
_canEngage = _exit == RushExit.Committed
|
||||
? x => x.Sensor.InChaseZone() && x.Combat.CanUseAbility(id)
|
||||
: (Func<IAiContext, bool>)(x => x.Sensor.InChaseZone());
|
||||
}
|
||||
return _canEngage;
|
||||
}
|
||||
}
|
||||
|
||||
public void Build(BrainBuilder b, string rest)
|
||||
{
|
||||
string id = RequireAbilityId();
|
||||
var s = AiStateFragments.Ability(b, Rush, id);
|
||||
if (_exit == RushExit.Committed)
|
||||
s.To(rest).When(x => !x.Combat.IsAbilityRunning(id), "rushDone→CD");
|
||||
else
|
||||
s.To(rest).When(AiStateFragments.LostAllZones, "leftAllZones");
|
||||
}
|
||||
|
||||
// 校验放这里而非构造函数:反序列化路径不走 ctor,漏配必须在建图时暴露。
|
||||
string RequireAbilityId()
|
||||
{
|
||||
string id = _ability.Id;
|
||||
if (string.IsNullOrEmpty(id))
|
||||
throw new InvalidOperationException("RushEngagement:未配置冲锋能力。");
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4df22f40788d1624fbcbe0081aea92e1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace BaseGames.Enemies
|
||||
{
|
||||
/// <summary>冲锋的脱战语义。一个值同时决定"脱战边怎么写"与"进入条件带不带冷却门"。</summary>
|
||||
public enum RushExit
|
||||
{
|
||||
/// <summary>追不到就放弃:脱离全部感知区即停。</summary>
|
||||
OnLostTarget,
|
||||
|
||||
/// <summary>
|
||||
/// 起手即锁定:整段冲锋跑完才脱战,中途丢失感知不打断。
|
||||
/// 冷却门由模块自动附加——否则打完回未发现态后,下一帧仍在追逐区会立刻再冲,
|
||||
/// 出现 冲锋态 ↔ 未发现态 每帧抖动。
|
||||
/// </summary>
|
||||
Committed,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62cce901ea34dbd4ba6edc77f15e17f5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user