Files
vampire-like/Assets/GameMain/Scripts/Runtime/EntityLogic/Enemy/MeleeEnemy.cs
T
2026-09-15 11:07:01 +08:00

154 lines
4.5 KiB
C#

using SepCore.CustomUtility;
using SepCore.Definition;
using UnityEngine;
namespace SepCore.Entity
{
public class MeleeEnemy : EnemyBase
{
private float _sqrAttackRange;
private EnemyStateType enemyState = EnemyStateType.Idle;
private TargetableObject _targetableTarget;
#region Lifecycle
protected override void OnShow(object userData)
{
base.OnShow(userData);
_sqrAttackRange = AttackRange * AttackRange;
enemyState = EnemyStateType.Idle;
_targetableTarget = null;
}
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(elapseSeconds, realElapseSeconds);
UpdateAttackState(elapseSeconds);
}
protected override void OnHide(bool isShutdown, object userData)
{
_targetableTarget = null;
enemyState = EnemyStateType.Idle;
base.OnHide(isShutdown, userData);
}
#endregion
public override void SetTarget(Transform target)
{
base.SetTarget(target);
_targetableTarget = target != null ? target.GetComponent<TargetableObject>() : null;
}
private void UpdateAttackState(float elapseSeconds)
{
switch (enemyState)
{
case EnemyStateType.Idle:
Movement.SetMove(false);
if (HasValidTarget())
{
TransitionTo(EnemyStateType.Seek);
}
break;
case EnemyStateType.Seek:
if (!HasValidTarget())
{
TransitionTo(EnemyStateType.Idle);
return;
}
if (IsTargetInRange())
{
TransitionTo(EnemyStateType.Chase);
return;
}
Movement.SetMove(true);
Movement.SetDirection(GetTargetDirection());
break;
case EnemyStateType.Chase:
if (!HasValidTarget())
{
TransitionTo(EnemyStateType.Idle);
return;
}
Movement.SetMove(false);
if (!IsTargetInRange())
{
TransitionTo(EnemyStateType.Seek);
return;
}
if (_canAttack)
{
ResetAttackCooldown(AttackCooldown);
TransitionTo(EnemyStateType.Attack);
}
break;
}
}
private void TransitionTo(EnemyStateType newState)
{
enemyState = newState;
if (enemyState == EnemyStateType.Chase)
{
Movement.SetMove(false);
}
if (enemyState == EnemyStateType.Attack)
{
Movement.SetMove(false);
ExecuteAttack();
TransitionTo(EnemyStateType.Chase);
}
}
private bool HasValidTarget()
{
if (_target == null) return false;
if (_targetableTarget == null || _targetableTarget.CachedTransform != _target)
{
_targetableTarget = _target.GetComponent<TargetableObject>();
}
return _targetableTarget != null && _targetableTarget.Available && !_targetableTarget.IsDead;
}
private bool IsTargetInRange()
{
if (_target == null) return false;
Vector3 delta = _target.position - CachedTransform.position;
delta.y = 0f;
return delta.sqrMagnitude <= _sqrAttackRange;
}
private void ExecuteAttack()
{
if (!HasValidTarget() || !IsTargetInRange()) return;
ImpactData targetImpactData = _targetableTarget.GetImpactData();
ImpactData selfImpactData = GetImpactData();
if (AIUtility.GetRelation(selfImpactData.Camp, targetImpactData.Camp) == RelationType.Friendly)
{
return;
}
int damage = AIUtility.CalcDamageHP(AttackDamage, null, targetImpactData.DefenseStat,
targetImpactData.DodgeStat);
_targetableTarget.ApplyDamage(this, damage);
}
}
}