Files
daluandou/Assets/Scripts/系统脚本/StatusEffectController.cs
T
huadexuan 8cbe8e000b ```
feat(ArcherSkill): 弓箭手技能重构为阶梯体系支持1/3/6/10级完整升级

- 实现迅捷三连技能,支持1级基础3箭、10级升级为6支风暴连射
- 添加弱点锁定机制,6级后伤害逐箭递增且最后一箭必暴击
- 集成破甲易伤标记系统,使目标受到伤害增加30%持续4秒
- 优化技能释放逻辑,支持目标死亡后自动切换最近敌人
- 完善技能平衡性调整,3级箭矢速度提升35%总伤害增加25%

feat(StatusEffectController): 新增易伤状态管理系统

- 添加vulnerability相关属性和ApplyVulnerability方法
- 实现易伤效果的生命周期管理和伤害计算
- 集成到UnitBase的伤害结算流程中

docs: 更新角色技能说明文档支持新技能体系

- 将原弓箭猎人重命名为荒野猎手,更新技能描述
- 同步更新角色与技能对应关系表格
- 调整技能名称从穿透箭改为穿心猎矛等新命名
```
2026-10-13 19:33:54 +08:00

178 lines
4.7 KiB
C#

using UnityEngine;
public class StatusEffectController : MonoBehaviour
{
[Header("通用眩晕显示")]
[SerializeField] private bool showStunIndicator = true;
[SerializeField] private float indicatorHeight = 0.35f;
[SerializeField] private GameObject stunIndicatorPrefab;
private Animator animator;
private float stunnedRemaining;
private float animatorSpeedBeforeStun = 1f;
private GameObject stunIndicator;
private Transform indicatorTransform;
public bool IsStunned => stunnedRemaining > 0f;
public float StunnedRemaining => Mathf.Max(0f, stunnedRemaining);
/// <summary>是否处于眩晕免疫/霸体状态</summary>
public bool isStunImmune = false;
[Header("易伤状态")]
private float vulnerabilityRemaining = 0f;
private float vulnerabilityRatio = 0f;
public bool HasVulnerability => vulnerabilityRemaining > 0f;
public float VulnerabilityRatio => vulnerabilityRemaining > 0f ? vulnerabilityRatio : 0f;
/// <summary>
/// 施加破甲/易伤标记:使目标在持续时间内受到的所有伤害增加指定比例
/// </summary>
public void ApplyVulnerability(float duration, float ratio)
{
if (duration <= 0f || ratio <= 0f) return;
vulnerabilityRemaining = Mathf.Max(vulnerabilityRemaining, duration);
vulnerabilityRatio = Mathf.Max(vulnerabilityRatio, ratio);
}
private void Awake()
{
animator = GetComponent<Animator>();
}
public void ApplyStun(float duration)
{
if (duration <= 0f || isStunImmune)
{
return;
}
if (!IsStunned && animator != null)
{
animatorSpeedBeforeStun = animator.speed;
}
stunnedRemaining = Mathf.Max(stunnedRemaining, duration);
if (animator != null)
{
animator.speed = 0f;
}
if (showStunIndicator)
{
EnsureIndicator();
}
}
private void Update()
{
if (vulnerabilityRemaining > 0f)
{
vulnerabilityRemaining -= Time.deltaTime;
if (vulnerabilityRemaining <= 0f)
{
vulnerabilityRemaining = 0f;
vulnerabilityRatio = 0f;
}
}
if (!IsStunned)
{
return;
}
stunnedRemaining -= Time.deltaTime;
if (animator != null)
{
animator.speed = 0f;
}
if (stunnedRemaining <= 0f)
{
stunnedRemaining = 0f;
if (animator != null)
{
UnitBase unitBase = GetComponent<UnitBase>();
animator.speed = unitBase != null
? Mathf.Max(0.01f, unitBase.AttackSpeedMultiplier)
: 1f;
}
DestroyIndicator();
}
}
private void LateUpdate()
{
if (stunIndicator == null || !IsStunned)
{
return;
}
Bounds bounds = new Bounds(transform.position, Vector3.zero);
Renderer[] renderers = GetComponentsInChildren<Renderer>(true);
bool hasRenderer = false;
foreach (Renderer renderer in renderers)
{
if (stunIndicator != null && renderer.transform.IsChildOf(stunIndicator.transform))
{
continue;
}
if (!hasRenderer)
{
bounds = renderer.bounds;
hasRenderer = true;
}
else
{
bounds.Encapsulate(renderer.bounds);
}
}
if (!hasRenderer)
{
bounds = new Bounds(transform.position, Vector3.zero);
}
indicatorTransform.position = new Vector3(
bounds.center.x,
bounds.max.y + indicatorHeight,
bounds.center.z);
}
private void EnsureIndicator()
{
if (stunIndicator != null || stunIndicatorPrefab == null)
{
return;
}
stunIndicator = Instantiate(stunIndicatorPrefab, transform);
stunIndicator.name = "StunIndicator_Particle";
indicatorTransform = stunIndicator.transform;
}
private void DestroyIndicator()
{
if (stunIndicator != null)
{
ParticleSystem[] particleSystems = stunIndicator.GetComponentsInChildren<ParticleSystem>(true);
foreach (ParticleSystem particleSystem in particleSystems)
{
particleSystem.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
}
Destroy(stunIndicator);
}
stunIndicator = null;
indicatorTransform = null;
}
private void OnDestroy()
{
DestroyIndicator();
}
}