- Implemented HurtBoxOwnerGuard to ensure that multiple HurtBoxes on the same character do not register damage multiple times during a single HitBox activation. - Added custom editor for HitBox to facilitate the creation of shape colliders with HitBoxColliderProxy. - Introduced PhysicsPerceptionSystem for enemy perception, supporting multiple detection modes including RangeCircle, BatchLOS, FanCast, and BoxCast. - Created EnemyPatrolZone to define patrol and chase areas for enemies, allowing for shared zones among multiple enemies. - Added BD_IsOutsideZone conditional task for Behavior Designer to check if an enemy or player is outside a defined patrol zone.
64 lines
2.0 KiB
C#
64 lines
2.0 KiB
C#
using System.Collections;
|
||
using Animancer;
|
||
using UnityEngine;
|
||
|
||
namespace BaseGames.Enemies.Abilities
|
||
{
|
||
/// <summary>
|
||
/// 循环追击 + 体接触伤害能力。
|
||
/// 追击期间每帧更新 MoveTo,失去感知后收招退出并恢复巡逻状态。
|
||
/// 可复用于任何需要"追击+接触伤害循环"的敌人。
|
||
/// </summary>
|
||
public class ContactChaseAbility : EnemyAbilityBase
|
||
{
|
||
[Header("动画")]
|
||
[SerializeField] private ClipTransition _loopClip;
|
||
[SerializeField] private ClipTransition _endClip;
|
||
|
||
[Header("感知与接触伤害")]
|
||
[SerializeField] private BodyContactDamage _contactDamage;
|
||
|
||
[Tooltip("用于追击感知判断的传感器槽位名,通常为 \"aggro\"")]
|
||
[SerializeField] private string _aggroSlotName = "aggro";
|
||
|
||
protected override IEnumerator ExecuteCoroutine()
|
||
{
|
||
Phase = AbilityRunState.Active;
|
||
|
||
if (_loopClip.Clip != null)
|
||
_animancer.Play(_loopClip);
|
||
|
||
if (_contactDamage != null)
|
||
_contactDamage.enabled = true;
|
||
|
||
while (true)
|
||
{
|
||
if (_enemy.PlayerTransform == null) break;
|
||
if (_enemy.SensorHub != null && !_enemy.SensorHub.IsDetecting(_aggroSlotName, _enemy.PlayerTransform.gameObject))
|
||
break;
|
||
_enemy.MoveTo(_enemy.PlayerTransform.position);
|
||
yield return null;
|
||
}
|
||
|
||
if (_contactDamage != null)
|
||
_contactDamage.enabled = false;
|
||
|
||
_enemy.StopMovement();
|
||
|
||
if (_endClip.Clip != null)
|
||
{
|
||
_animancer.Play(_endClip);
|
||
yield return EnemyAbilityWaits.Get(_endClip.Clip.length);
|
||
}
|
||
|
||
_enemy.SetAiPhase(AiPhase.Patrol);
|
||
}
|
||
|
||
protected override void OnInterrupted(InterruptReason reason)
|
||
{
|
||
if (_contactDamage != null)
|
||
_contactDamage.enabled = false;
|
||
}
|
||
}
|
||
}
|