using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using ActionGameFramework.Health; using Core.Health; using Core.Utilities; using DG.Tweening; using KTGMGemClient; using TMPro.Examples; using TowerDefense.Affectors; using TowerDefense.Agents.Data; using TowerDefense.Economy; using TowerDefense.Level; using TowerDefense.Nodes; using UnityEngine; using UnityEngine.AI; namespace TowerDefense.Agents { // 预计算移动的方位. public enum EAgentMovDir { Start, XPositive, XNegative, ZPositive, ZNegative, End } /// /// 每一个Agent发布到场景内时设置的数据 /// public struct AgentSetData { public float speed; public float hp; } /// /// An agent will follow a path of nodes /// NavMeshAgent和AttackAffector是必须得加入的EntityNode. /// [RequireComponent(typeof(NavMeshAgent)), RequireComponent(typeof(AttackAffector))] public abstract class Agent : Targetable { /// /// A means of keeping track of the agent along its path /// public enum State { /// /// When the agent is on a path that is not blocked /// OnCompletePath, /// /// When the agent is on a path is blocked /// OnPartialPath, /// /// When the agent has reached the end of a blocked path /// Attacking, /// /// For flying agents, when they move over obstacles /// PushingThrough, /// /// When the agent has completed their path /// PathComplete } /// /// Event fired when agent reached its final node /// public event Action destinationReached; /// /// Position offset for an applied affect /// 这个主要是用于AgentEffect相关的类,给当前的Agent加相关的效果,移动变慢,加速等等。 /// public Vector3 appliedEffectOffset = Vector3.zero; /// /// Scale adjustment for an applied affect /// 加强效果对应的Scale数据 /// public float appliedEffectScale = 1; /// /// 当前的Agent对应的healthBar. /// public HealthVisualizer healthBar; /// /// 如果不为空,则播放当前的particle. /// public ParticleSystem spawnParticle; public AgentSetData mAgentData; //public Textur /// /// The NavMeshAgent component attached to this /// 这个,Unity内比较核心的类 /// protected NavMeshAgent m_NavMeshAgent; /// /// The Current node that the agent must navigate to /// protected Node m_CurrentNode; /// /// 修改当前的NavMeshAgent移动模式,修改为纯手动移动 /// protected Node m_NextNode; /// /// 记录初始化的位置和Node,用于重设当前Agent的位置 /// protected Node initNode; protected Vector3 initPos; /// /// Reference to the level manager /// protected LevelManager m_LevelManager; protected EndlessLevelManager endlessLevelManager; /// /// Stores the Destination to the next node so we don't need to get new random positions every time /// protected Node m_Destination; /// /// 每次移动从SrcPosition到m_Destination. /// protected Vector3 m_SrcPosition; /// /// 每次切换Node,都会重新计算移动方向,用于中间状态时,更快速的计算移动数据。 /// protected EAgentMovDir moveDir; /// /// 移动速度,暂时从navMeshAgent中获取. /// protected float fMoveSpeed; protected float MoveStopTime = 0.0f; protected ParticleSystem MoveStopEffect = null; /// /// 距离目标的最终距离. /// protected float m_DisToDestination; /// /// 当前Agent的默认Scale数据 /// protected Vector3 mDefaultScale; /// /// 当前小怪对应的掉落数据 /// protected LootDrop mLootDrop; /// /// 每一个Node加一个超长距离值 /// protected readonly float NODE_DIS = 1000f; /// /// 当前Agent的开始Yval,用于标注层级显示. /// protected float mStartYVal; protected float mStartZVal; /// /// 动画器. /// public Animator ActionAnimator; protected AnimationClip[] clips; protected bool bInDeathAct = false; /// /// 原地罚站 /// /// public bool CanMove { get; set; } = true; /// /// Gets the attached nav mesh agent velocity /// public override Vector3 velocity { get { return m_NavMeshAgent.velocity; } } public bool bInDeathState { get { return this.bInDeathAct; } set { bInDeathAct = value; } } /// /// 是否是可再生的怪物类型 /// public bool bRespawn { get; set; } /// /// The current state of the agent along the path /// public State state { get; protected set; } /// /// 当前Agent对应到的兵线ID. /// public int waveLineID { get; set; } public NavMeshAgent navMeshAgent { get { return this.m_NavMeshAgent; } } /// /// 是否显示目标位置信息 /// public bool bShowDebugNode = false; /// /// 持续寻路,起到寻路成功 /// protected bool nodeMoveUpdate = false; /// /// 代理的类型 /// public SpawnAgentType AgentType { get; set; } = SpawnAgentType.Normal; /// /// 无尽模式小怪对应 endless_enemy表中数据 /// public endless_enemy EnemyData { get; set; } /// /// Accessor to /// public NavMeshAgent navMeshNavMeshAgent { get { return m_NavMeshAgent; } set { m_NavMeshAgent = value; } } public float distanceToDest { get { return this.m_DisToDestination; } } /// /// The area mask of the attached nav mesh agent /// public int navMeshMask { get { return m_NavMeshAgent.areaMask; } } /// /// Gets this agent's original movement speed /// public float originalMovementSpeed { get; protected set; } /// /// 小怪的动作状态 /// public AgentActionState ActionState { get; protected set; } private string paramName = "AgentActionState"; /// /// 更新怪物的移动速度。 /// /// public void SetMoveSpeedScale(float fscale) { fMoveSpeed = fMoveSpeed * fscale; } /// /// 动态设置Agent的血量数据. /// /// 设置当前小怪的血量. /// 设置当前小怪的移动速度 /// 设置当前小怪的金币掉落数据 public void SetAgentData(float health, float moveSpeed = -1, int coinDrop = 0) { this.configuration.maxHealth = health; this.configuration.startingHealth = health; this.configuration.SetMaxHealth(health); this.configuration.Init(); this.configuration.SetHealth(health); // 只有在速度大于零的情况下才会设置. if (moveSpeed > 0) fMoveSpeed = moveSpeed; // 金币掉落大于零. if (coinDrop > 0) mLootDrop.lootDropped = coinDrop; mAgentData.speed = fMoveSpeed; mAgentData.hp = this.configuration.maxHealth; // mStartYVal = this.transform.position.y; mStartZVal = this.transform.position.z; // 确保设置成默认白色纹理: this.SetTargetableMatColor(Color.white, true); speedSlowRate = 0.0f; poisonHurt = 0; poisonAttid = 0; poisonTimes = 0; timeToPoisonHurt = 0; bShieldBreak = false; CanMove = true; /*// 如果对应的粒子不为空,则播放 if( spawnParticle) { ParticleSystem tpar = Instantiate(spawnParticle); tpar.transform.localScale = new Vector3(1.5f, 1.5f, 1.5f); tpar.transform.position = this.transform.position; tpar.Simulate(0.0f); tpar.Play(); }*/ // if (healthBar) // healthBar.bOpponent = opponentAgent; } /// /// Checks if the path is blocked /// /// /// The status of the agent's path /// protected virtual bool isPathBlocked { get { return m_NavMeshAgent.pathStatus == NavMeshPathStatus.PathPartial; } } /// /// Is the Agent close enough to its destination? /// protected virtual bool isAtDestination { get { return navMeshNavMeshAgent.remainingDistance <= navMeshNavMeshAgent.stoppingDistance; } } /// /// 改变m_NextNode,因为要切换基地 /// /// public void ChangeNextNode(Node node) { m_NextNode = node; } /// /// Sets the node to navigate to /// /// The node that the agent will navigate to public virtual void SetNode(Node node, int lineid) { if (lineid >= 0) waveLineID = lineid; // 设置为空的时候,是为了不再每一帧更新Agent的位置信息 if (node == null) { m_CurrentNode = null; m_NextNode = null; return; } if (m_CurrentNode == null) { initNode = node; } m_CurrentNode = node; // 需要设置移动的目标Node. m_NextNode = m_CurrentNode.GetNextNode(); this.MoveToNode(); } /// /// 处理Agent的锁定Buf,播放特效,设置速度为零,并时间到达后重设数据。 /// /// protected virtual void SetAgentStopBuff(buffinfo binfo) { MoveStopTime = binfo.last / 1000; if (!isFrost) { isFrost = true; if (FrostParticle != null) FrostParticle.Play(); } } /// /// 设置当前Agent对应的各种技能属性ID. /// /// public void SetAgentBuffEffect(int buffid) { buffinfo bufdata = JsonDataCenter.GetBuffFromId(buffid); if (bufdata == null) return; if (bufdata.buff_func[0] == 3) { SetAgentStopBuff(bufdata); } else return; } public override bool isAgent() { return true; } /// /// Stops the navMeshAgent and attempts to return to pool /// public override void Remove() { // 统一管理器内删除当前的Agent: AgentInsManager.instance.removeAgent(this); EventCenter.Ins.BroadCast((int)KTGMGemClient.EventType.EndlessAgentDead, this); base.Remove(); if (m_LevelManager) m_LevelManager.DecrementNumberOfEnemies(); else endlessLevelManager.DecrementNumberOfEnemies(); if (m_NavMeshAgent.enabled) { m_NavMeshAgent.isStopped = true; } m_NavMeshAgent.enabled = false; // 必须要重置数据,不然会有一系列的小Bug. this.m_CurrentNode = null; m_NextNode = null; this.liveID = this.liveID + 1; speedSlowRate = 0.0f; poisonHurt = 0; poisonAttid = 0; poisonTimes = 0; timeToPoisonHurt = 0; isFrost = false; bShieldBreak = false; bInDeathAct = false; ChangeState(AgentActionState.Move); configuration.ClearShieldWall(); StopFrostParticle(); //this.SetTargetableMatColor(Color.white); // 删除当前停止特效和状态. if (MoveStopTime > 0) MoveStopTime = 0.0f; // 停止DoTween动画. this.transform.DOKill(); Poolable.TryPool(gameObject); } private void StopFrostParticle() { if (FrostParticle != null) FrostParticle.Stop(); } /// /// Setup all the necessary parameters for this agent from configuration data /// public virtual void Initialize() { ResetPositionData(); LazyLoad(); configuration.SetHealth(configuration.maxHealth); state = isPathBlocked ? State.OnPartialPath : State.OnCompletePath; // River TEST CODE TO DELETE: 测试成功之后,是需要删除navMeshAgent组件的,根本不需要 m_NavMeshAgent.enabled = false; if (m_LevelManager) m_LevelManager.IncrementNumberOfEnemies(); else endlessLevelManager.IncrementNumberOfEnemies(); // // 设置一个DOTween队列,让场景内刷出来的Agent有一个变大淡出的效果,此时是无敌效果加持. this.configuration.bInvincible = true; mDefaultScale = this.transform.localScale; Sequence agentTweenSeq = DOTween.Sequence(); var ss = mDefaultScale * 0.3f; this.transform.localScale = this.transform.localScale * 0.3f; Tweener agScale = this.transform.DOScale(mDefaultScale, 0.3f); agentTweenSeq.Append(agScale); agentTweenSeq.AppendCallback(beDamageStart); this.nodeMoveUpdate = false; // 获取移动速度 fMoveSpeed = this.m_NavMeshAgent.speed / 2.0f; } protected void beDamageStart() { this.configuration.bInvincible = false; } /// /// 把当前的Agent拉到起始位置 /// public void ResetAgentToInitialPos() { if (!this.initNode) return; Vector3 initPos = this.initNode.GetRandomPointInNodeArea(); transform.position = initPos; ResetPositionData(); this.SetNode(initNode, -1); // 更新AgentMgr,确保不再攻击回到原点的Agent. AgentInsManager.instance.updateInsMgrPos(this.opponentAgent); } /// /// 执行重设到开始位置的Agent特效,需要执行一系列的动作. /// public void execAgentPosResetAction() { // 无敌状态不增加当前的效果: if (configuration.bInvincible) return; // 只有处于非PosEffect状态才可以有这个状态. var posResetEff = this.GetComponent(); if (posResetEff == null) { posResetEff = this.gameObject.AddComponent(); // 初始化当前的PosResetEffect posResetEff.Initialize(3, AgentInsManager.instance.posResetFx); } } /// /// 预处理当前的Agent最大或最小可以到达的ZValue. /// protected void PreProcessZValue() { if (!m_CurrentNode) return; Node nextNode = m_CurrentNode.GetNextNode(); if (!nextNode) return; /* if (m_CurrentNode.transform.position.z > nextNode.transform.position.z) this.m_PositiveZ = false; else this.m_PositiveZ = true; m_ZMaxValue = nextNode.transform.position.z; Node thirdNode = nextNode.GetNextNode(); if (!thirdNode) return; if (thirdNode.transform.position.x > nextNode.transform.position.x) this.m_PositiveX = true; else { this.m_PositiveX = false; } m_XMaxValue = thirdNode.transform.position.x;*/ } /// /// Finds the next node in the path /// public virtual void MoveToNextNode(Node currentlyEnteredNode) { // Don't do anything if the calling node is the same as the m_CurrentNode if (m_NextNode != currentlyEnteredNode) { return; } if (m_NextNode == null) { Debug.LogError("Cannot find current node"); return; } Node nextNode = m_NextNode.GetNextNode(); if (nextNode == null) { if (m_NavMeshAgent.enabled) { m_NavMeshAgent.isStopped = true; } // 清空当前的Node和NextNode. m_CurrentNode = null; HandleDestinationReached(); m_NextNode = null; return; } Debug.Assert(nextNode != m_CurrentNode); SetNode(m_NextNode, -1); } /// /// Moves the agent to a position in the /// 预计算开始位置,结束位置,以及移动方向。 /// public virtual void MoveToNode() { if ((!m_CurrentNode) || (!m_NextNode)) { if (!m_CurrentNode) Debug.Log("当前的Node值为空."); else Debug.Log("NextNode的值为空."); return; } m_Destination = m_NextNode; m_SrcPosition = m_CurrentNode.transform.position; // // 预处理,确定移动方向. if (m_Destination.transform.position.x == m_SrcPosition.x) { if (m_Destination.transform.position.z > m_SrcPosition.z) moveDir = EAgentMovDir.ZPositive; else moveDir = EAgentMovDir.ZNegative; } else { if (m_Destination.transform.position.z != m_SrcPosition.z) { Debug.Log("目标位置和开始位置的Z值不相等:" + m_Destination.transform.position.x + "," + m_Destination.transform.position.z + "," + m_SrcPosition.x + "," + m_SrcPosition.z); } if (m_Destination.transform.position.x > m_SrcPosition.x) moveDir = EAgentMovDir.XPositive; else moveDir = EAgentMovDir.XNegative; } } /// /// The logic for what happens when the destination is reached /// public virtual void HandleDestinationReached() { state = State.PathComplete; if (destinationReached != null) { destinationReached(m_NextNode); } } /// /// Lazy Load, if necesaary and ensure the NavMeshAgent is disabled /// protected override void Awake() { //Debug.Log("哪里生成的?"); base.Awake(); LazyLoad(); m_NavMeshAgent.enabled = false; MoveStopTime = 0.0f; } /// /// 根据帧间的时间,来更新Agent的位置信息,其它信息直接删除. /// 1: /// /// protected void updateAgentPos(float deltaTime) { if ((!m_CurrentNode) || (!m_NextNode)) return; // 是否处于停止状态. if (MoveStopTime > 0) { MoveStopTime -= Time.deltaTime; if (MoveStopTime <= 0) { StopFrostParticle(); MoveStopTime = 0; } else return; } if (this.fMoveSpeed == 0) { Debug.Log("当前的移动为零:" + fMoveSpeed); return; } float finalSpeed = fMoveSpeed * (1 - speedSlowRate); if (speedSlowRate > 0 && !isSlowDown) { isSlowDown = true; if (SlowDownParticle != null) SlowDownParticle.Play(); } else if (speedSlowRate == 0 && isSlowDown) { isSlowDown = false; if (SlowDownParticle != null) { SlowDownParticle.Stop(); SlowDownParticle.Clear(); } } Vector3 curPos = m_NavMeshAgent.transform.position; bool swithNode = false; switch (moveDir) { case EAgentMovDir.ZPositive: { curPos.z += (deltaTime * finalSpeed); if (curPos.z >= m_Destination.transform.position.z) { curPos.z = m_Destination.transform.position.z; swithNode = true; } break; } case EAgentMovDir.ZNegative: { curPos.z -= (deltaTime * finalSpeed); if (curPos.z <= m_Destination.transform.position.z) { curPos.z = m_Destination.transform.position.z; swithNode = true; } break; } case EAgentMovDir.XPositive: { curPos.x += (deltaTime * finalSpeed); if (curPos.x >= m_Destination.transform.position.x) { curPos.x = m_Destination.transform.position.x; swithNode = true; } break; } case EAgentMovDir.XNegative: { curPos.x -= (deltaTime * finalSpeed); if (curPos.x <= m_Destination.transform.position.x) { curPos.x = m_Destination.transform.position.x; swithNode = true; } break; } } // 根据是否到达一个结点来进行不同的处理 if (swithNode) { this.MoveToNextNode(m_NextNode); } else { // Y值插值. float lerpVal = (curPos.z - mStartZVal) / (m_Destination.transform.position.z - mStartZVal); if (!this.opponentAgent) // curPos.y = mStartYVal + lerpVal * 60f; curPos.y = mStartYVal; m_NavMeshAgent.transform.position = curPos; } return; } /// /// 更新动作信息. /// /// protected void UpdateAction() { if (ActionAnimator == null) return; AnimatorStateInfo stateInfo = ActionAnimator.GetCurrentAnimatorStateInfo(0); switch (ActionState) { case AgentActionState.Move: break; case AgentActionState.GetHit: if (stateInfo.normalizedTime >= 1f) ChangeState(AgentActionState.Move); break; case AgentActionState.Attack: if (stateInfo.normalizedTime >= 1f) { if (isDead) { AgentInsManager.instance.removeAgent(this); Remove(); } } break; case AgentActionState.Death: if (stateInfo.normalizedTime >= 1f) Remove(); break; } } private void ChangeState(AgentActionState state) { if (state == ActionState) return; ActionState = state; if (ActionAnimator != null) ActionAnimator.SetInteger(paramName, (int)state); } /// /// 检查自身血量 /// private void CheckHealth() { if (this.healthVal <= 0.1) { Die(); //Debug.Log("删除多余的攻击Agent."); } } private void Die() { // 统一管理器内删除当前的Agent: AgentInsManager.instance.removeAgent(this); this.Remove(); } /// /// Updates the agent in its different states, /// Reset destination when path is stale /// River: 更新的时候,加入离最终目标的距离数据. /// protected virtual void LateUpdate() { this.UpdateAction(); HandleShieldWall(); // 处理死亡状态了,不必再移动: if (bInDeathAct || !CanMove) return; m_Destination = initNode.GetNextNode(); updateAgentPos(Time.deltaTime); // 计算离目标的距离,非最终距离,只用于比较大小 this.m_DisToDestination = this.GetDisToDestination(); // 计算中毒相关. if ((poisonTimes > 0) && (poisonHurt > 0)) updatePoison(Time.deltaTime); } protected virtual void Update() { } /// /// 处理魔法护盾血量值 /// protected void HandleShieldWall() { if (configuration.IsExistShieldWall) { if (configuration.ShieldWallCurrentHealth <= 0.00001f) configuration.IsExistShieldWall = false; else if (configuration.ShieldWallEffectiveTime > 0.00001f) { if (configuration.ShieldWallRemainTime <= 0.00001f) configuration.IsExistShieldWall = false; else configuration.ShieldWallRemainTime -= Time.deltaTime; } } } /// /// 限制当前Agent的移动位置,让Agent的移动看起来更帅一些 /// protected void restrictAgentPos() { /* // 设置最大的Z值,确保按路线移动 Vector3 pos = m_NavMeshAgent.transform.position; if (this.m_PositiveZ) { if (pos.z > m_ZMaxValue) { pos.z = m_ZMaxValue; m_NavMeshAgent.transform.position = pos; } } else { if (pos.z < m_ZMaxValue) { pos.z = m_ZMaxValue; m_NavMeshAgent.transform.position = pos; } } // 设置X值的限制,确保按路线移动 if(this.m_PositiveX) { if( pos.x > m_XMaxValue) { pos.x = m_XMaxValue; m_NavMeshAgent.transform.position = pos; } } else { if( pos.x < m_XMaxValue) { pos.x = m_XMaxValue; m_NavMeshAgent.transform.position = pos; } }*/ } /// /// Set the NavMeshAgent's destination /// /// The position to navigate to protected virtual bool NavigateTo(Vector3 nextPoint) { // River mod: 完全自己控制移动 ,不需要navMeshAgent. return true; /* LazyLoad(); bool res = false; if (m_NavMeshAgent.isOnNavMesh) { nextPoint.y += 0.1f; res = m_NavMeshAgent.SetDestination(nextPoint); } return res;*/ } /// /// 计算当前的Agent距离目标的最终距离,不是真实距离,是比较大小的数值. /// /// protected float GetDisToDestination() { if (!m_CurrentNode) return 0; float tmpDis = 0; Node tmpNode = m_CurrentNode.GetNextNode(); while (tmpNode.GetNextNode() != null) { tmpDis += NODE_DIS; tmpNode = tmpNode.GetNextNode(); } Vector3 tpos = this.position; tpos.y = mStartYVal; tmpDis += Vector3.Distance(tpos, this.m_Destination.transform.position); return tmpDis; } protected ChangeMat changeMat; /// /// This is a lazy way of caching several components utilised by the Agent /// protected virtual void LazyLoad() { if (m_NavMeshAgent == null) { m_NavMeshAgent = GetComponent(); mLootDrop = GetComponent(); originalMovementSpeed = m_NavMeshAgent.speed; } if (m_LevelManager == null) { m_LevelManager = LevelManager.instance; } if (!endlessLevelManager) endlessLevelManager = EndlessLevelManager.instance; } /// /// 播放受击动画. /// public void PlayOnHit() { ChangeState(AgentActionState.GetHit); } /// /// 播放受击动画,直接从头开始播放 /// public void PlayOnHitImmediately() { ChangeState(AgentActionState.GetHit); if (ActionAnimator) { ActionAnimator.Play("GetHit", 0, 0); ActionAnimator.Update(0); } } /// /// 播放火技能打击动画 /// public void PlayFireSkillHit() { if (FireSkillParticle != null) FireSkillParticle.Play(); } public void PlayAttack() { AudioSourceManager.Ins.Play(AudioEnum.AttackTower); ChangeState(AgentActionState.Attack); } public override void PlayDeath() { if (isPoison) { isPoison = false; // 移除Agent身上的中毒特效,并播放一个中毒效果消失的特效 if (PoisonParticle != null) { PoisonParticle.Stop(); PoisonParticle.Clear(); if (PoisonEndParticle != null) PoisonEndParticle.Play(); } } if (isSlowDown) { isSlowDown = false; if (SlowDownParticle != null) { SlowDownParticle.Stop(); SlowDownParticle.Clear(); } } ChangeState(AgentActionState.Death); // 统一管理器内删除当前的Agent: AgentInsManager.instance.removeAgent(this); bInDeathAct = true; } /// /// Move along the path, change to /// protected virtual void OnCompletePathUpdate() { if (isPathBlocked) { state = State.OnPartialPath; } } /// /// Peforms the relevant path update /// protected abstract void PathUpdate(); /// /// The behaviour for when the agent has been blocked /// protected abstract void OnPartialPathUpdate(); #if UNITY_EDITOR /// /// Draw the agent's path /// protected virtual void OnDrawGizmosSelected() { if (m_NavMeshAgent != null) { Vector3[] pathPoints = m_NavMeshAgent.path.corners; int count = pathPoints.Length; for (int i = 0; i < count - 1; i++) { Vector3 from = pathPoints[i]; Vector3 to = pathPoints[i + 1]; Gizmos.DrawLine(from, to); } Gizmos.DrawWireSphere(m_NavMeshAgent.destination, 0.2f); } } #endif } }