多轮审查和修复
This commit is contained in:
33
Assets/Scripts/Enemies/Boss/AttackPatternSO.cs
Normal file
33
Assets/Scripts/Enemies/Boss/AttackPatternSO.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using BaseGames.Combat;
|
||||
|
||||
namespace BaseGames.Boss
|
||||
{
|
||||
/// <summary>
|
||||
/// 单个攻击图案的数据。伤害参数只写在此处,BossSkillSO 不存参数。
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Boss/AttackPattern")]
|
||||
public class AttackPatternSO : ScriptableObject
|
||||
{
|
||||
[Header("输出")]
|
||||
public DamageSourceSO DamageSource;
|
||||
public float KnockbackAngle;
|
||||
|
||||
[Header("弹幕(若为弹幕类型)")]
|
||||
public AssetReferenceGameObject ProjectilePrefab;
|
||||
public int ProjectileCount = 1;
|
||||
public float SpreadAngle = 0f;
|
||||
public float ProjectileSpeed = 8f;
|
||||
|
||||
[Header("范围攻击(若为 AoE 类型)")]
|
||||
public float AoERadius;
|
||||
public Vector2 AoEOffset;
|
||||
|
||||
[Header("时序")]
|
||||
[Min(0f)] public float WindupDuration;
|
||||
[Min(0f)] public float ActiveDuration;
|
||||
[Min(0f)] public float RecoveryDuration;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Enemies/Boss/AttackPatternSO.cs.meta
Normal file
11
Assets/Scripts/Enemies/Boss/AttackPatternSO.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81f89b6e2f8f2774ab7cedbe45dcb810
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
48
Assets/Scripts/Enemies/Boss/BossBase.cs
Normal file
48
Assets/Scripts/Enemies/Boss/BossBase.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using UnityEngine;
|
||||
using BaseGames.Core.Events;
|
||||
|
||||
namespace BaseGames.Enemies
|
||||
{
|
||||
/// <summary>
|
||||
/// Boss 敌人基类。扩展 <see cref="EnemyBase"/> 以支持多阶段切换与战斗结束广播。
|
||||
/// 具体 Boss 继承此类并重写 <see cref="EnterPhase"/>。
|
||||
/// </summary>
|
||||
public class BossBase : EnemyBase
|
||||
{
|
||||
[Header("Boss 配置")]
|
||||
[SerializeField] private string _bossId;
|
||||
[SerializeField] private BoolEventChannelSO _onBossFightEnded;
|
||||
[SerializeField] private BossPhaseEventChannelSO _onBossPhaseChanged;
|
||||
|
||||
public string BossId => _bossId;
|
||||
|
||||
protected int _currentPhase = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 进入指定阶段。广播 <see cref="BossPhaseEvent"/> 供 UI / 音乐系统响应。
|
||||
/// 子类可重写以添加额外过渡逻辑(动画、无敌帧等)。
|
||||
/// </summary>
|
||||
public virtual void EnterPhase(int phase)
|
||||
{
|
||||
_currentPhase = phase;
|
||||
_onBossPhaseChanged?.Raise(new BossPhaseEvent
|
||||
{
|
||||
BossId = _bossId,
|
||||
Phase = phase,
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>检查当前 HP 是否低于指定百分比(0~1)。</summary>
|
||||
public bool IsHPBelow(float ratio)
|
||||
{
|
||||
if (_stats == null || _stats.MaxHP <= 0) return false;
|
||||
return (float)_stats.CurrentHP / _stats.MaxHP < ratio;
|
||||
}
|
||||
|
||||
protected override void Die()
|
||||
{
|
||||
base.Die();
|
||||
_onBossFightEnded?.Raise(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Enemies/Boss/BossBase.cs.meta
Normal file
11
Assets/Scripts/Enemies/Boss/BossBase.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53427085944cddb4bacba2c2e80fb134
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
26
Assets/Scripts/Enemies/Boss/BossResourceConfigSO.cs
Normal file
26
Assets/Scripts/Enemies/Boss/BossResourceConfigSO.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace BaseGames.Boss
|
||||
{
|
||||
/// <summary>
|
||||
/// Boss 自身资源(如愤怒值)的配置 ScriptableObject。
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Boss/ResourceConfig")]
|
||||
public class BossResourceConfigSO : ScriptableObject
|
||||
{
|
||||
public string resourceId;
|
||||
public string displayName;
|
||||
public float maxValue;
|
||||
public float startValue;
|
||||
|
||||
[Header("自动变化")]
|
||||
public float passiveRate;
|
||||
public float onTakeDamageGain;
|
||||
public float onSkillUseGain;
|
||||
|
||||
[Header("满值效果")]
|
||||
public bool autoTriggerOnFull;
|
||||
public BossSkillSO fullTriggerSkill;
|
||||
public float resetValueAfterTrigger;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Enemies/Boss/BossResourceConfigSO.cs.meta
Normal file
11
Assets/Scripts/Enemies/Boss/BossResourceConfigSO.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47b7618faa6ceb3458714246d12f9e73
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
184
Assets/Scripts/Enemies/Boss/BossSkillExecutor.cs
Normal file
184
Assets/Scripts/Enemies/Boss/BossSkillExecutor.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Animancer;
|
||||
using BaseGames.Combat;
|
||||
using BaseGames.Core.Events;
|
||||
|
||||
namespace BaseGames.Boss
|
||||
{
|
||||
/// <summary>
|
||||
/// 挂在 Boss GameObject 上,接收 BossOrchestrator 的指令执行指定 BossSkillSO。
|
||||
/// 管理 VulnerabilityWindow 计时和 WeakPointSystem 激活。
|
||||
/// </summary>
|
||||
public class BossSkillExecutor : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private HitBox[] _hitBoxes;
|
||||
[SerializeField] private WeakPointSystem _weakPointSystem;
|
||||
[SerializeField] private AnimancerComponent _animancer;
|
||||
[SerializeField] private string _bossId;
|
||||
[SerializeField] private BossSkillEventChannelSO _onBossSkillStarted;
|
||||
[SerializeField] private BossSkillEventChannelSO _onBossSkillEnded;
|
||||
/// <remarks>PlayerController 无 Instance(架构 05 §2),由 Inspector 指定。</remarks>
|
||||
[SerializeField] private Transform _playerTransform;
|
||||
|
||||
private BossSkillSO _currentSkill;
|
||||
private bool _isExecuting;
|
||||
private Coroutine _activeCoroutine;
|
||||
|
||||
public bool IsExecuting => _isExecuting;
|
||||
|
||||
/// <summary>
|
||||
/// 按 float 值复用 WaitForSeconds 实例,消除协程中每次 new WaitForSeconds 的 GC 分配。
|
||||
/// Domain Reload 禁用时静态缓存跨 PlayMode 会话保留,但 WaitForSeconds 是幂等值对象,
|
||||
/// 不会引发功能错误;[RuntimeInitializeOnLoadMethod] 确保每次进入 Play 时清空。
|
||||
/// </summary>
|
||||
private static readonly Dictionary<float, WaitForSeconds> _wfsCache = new();
|
||||
|
||||
[UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void ClearWFSCache() => _wfsCache.Clear();
|
||||
|
||||
private static WaitForSeconds GetWFS(float t)
|
||||
{
|
||||
if (!_wfsCache.TryGetValue(t, out var wfs))
|
||||
_wfsCache[t] = wfs = new WaitForSeconds(t);
|
||||
return wfs;
|
||||
}
|
||||
|
||||
// ── 公共 API ───────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// 执行一个 Boss 技能。若当前已在执行中则直接返回。
|
||||
/// </summary>
|
||||
public void ExecuteSkill(BossSkillSO skill)
|
||||
{
|
||||
if (_isExecuting || skill == null) return;
|
||||
_activeCoroutine = StartCoroutine(ExecuteSkillCoroutine(skill));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 立即打断正在执行的技能(阶段切换时调用)。
|
||||
/// </summary>
|
||||
public void InterruptCurrentSkill()
|
||||
{
|
||||
if (_activeCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_activeCoroutine);
|
||||
_activeCoroutine = null;
|
||||
}
|
||||
FinishExecution();
|
||||
}
|
||||
|
||||
// ── 主协程 ─────────────────────────────────────────────────────────────
|
||||
|
||||
private IEnumerator ExecuteSkillCoroutine(BossSkillSO skill)
|
||||
{
|
||||
_isExecuting = true;
|
||||
_currentSkill = skill;
|
||||
_onBossSkillStarted?.Raise(new BossSkillEvent { BossId = _bossId, SkillId = skill.skillId });
|
||||
|
||||
// 播放技能动画
|
||||
if (skill.skillAnimation != null)
|
||||
_animancer.Play(skill.skillAnimation);
|
||||
|
||||
// 启动 VulnerabilityWindow 协程(与主序列并行)
|
||||
Coroutine vulnCoroutine = null;
|
||||
if (skill.vulnerabilityWindows != null && skill.vulnerabilityWindows.Length > 0)
|
||||
vulnCoroutine = StartCoroutine(ActivateVulnerabilityWindowsCoroutine(skill));
|
||||
|
||||
// 执行攻击序列(优先 sequenceOnMiss 作为默认序列)
|
||||
if (skill.sequenceOnMiss != null)
|
||||
yield return ExecuteSequenceCoroutine(skill.sequenceOnMiss);
|
||||
|
||||
// 若弱点协程还在运行则等待其结束(避免孤立协程)
|
||||
if (vulnCoroutine != null)
|
||||
yield return vulnCoroutine;
|
||||
|
||||
FinishExecution();
|
||||
}
|
||||
|
||||
private void FinishExecution()
|
||||
{
|
||||
_isExecuting = false;
|
||||
if (_currentSkill != null)
|
||||
{
|
||||
_onBossSkillEnded?.Raise(new BossSkillEvent { BossId = _bossId, SkillId = _currentSkill.skillId });
|
||||
_currentSkill = null;
|
||||
}
|
||||
}
|
||||
|
||||
// ── 序列协程 ────────────────────────────────────────────────────────────
|
||||
|
||||
private IEnumerator ExecuteSequenceCoroutine(SkillSequenceSO seq)
|
||||
{
|
||||
int repeatCount = 0;
|
||||
do
|
||||
{
|
||||
foreach (var step in seq.steps)
|
||||
{
|
||||
if (step.delayBeforeStep > 0f)
|
||||
yield return GetWFS(step.delayBeforeStep);
|
||||
|
||||
if (step.pattern != null)
|
||||
yield return ExecutePatternCoroutine(step.pattern);
|
||||
}
|
||||
|
||||
repeatCount++;
|
||||
|
||||
if (seq.RepeatIfPlayerInRange && seq.RepeatDelay > 0f)
|
||||
yield return GetWFS(seq.RepeatDelay);
|
||||
}
|
||||
while (seq.RepeatIfPlayerInRange
|
||||
&& (seq.MaxRepeatCount == 0 || repeatCount < seq.MaxRepeatCount)
|
||||
&& IsPlayerInRange());
|
||||
}
|
||||
|
||||
private IEnumerator ExecutePatternCoroutine(AttackPatternSO pattern)
|
||||
{
|
||||
// 预备
|
||||
if (pattern.WindupDuration > 0f)
|
||||
yield return GetWFS(pattern.WindupDuration);
|
||||
|
||||
// 激活 HitBox(架构 06 §4:Activate(DamageSourceSO, Transform))
|
||||
foreach (var hb in _hitBoxes)
|
||||
hb.Activate(pattern.DamageSource, transform);
|
||||
|
||||
if (pattern.ActiveDuration > 0f)
|
||||
yield return GetWFS(pattern.ActiveDuration);
|
||||
|
||||
// 关闭 HitBox
|
||||
foreach (var hb in _hitBoxes)
|
||||
hb.Deactivate();
|
||||
|
||||
// 后摇
|
||||
if (pattern.RecoveryDuration > 0f)
|
||||
yield return GetWFS(pattern.RecoveryDuration);
|
||||
}
|
||||
|
||||
// ── VulnerabilityWindow 协程 ─────────────────────────────────────────────
|
||||
|
||||
private IEnumerator ActivateVulnerabilityWindowsCoroutine(BossSkillSO skill)
|
||||
{
|
||||
foreach (var window in skill.vulnerabilityWindows)
|
||||
{
|
||||
if (window.TriggerDelay > 0f)
|
||||
yield return GetWFS(window.TriggerDelay);
|
||||
|
||||
bool activateSpecific = window.ActivateWeakPointHurtBox;
|
||||
_weakPointSystem?.SetActive(true, window.DamageMultiplier, activateSpecific);
|
||||
window.OpenFeedback?.PlayFeedbacks();
|
||||
|
||||
yield return GetWFS(window.Duration);
|
||||
|
||||
_weakPointSystem?.SetActive(false, 1f, activateSpecific);
|
||||
window.CloseFeedback?.PlayFeedbacks();
|
||||
}
|
||||
}
|
||||
|
||||
// ── 工具 ───────────────────────────────────────────────────────────────
|
||||
|
||||
private bool IsPlayerInRange() =>
|
||||
_playerTransform != null &&
|
||||
Vector2.Distance(transform.position, _playerTransform.position) < 8f;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Enemies/Boss/BossSkillExecutor.cs.meta
Normal file
11
Assets/Scripts/Enemies/Boss/BossSkillExecutor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4dfa1c525eaca5640b3cfe945626a466
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
61
Assets/Scripts/Enemies/Boss/BossSkillSO.cs
Normal file
61
Assets/Scripts/Enemies/Boss/BossSkillSO.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Animancer;
|
||||
using BaseGames.Combat;
|
||||
|
||||
namespace BaseGames.Boss
|
||||
{
|
||||
/// <summary>
|
||||
/// Boss 单个技能的所有数据,包括攻击模式、弱点窗口、互动标签等。
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Boss/BossSkill")]
|
||||
public class BossSkillSO : ScriptableObject
|
||||
{
|
||||
[Header("元信息")]
|
||||
public string skillId;
|
||||
public string displayName;
|
||||
[TextArea(1, 4)]
|
||||
public string designNote;
|
||||
|
||||
[Header("技能分类")]
|
||||
public BossSkillCategory category;
|
||||
public BossSkillType skillType;
|
||||
|
||||
[Header("阶段可用性")]
|
||||
[Tooltip("空数组 = 全阶段可用")]
|
||||
public int[] availablePhaseIndices;
|
||||
|
||||
[Header("核心攻击动作引用")]
|
||||
public AttackPatternSO[] attackPatterns;
|
||||
|
||||
[Header("弱点窗口(至少 1 个)")]
|
||||
public VulnerabilityWindow[] vulnerabilityWindows;
|
||||
|
||||
[Header("互动标签")]
|
||||
public InteractionTag interactionTags;
|
||||
|
||||
[Header("连段")]
|
||||
public SkillSequenceSO sequenceOnHit;
|
||||
public SkillSequenceSO sequenceOnMiss;
|
||||
|
||||
[Header("玩家反制接口")]
|
||||
public PlayerCounterResponse[] counterResponses;
|
||||
|
||||
[Header("场景联动")]
|
||||
public ArenaEventTrigger[] arenaEvents;
|
||||
|
||||
[Header("Boss 资源")]
|
||||
public BossResourceCost resourceCost;
|
||||
public bool buildsRage;
|
||||
|
||||
[Header("霸体配置")]
|
||||
public PoiseWindowConfig poiseWindow;
|
||||
|
||||
[Header("动画")]
|
||||
public ClipTransition skillAnimation;
|
||||
|
||||
[Header("冷却")]
|
||||
[Min(0f)]
|
||||
public float cooldown;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Enemies/Boss/BossSkillSO.cs.meta
Normal file
11
Assets/Scripts/Enemies/Boss/BossSkillSO.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de92221c7c3fb4a42a7cd122a8f97632
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
184
Assets/Scripts/Enemies/Boss/BossSkillTypes.cs
Normal file
184
Assets/Scripts/Enemies/Boss/BossSkillTypes.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using MoreMountains.Feedbacks;
|
||||
|
||||
namespace BaseGames.Boss
|
||||
{
|
||||
// ── 分类枚举 ───────────────────────────────────────────────────────────────
|
||||
|
||||
public enum BossSkillCategory
|
||||
{
|
||||
Melee, Ranged, Charge, AoE, Environmental, Summon,
|
||||
Buff, Debuff, Phase, Passive, Reactive
|
||||
}
|
||||
|
||||
public enum BossSkillType
|
||||
{
|
||||
MeleeSlash,
|
||||
ChargeAttack,
|
||||
LeapSlam,
|
||||
ProjectileVolley,
|
||||
LaserBeam,
|
||||
PhaseTransition,
|
||||
SummonMinion,
|
||||
ArenaTrap,
|
||||
SpeedBurst,
|
||||
DefensiveShell,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum InteractionTag
|
||||
{
|
||||
None = 0,
|
||||
Parryable = 1 << 0,
|
||||
PerfectParryOnly = 1 << 1,
|
||||
DodgeWindow = 1 << 2,
|
||||
Unblockable = 1 << 3,
|
||||
CanBeReflected = 1 << 4,
|
||||
ExposesWeakPoint = 1 << 5,
|
||||
GrantsPlayerReso = 1 << 6,
|
||||
ArenaHazard = 1 << 7,
|
||||
PhaseGate = 1 << 8,
|
||||
}
|
||||
|
||||
// ── VulnerabilityWindow ────────────────────────────────────────────────────
|
||||
|
||||
public enum VulnTriggerType
|
||||
{
|
||||
OnAttackRecovery,
|
||||
OnParriedSuccess,
|
||||
OnCounterSkillHit,
|
||||
OnPhaseTransition,
|
||||
OnHazardBackfire,
|
||||
OnSummonDefeated,
|
||||
Manual,
|
||||
}
|
||||
|
||||
public enum WeakPointType
|
||||
{
|
||||
FullBody,
|
||||
HeadOnly,
|
||||
BackOnly,
|
||||
CoreExposed,
|
||||
CustomPoint,
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct VulnerabilityWindow
|
||||
{
|
||||
[Tooltip("弱点触发方式")]
|
||||
public VulnTriggerType TriggerType;
|
||||
|
||||
[Tooltip("触发后延迟出现(秒)")]
|
||||
[Min(0f)]
|
||||
public float TriggerDelay;
|
||||
|
||||
[Tooltip("弱点持续时长(秒)")]
|
||||
[Min(0.1f)]
|
||||
public float Duration;
|
||||
|
||||
public WeakPointType WeakPointType;
|
||||
|
||||
[Tooltip("弱点激活时 Boss 受击乘数")]
|
||||
[Min(0.1f)]
|
||||
public float DamageMultiplier;
|
||||
|
||||
public bool ForceStagger;
|
||||
|
||||
[Min(0f)]
|
||||
public float StaggerDuration;
|
||||
|
||||
public MMF_Player OpenFeedback;
|
||||
public MMF_Player CloseFeedback;
|
||||
public Color HighlightColor;
|
||||
|
||||
public bool ActivateWeakPointHurtBox => WeakPointType != WeakPointType.FullBody;
|
||||
}
|
||||
|
||||
// ── PlayerCounterResponse ─────────────────────────────────────────────────
|
||||
|
||||
public enum CounterType
|
||||
{
|
||||
Parry,
|
||||
PerfectParry,
|
||||
DodgeThrough,
|
||||
SpecificSkill,
|
||||
WeakPointHit,
|
||||
HazardBackfire,
|
||||
SummonKill,
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct PlayerCounterResponse
|
||||
{
|
||||
[Header("反制条件")]
|
||||
public CounterType counterType;
|
||||
public string requiredSkillId;
|
||||
|
||||
[Header("反制效果(对 Boss)")]
|
||||
public float bossStaggerDuration;
|
||||
public float bossDamageBonus;
|
||||
public bool openVulnWindow;
|
||||
public bool interruptSkill;
|
||||
|
||||
[Header("反制收益(对玩家)")]
|
||||
public int soulPowerGrant;
|
||||
public int spiritPowerGrant;
|
||||
public MMF_Player counterFeedback;
|
||||
}
|
||||
|
||||
// ── ArenaEvent ────────────────────────────────────────────────────────────
|
||||
|
||||
public enum ArenaEventType
|
||||
{
|
||||
DestroyPlatform,
|
||||
ActivateHazard,
|
||||
DeactivateHazard,
|
||||
SpawnHazardArea,
|
||||
ShakeArena,
|
||||
ToggleLighting,
|
||||
SpawnPlatform,
|
||||
TriggerCutscene,
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct ArenaEventParams
|
||||
{
|
||||
public float duration;
|
||||
public float intensity;
|
||||
public bool revertsOnPhaseEnd;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct ArenaEventTrigger
|
||||
{
|
||||
public string targetArenaObjectId;
|
||||
public ArenaEventType eventType;
|
||||
public float delay;
|
||||
public ArenaEventParams parameters;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct ArenaEventData
|
||||
{
|
||||
public ArenaEventType type;
|
||||
public ArenaEventParams parameters;
|
||||
public string sourceSkillId;
|
||||
}
|
||||
|
||||
public interface IArenaInteractable
|
||||
{
|
||||
string ArenaObjectId { get; }
|
||||
void OnBossArenaEvent(ArenaEventData data);
|
||||
}
|
||||
|
||||
// ── BossResourceCost ──────────────────────────────────────────────────────
|
||||
|
||||
[Serializable]
|
||||
public struct BossResourceCost
|
||||
{
|
||||
public string resourceId;
|
||||
public float cost;
|
||||
public float minRequired;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Enemies/Boss/BossSkillTypes.cs.meta
Normal file
11
Assets/Scripts/Enemies/Boss/BossSkillTypes.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a1beb8f8f7958b84c9ab60abe5f8c4ed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
50
Assets/Scripts/Enemies/Boss/Patterns/TelegraphSystem.cs
Normal file
50
Assets/Scripts/Enemies/Boss/Patterns/TelegraphSystem.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using BaseGames.Core;
|
||||
using BaseGames.Core.Pool;
|
||||
|
||||
namespace BaseGames.Enemies.Boss.Patterns
|
||||
{
|
||||
/// <summary>
|
||||
/// 攻击预警系统(架构 07_EnemyModule §11)。
|
||||
/// 在攻击前若干帧显示视觉提示(VFX 从对象池取出,到期归还)。
|
||||
/// 由 BD_TelegraphAttack 通过协程调用 ShowTelegraph。
|
||||
/// </summary>
|
||||
public class TelegraphSystem : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// 开始预警:从对象池取出 vfxKey 对应预警 VFX,等待 duration 秒后归还。
|
||||
/// 由 BD_TelegraphAttack.OnStart 通过 StartCoroutine 调用。
|
||||
/// </summary>
|
||||
public IEnumerator ShowTelegraph(string vfxKey, float duration, Vector2 position)
|
||||
{
|
||||
if (string.IsNullOrEmpty(vfxKey) || duration <= 0f)
|
||||
{
|
||||
yield return null;
|
||||
yield break;
|
||||
}
|
||||
|
||||
GameObject vfx = null;
|
||||
var pool = ServiceLocator.GetOrDefault<IObjectPoolService>();
|
||||
if (pool != null)
|
||||
vfx = pool.Spawn(vfxKey, new Vector3(position.x, position.y, 0f), Quaternion.identity);
|
||||
else
|
||||
Debug.LogWarning($"[TelegraphSystem] IObjectPoolService 未就绪,预警 VFX '{vfxKey}' 无法显示。");
|
||||
|
||||
yield return new WaitForSeconds(duration);
|
||||
|
||||
if (vfx != null && pool != null)
|
||||
{
|
||||
var po = vfx.GetComponent<PooledObject>();
|
||||
if (po != null) po.ReturnToPool();
|
||||
else vfx.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>立即隐藏所有活跃预警 VFX(技能被打断时调用)。</summary>
|
||||
public void CancelTelegraph()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Enemies/Boss/Patterns/TelegraphSystem.cs.meta
Normal file
11
Assets/Scripts/Enemies/Boss/Patterns/TelegraphSystem.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6f4987894dfe1648909b6863c003c31
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
26
Assets/Scripts/Enemies/Boss/SkillSequenceSO.cs
Normal file
26
Assets/Scripts/Enemies/Boss/SkillSequenceSO.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BaseGames.Boss
|
||||
{
|
||||
/// <summary>
|
||||
/// 有序攻击序列(一个技能内的多段连段)。
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Boss/SkillSequence")]
|
||||
public class SkillSequenceSO : ScriptableObject
|
||||
{
|
||||
[Serializable]
|
||||
public struct SequenceStep
|
||||
{
|
||||
public AttackPatternSO pattern;
|
||||
[Min(0f)] public float delayBeforeStep;
|
||||
}
|
||||
|
||||
public SequenceStep[] steps;
|
||||
|
||||
[Header("序列完成后的行为")]
|
||||
public bool RepeatIfPlayerInRange;
|
||||
[Min(0f)] public float RepeatDelay;
|
||||
[Range(0, 10)] public int MaxRepeatCount;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Enemies/Boss/SkillSequenceSO.cs.meta
Normal file
11
Assets/Scripts/Enemies/Boss/SkillSequenceSO.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab2ec01e225283d4face08cef0d72c87
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
51
Assets/Scripts/Enemies/Boss/WeakPointSystem.cs
Normal file
51
Assets/Scripts/Enemies/Boss/WeakPointSystem.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using UnityEngine;
|
||||
using BaseGames.Combat;
|
||||
using BaseGames.Core.Events;
|
||||
|
||||
namespace BaseGames.Boss
|
||||
{
|
||||
/// <summary>
|
||||
/// 管理 Boss 的专属弱点 HurtBox(如核心、眼睛等)。
|
||||
/// 弱点激活期间受到的伤害会乘以 DamageMultiplier。
|
||||
/// </summary>
|
||||
public class WeakPointSystem : MonoBehaviour
|
||||
{
|
||||
[System.Serializable]
|
||||
public struct WeakPoint
|
||||
{
|
||||
public HurtBox hurtBox;
|
||||
public GameObject visualIndicator;
|
||||
}
|
||||
|
||||
[SerializeField] private WeakPoint[] _weakPoints;
|
||||
[SerializeField] private string _bossId;
|
||||
[SerializeField] private StringEventChannelSO _onVulnerabilityWindowOpened;
|
||||
|
||||
private float _damageMultiplier = 1f;
|
||||
|
||||
/// <summary>激活或关闭弱点 HurtBox 及视觉指示器。</summary>
|
||||
/// <param name="active">是否激活。</param>
|
||||
/// <param name="multiplier">激活时的受击伤害乘数。</param>
|
||||
/// <param name="activateSpecific">true = 仅激活弱点专属 HurtBox;false = 全身视为弱点(不改变 HurtBox 状态)。</param>
|
||||
public void SetActive(bool active, float multiplier = 1f, bool activateSpecific = false)
|
||||
{
|
||||
_damageMultiplier = active ? multiplier : 1f;
|
||||
|
||||
if (activateSpecific)
|
||||
{
|
||||
foreach (var wp in _weakPoints)
|
||||
{
|
||||
wp.hurtBox.gameObject.SetActive(active);
|
||||
if (wp.visualIndicator != null)
|
||||
wp.visualIndicator.SetActive(active);
|
||||
}
|
||||
}
|
||||
|
||||
if (active)
|
||||
_onVulnerabilityWindowOpened?.Raise(_bossId);
|
||||
}
|
||||
|
||||
/// <summary>弱点 HurtBox 受击时,由 BossStats 调用此方法获取最终伤害系数。</summary>
|
||||
public float GetDamageMultiplier() => _damageMultiplier;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Enemies/Boss/WeakPointSystem.cs.meta
Normal file
11
Assets/Scripts/Enemies/Boss/WeakPointSystem.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96ffe91642a6ccc4ea4c6076d80f5e27
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user