using System; using UnityEngine; public class KillUntilDieData : HeroAI_Data { public uint targetServerInstID; public int defaultSkillID; } /// /// 执行普攻攻击致死的AI逻辑 /// public class HeroAI_KillUntilDie : HeroAI_Base { private uint m_TargetID; private int m_FirstSkill; private float m_LastUseSkillTime; private bool m_LimitOnce; private bool m_ActiveInterrupt; private bool m_IsMovingToTarget; public override bool Condition() { GA_Hero _hero = PlayerDatas.Instance.hero; if (_hero == null) { return false; } if (_hero.aiHandler.currentType == E_HeroAIType.KillUntilDie) { return true; } return false; } public override void Enter() { m_IsMovingToTarget = false; m_FirstSkill = -1; m_TargetID = 0; m_LimitOnce = false; m_ActiveInterrupt = false; GA_Hero _hero = PlayerDatas.Instance.hero; if (_hero == null) { return; } byte _type = (byte)E_HeroAIType.KillUntilDie; KillUntilDieData _data = _hero.aiHandler.aiData[_type] as KillUntilDieData; m_TargetID = _data.targetServerInstID; m_FirstSkill = _data.defaultSkillID; UserInputHandler.OnCirclePanelTouched += OnActiveInterrupt; UserInputHandler.OnClickedFloor += OnClickFloor; HeroBehaviour.OnUserClickSkill += OnUserClickSkill; GA_Hero.OnLockTargetChanged += OnLockTargetChanged; HeroBehaviour.OnStartHandupAI += OnStartHandupAI; MapTransferUtility.s_OnHeroStartMoveToNPC += OnStartMoveToNpc; } private void OnStartMoveToNpc() { GA_Hero _hero = PlayerDatas.Instance.hero; if (_hero != null) { _hero.aiHandler.currentType = E_HeroAIType.None; } m_LimitOnce = true; } private void OnStartHandupAI() { m_LimitOnce = true; } private void OnLockTargetChanged(uint sid) { m_TargetID = sid; } private void OnUserClickSkill(int skillID) { GActor _target = GAMgr.Instance.GetBySID(m_TargetID); if (_target != null && !_target.ActorInfo.serverDie) { m_FirstSkill = skillID; } } public override void Update() { if (!DTC0403_tagPlayerLoginLoadOK.finishedLogin) { return; } GA_Hero _hero = PlayerDatas.Instance.hero; if (_hero == null || _hero.ActorInfo.serverDie || !_hero.CanCastSkill() || !_hero.CanCommonAtk()) { return; } // 这里需要实时取对象, 因为视野可能导致对象回收 GActorFight _target = GAMgr.Instance.GetBySID(m_TargetID) as GActorFight; // 对象是否还存在且为可攻击状态 if (_target == null) { m_TargetID = 0; _hero.aiHandler.currentType = E_HeroAIType.None; _hero.StopRush(); } // 攻击间隔中 if (Time.time - m_LastUseSkillTime < (1f / _hero.ActorInfo.atkSpeed) * .8f) { return; } Skill _skill = _hero.SkillMgr.CurCastSkill; // 判断主角当前是否有技能尚未释放完毕 if (_skill != null) { // 如果是蓄力技能, 判断是否蓄力完毕 if (!_skill.SkillCompelete) { if (_skill.skillInfo.config.CastTime > 0) { if (_skill.CSkillPrepareEnd && _hero.SkillMgr.DoingPrepareSkill) { _hero.Behaviour.DoAttack(_skill); _hero.SkillMgr.DoingPrepareSkill = false; } } return; } if (_hero.SkillMgr.DoingPrepareSkill) { return; } } // 确定要使用的技能 // 是否存在预设定的技能 if (m_FirstSkill > 0) { _skill = _hero.SkillMgr.Get(m_FirstSkill); } else { int _index = _hero.nextComAtkIndex; if (_index == -1) { _index = 0; } int _comSkillID = _hero.GetCommonSkillID(_index); _skill = _hero.SkillMgr.Get(_comSkillID); } if (_skill == null || !_skill.IsValid()) { m_FirstSkill = -1; _skill = null; return; } bool _forceMove = _skill.skillInfo.soFile != null && _skill.skillInfo.soFile.forceMove; if (_target == null || (!_forceMove && !_hero.IsRushing // 不处于移动至目标 && !IsSkillNeedMove(_skill.skillInfo.config.Tag, (E_SkillType)_skill.skillInfo.config.SkillType))) { _hero.Behaviour.DoAttack(_skill); m_LimitOnce = true; } else { // 判断技能范围, 不在可释放范围需要移动至目标 float _compareDist = _skill.skillInfo.config.AtkDist * .5f; if (!PreFightMission.Instance.IsFinished()) { _compareDist -= 1; if (_compareDist < 0) { _compareDist = 0; } } float _compareDistSqrt = _compareDist * _compareDist; // 计算当前和目标的距离 Vector3 _dest = _target.Pos; PathFinder.TryGetValidDest(_hero.Pos, _target.Pos, ref _dest); float _currentDistSqrt = MathUtility.DistanceSqrtXZ(_hero.Pos, _dest); // 比较距离 if (_currentDistSqrt >= _compareDistSqrt) { if (StatusMgr.IsValid() && !StatusMgr.Instance.CanMove(_hero.ServerInstID)) { return; } // 移动至目标 _hero.MoveToTarget(_target, _compareDist); // 判断是否需要冲锋 if (_hero.IsNeedRush(_currentDistSqrt)) { _hero.StartRush(); } m_IsMovingToTarget = true; if (!_hero.IsRushing && UserInputHandler.isTouched) { m_LimitOnce = true; _hero.StopPathFind(); } return; } // 停止冲锋逻辑 _hero.StopRush(); Vector3 _forward = MathUtility.ForwardXZ(_target.Pos, _hero.Pos); _hero.destForward = _hero.Forward = _forward; if (m_FirstSkill != -1 && !_hero.Behaviour.IsComAtk(m_FirstSkill)) { _hero.Behaviour.DoAttack(_skill); m_LimitOnce = true; } else { _hero.Behaviour.DoCommonAttack(); m_LimitOnce = true; } } // 置空技能 m_FirstSkill = -1; #if UNITY_EDITOR if (RuntimeLogUtility.s_PerpetualAttack == false) { _hero.aiHandler.currentType = E_HeroAIType.None; } #endif } public override void Exit() { UserInputHandler.OnCirclePanelTouched -= OnActiveInterrupt; UserInputHandler.OnClickedFloor -= OnClickFloor; HeroBehaviour.OnUserClickSkill -= OnUserClickSkill; GA_Hero.OnLockTargetChanged -= OnLockTargetChanged; HeroBehaviour.OnStartHandupAI -= OnStartHandupAI; MapTransferUtility.s_OnHeroStartMoveToNPC -= OnStartMoveToNpc; m_FirstSkill = -1; m_TargetID = 0; GA_Hero _hero = PlayerDatas.Instance.hero; if (_hero != null) { _hero.StopRush(); } } public override bool IsOver() { GA_Hero _hero = PlayerDatas.Instance.hero; GActorFight _target = GAMgr.Instance.GetBySID(m_TargetID) as GActorFight; // if (_target == null || !_target.CanAtked()) // { // Debug.Log("目标已死亡或者不可被攻击"); // } // if (PlayerDatas.Instance.hero == null) // { // Debug.Log("主角被销毁"); // } // if (m_ActiveInterrupt) // { // Debug.Log("行为被打断"); // } // if (_hero.aiHandler.currentType != E_HeroAIType.KillUntilDie) // { // Debug.Log("已切换ai行为"); // } // if (m_LimitOnce) // { // Debug.Log("释放过一次技能"); // } return (_target == null || !_target.CanAtked() || m_ActiveInterrupt || _hero == null || _hero.aiHandler.currentType != E_HeroAIType.KillUntilDie) && (m_LimitOnce || MapArea.IsInMapArea(_hero.CurMapArea, MapArea.E_Type.Safe) || MapArea.IsInMapArea(_hero.CurMapArea, MapArea.E_Type.RebornSafe)); } private void OnActiveInterrupt() { m_ActiveInterrupt = true; GA_Hero _hero = PlayerDatas.Instance.hero; if (_hero != null && m_FirstSkill < 0) { _hero.aiHandler.currentType = E_HeroAIType.None; } } private void OnClickFloor(Vector3 dest) { m_ActiveInterrupt = true; GA_Hero _hero = PlayerDatas.Instance.hero; if (_hero != null) { _hero.aiHandler.currentType = E_HeroAIType.None; } } }