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() : 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(); } 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); } } }