using ActionGameFramework.Health; using Core.Health; using Core.Utilities; using DG.Tweening; using KTGMGemClient; using System; using System.Collections.Generic; using TowerDefense.Agents; using TowerDefense.Targetting; using TowerDefense.UI.HUD; using UnityEngine; using UnityEngine.AI; /// /// 基于兵线的Agent Instance管理器 /// public class WaveLineAgentInsMgr { /// /// 当前WaveID对应到的所有Agent实例 /// protected List agentInsList; protected Vector3 targetPosition; /// /// 对应的WaveLineID. /// public int waveLineID { get; set; } public WaveLineAgentInsMgr(int waveID) { waveLineID = waveID; agentInsList = new List(); } /// /// 添加一个AgentIns. /// /// public void addAgentIns(Agent ag) { agentInsList.Add(ag); } /// /// 删除一个AgentIns. /// /// public void delAgentIns(Agent ag) { agentInsList.Remove(ag); } /// /// 当前列对应的怪物数目 /// /// public int getAgentInsNum() { return this.agentInsList.Count; } /// /// 获取当前管理对应的listAgent. /// public List listAgent { get { return this.agentInsList; } } /// /// 获取距目标结点最近的Agent. /// /// public Agent getMinDisAgent(bool _noPoison = false) { if (agentInsList.Count == 0) return null; // 排序,然后返回对应的数据 // 直接使用闭包函数来进行排序: agentInsList.Sort((left, right) => { if (left.distanceToDest > right.distanceToDest) { return 1; } else if (left.distanceToDest == right.distanceToDest) { return 0; } else { return -1; } }); if (_noPoison) { for (int ti = 0; ti < agentInsList.Count; ti++) { if (!agentInsList[ti].bInPoison) return agentInsList[ti]; } return null; } else return agentInsList[0]; } } /// /// Wave刷新出来的每一个AgentInstance加进来,统一管理。Targetter不再管理每一个细节。 /// 每一个关卡统一管理在场景内出现的AgentInstance. /// public class AgentInsManager : Singleton { protected readonly int MAX_ATTCNT = 5; public static bool bBossCreateState = false; /// /// Agent位置重设的特效. /// public GameObject posResetFx; /// /// Agent之间的电弧特效,两个Agent之间发生 /// public GameObject lightBoltFx; /// /// 被电弧击中的效果. /// public GameObject lightHitFx; /// /// 所有Agent往中间移动的时候,播放的粒子特效 /// public ParticleSystem centMovEffect; /// /// 战场上所有存活的Agent的列表,遍历这个列表,提取出所有的数据 /// protected List agentInsList; protected Agent agentMinDis = null; protected List agentInRange = null; /// /// 存储Agent已方的最高血量数据 /// protected List agentListMaxHp = null; protected Agent agentMaxHp = null; /// /// 对手方要处理的Agent列表 /// protected List oppoAgentInsList; protected Agent oppoAgentMinDis = null; protected List oppoAgentInRange = null; /// /// 存储Agent最高血量数据. /// protected List oppoAgentListMaxHp = null; protected Agent oppoAgentMaxHp = null; /// /// 随机种子. /// protected System.Random mRand; /// /// 正方兵线Agent管理数组 /// protected WaveLineAgentInsMgr[] agentWaveLineArray; /// /// 反方兵线Agent管理数组 /// protected WaveLineAgentInsMgr[] oppoAgentWaveLineArray; /// /// 用于排序的Buf. /// protected Agent[] agentTmpArr = new Agent[3]; // Start is called before the first frame update void Start() { agentInsList = new List(); agentInRange = new List(); agentListMaxHp = new List(); oppoAgentInsList = new List(); oppoAgentInRange = new List(); oppoAgentListMaxHp = new List(); agentWaveLineArray = new WaveLineAgentInsMgr[5]; for (int ti = 0; ti < agentWaveLineArray.Length; ti++) agentWaveLineArray[ti] = new WaveLineAgentInsMgr(ti); oppoAgentWaveLineArray = new WaveLineAgentInsMgr[5]; for (int ti = 0; ti < oppoAgentWaveLineArray.Length; ti++) oppoAgentWaveLineArray[ti] = new WaveLineAgentInsMgr(ti); mRand = new System.Random(); } public WaveLineAgentInsMgr[] getOppoWaveLineList() { return this.oppoAgentWaveLineArray; } public WaveLineAgentInsMgr[] GetWaveLineList() { return agentWaveLineArray; } /// /// 设置某条兵线的所有小兵的移动状态 /// /// 兵线id 1~5, 如果是-1则设置所有兵线的状态 /// 是否可以移动 /// 是否是敌方 public void SetWaveLineCanMove(int waveLineId, bool canMove, bool isOppo) { WaveLineAgentInsMgr[] waveLineAgents = isOppo ? getOppoWaveLineList() : GetWaveLineList(); for (int i = 0; i < waveLineAgents.Length; ++i) { if (i == waveLineId - 1 || waveLineId == -1) { List list = waveLineAgents[i].listAgent; for (int j = 0; j < list.Count; ++j) { list[j].CanMove = canMove; } } } } public List agentList { get { return this.agentInsList; } } public List oppoAgentList { get { return this.oppoAgentInsList; } } /// /// 获取距离最短的Agent. /// public Agent MinDisAgent { get { return this.agentMinDis; } } /// /// 获取距离最近的Agents /// /// /// public Agent GetMinDisAgent(int lineid, bool oppo, bool forceGet = false, bool noPoison = false) { if (lineid >= agentWaveLineArray.Length) return null; if (lineid < 0) return null; Agent ag; if (oppo) ag = oppoAgentWaveLineArray[lineid].getMinDisAgent(noPoison); else ag = agentWaveLineArray[lineid].getMinDisAgent(noPoison); // 这一行防止无限的循环下去。 if (forceGet) return ag; Agent agLeft = GetMinDisAgent(lineid - 1, oppo, true, noPoison); Agent agRight = GetMinDisAgent(lineid + 1, oppo, true, noPoison); agentTmpArr[0] = ag; agentTmpArr[1] = agLeft; agentTmpArr[2] = agRight; float minDis = 100000000f; int idx = -1; for (int ti = 0; ti < agentTmpArr.Length; ti++) { if ((agentTmpArr[ti] != null) && (agentTmpArr[ti].distanceToDest < minDis)) { idx = ti; minDis = agentTmpArr[ti].distanceToDest; } } // // 返回最近的Agent数据指针. if (idx < 0) { // 如果是查找无中毒状态的Agent,再查一次: if (noPoison) return GetMinDisAgent(lineid, oppo, forceGet); return null; } else return agentTmpArr[idx]; } public List AgentInRange { get { return this.agentInRange; } } public Agent oppoMinDisAgent { get { return this.oppoAgentMinDis; } } /// /// 获取血量最大的数据 /// /// /// public Agent getMaxHpAgent(bool opponent) { if (opponent) return this.oppoAgentMaxHp; else return this.agentMaxHp; } public List getAgentListMaxHp(bool opponent) { if (opponent) return oppoAgentListMaxHp; else return agentListMaxHp; } /// /// 获取随机的AgentList. /// /// /// public List getAgentListRandom(bool opponent) { List tlist; List resList = new List(); if (opponent) tlist = oppoAgentInsList; else tlist = agentInsList; int maxCnt = MAX_ATTCNT; if (tlist.Count < maxCnt) maxCnt = tlist.Count; for (int ti = 0; ti < maxCnt; ti++) { int idx = mRand.Next(0, tlist.Count); if (tlist[idx].opponentAgent != opponent) continue; resList.Add(tlist[idx]); } return resList; } /// /// 返回一个随机的Agent. /// /// /// public Agent getRandomAgent(bool opponent) { List tlist; if (opponent) tlist = oppoAgentInsList; else tlist = agentInsList; if (tlist.Count == 0) return null; int idx = mRand.Next(0, tlist.Count); return tlist[idx]; } public List OppoAgentInRange { get { return this.oppoAgentInRange; } } protected void updateAgent() { this.agentInRange.Clear(); this.agentListMaxHp.Clear(); this.agentMinDis = null; this.agentMaxHp = null; if (agentInsList.Count == 0) return; // 用闭包函数先对血量进行排序. agentInsList.Sort((left, right) => { if (left.healthVal < right.healthVal) return 1; else if (left.healthVal == right.healthVal) return 0; else return -1; }); agentMaxHp = agentInsList[0]; int maxCnt = MAX_ATTCNT; if (agentInsList.Count < maxCnt) maxCnt = agentInsList.Count; for (int ti = 0; ti < maxCnt; ti++) { if (agentInsList[ti].opponentAgent) continue; this.agentListMaxHp.Add(agentInsList[ti]); } // 直接使用闭包函数来进行排序: agentInsList.Sort((left, right) => { if (left.distanceToDest > right.distanceToDest) { return 1; } else if (left.distanceToDest == right.distanceToDest) { return 0; } else { return -1; } }); agentMinDis = agentInsList[0]; //maxCnt = MAX_ATTCNT; //if (agentInsList.Count < maxCnt) // maxCnt = agentInsList.Count; for (int ti = 0; ti < maxCnt; ti++) { if (agentInsList[ti].opponentAgent) continue; this.agentInRange.Add(agentInsList[ti]); } return; } /// /// 场景内所有的Agent移动到中心坐标。 /// public void moveAllAgentToCenter() { float moveTime = 0.9f; Targetter.bSearchTarget = false; bBossCreateState = true; int cnt = this.agentInsList.Count; Vector3 cpos = this.GetCenterPos(false); for (int ti = 0; ti < cnt; ti++) { agentInsList[ti].SetNode(null, -1); NavMeshAgent ag = agentInsList[ti].navMeshAgent; ag.transform.DOMoveX(cpos.x, moveTime); ag.transform.DOMoveZ(cpos.z, moveTime); } // 播放特效 ParticleSystem tpar = Instantiate(centMovEffect); tpar.transform.position = cpos; tpar.Simulate(0.0f); tpar.Play(); cnt = this.oppoAgentInsList.Count; cpos = this.GetCenterPos(true); for (int ti = 0; ti < cnt; ti++) { oppoAgentInsList[ti].SetNode(null, -1); NavMeshAgent ag = oppoAgentInsList[ti].navMeshAgent; ag.transform.DOMoveX(cpos.x, moveTime); ag.transform.DOMoveZ(cpos.z, moveTime); } // 播放特效: tpar = Instantiate(centMovEffect); tpar.transform.position = cpos; tpar.Simulate(0.0f); tpar.Play(); // // 1.25秒之后消失掉所有的小怪: Invoke("releaseAllCenterAgent", moveTime + 0.1f); } public void restartLevel() { bBossCreateState = false; return; } protected void releaseAllCenterAgent() { int cnt = this.agentInsList.Count; for (int ti = cnt - 1; ti >= 0; ti--) { if (agentInsList[ti].bBoss) continue; agentInsList[ti].Remove(); } cnt = this.oppoAgentInsList.Count; for (int ti = cnt - 1; ti >= 0; ti--) { if (oppoAgentInsList[ti].bBoss) continue; oppoAgentInsList[ti].Remove(); } } /// /// 获取WaveManager相关的中心点 /// /// public Vector3 GetCenterPos(bool oppo) { Vector3 cpos = Vector3.zero; return cpos; } protected void updateOpponentAgent() { this.oppoAgentInRange.Clear(); this.oppoAgentListMaxHp.Clear(); this.oppoAgentMinDis = null; this.oppoAgentMaxHp = null; if ((oppoAgentInsList.Count == 0)) return; // 根据血量进行排序: oppoAgentInsList.Sort((left, right) => { if (left.healthVal < right.healthVal) return 1; else if (left.healthVal == right.healthVal) return 0; else return -1; }); this.oppoAgentMaxHp = oppoAgentInsList[0]; int maxCnt = MAX_ATTCNT; if (oppoAgentInsList.Count < MAX_ATTCNT) maxCnt = oppoAgentInsList.Count; for (int ti = 0; ti < maxCnt; ti++) { if (!oppoAgentInsList[ti].opponentAgent) continue; oppoAgentListMaxHp.Add(oppoAgentInsList[ti]); } // 离目标的距离进行排序: oppoAgentInsList.Sort((left, right) => { if (left.distanceToDest > right.distanceToDest) { return 1; } else if (left.distanceToDest == right.distanceToDest) { return 0; } else { return -1; } }); oppoAgentMinDis = oppoAgentInsList[0]; for (int ti = 0; ti < maxCnt; ti++) { if (!oppoAgentInsList[ti].opponentAgent) continue; oppoAgentInRange.Add(oppoAgentInsList[ti]); } } /// /// 再次更新opponentManager /// /// public void updateInsMgrPos(bool opponent) { if (opponent) this.updateOpponentAgent(); else this.updateAgent(); } /// /// 处理战场上的Bomb伤害.以Bomb中心的为单位对战场上的怪物进行伤害。 /// /// /// /// /// public void ExecBombAttack(Vector3 pos, int sid, int slevel, bool opponent) { skilllevelinfo slinfo = JsonDataCenter.GetSkillLevelInfo(sid, slevel + 1); if (slinfo == null) return; WaveLineAgentInsMgr[] mgrList; if (opponent) mgrList = oppoAgentWaveLineArray; else mgrList = agentWaveLineArray; pos.y = 0; if (slinfo.atcmod.Count < 2) return; float radius = slinfo.atcmod[1]; for (int ti = 0; ti < mgrList.Length; ti++) { WaveLineAgentInsMgr mgr = mgrList[ti]; for (int idx = 0; idx < mgr.listAgent.Count; idx++) { Agent eag = mgr.listAgent[idx]; Vector3 fpos = eag.transform.position; fpos.y = 0; float dist = Vector3.Distance(fpos, pos); if (radius < dist) continue; float damage = slinfo.skilleffect[2]; damage += (slinfo.skilleffect[1] / 100.0f * eag.configuration.maxHealth); damage = (float)Math.Floor(damage); eag.TakeDamage(damage, fpos, null); if (!eag.opponentAgent) { if (GameUI.instanceExists) GameUI.instance.generateBloodText(fpos, damage, false, false); else if (EndlessGameUI.instanceExists) EndlessGameUI.instance.generateBloodText(fpos, damage, false, false); } if (eag.isDead) continue; else eag.SetAgentBuffEffect(3); } } return; } /// /// 处理战场上的兵线伤害,以兵线为单位对怪物进行伤害 /// /// /// /// /// public void ExecWavelineAttack(int waveline, int sid, int slevel, bool opponent) { skilllevelinfo slinfo = JsonDataCenter.GetSkillLevelInfo(sid, slevel + 1); if (slinfo == null) return; WaveLineAgentInsMgr wavelineIns; if (opponent) wavelineIns = oppoAgentWaveLineArray[waveline]; else wavelineIns = agentWaveLineArray[waveline]; if (wavelineIns == null) return; List listAg = wavelineIns.listAgent; for (int ti = listAg.Count - 1; ti >= 0; ti--) { Agent eag = listAg[ti]; Vector3 fpos = eag.transform.position; float damage = slinfo.skilleffect[2]; damage += (slinfo.skilleffect[1] / 100.0f * eag.configuration.maxHealth); damage = (float)Math.Floor(damage); eag.TakeDamage(damage, fpos, null); if (!eag.opponentAgent) { if (GameUI.instanceExists) GameUI.instance.generateBloodText(fpos, damage, false, false); else if (EndlessGameUI.instanceExists) EndlessGameUI.instance.generateBloodText(fpos, damage, false, false); } } } /// /// 每一帧更新,更新之后获取几个刚性数据: /// 1:血量最多的AgentInstance. /// 2:最前面的AgentInstance. /// 3: /// void Update() { this.updateAgent(); this.updateOpponentAgent(); // 测试重设最前面的Agent到初始化位置: if (Input.GetKeyDown(KeyCode.A)) { // 测试数据,重设Agent到开始位置 if (agentInsList.Count >= 2) { /* var posResetEff = MinDisAgent.GetComponent(); if (posResetEff == null) { posResetEff = MinDisAgent.gameObject.AddComponent(); } posResetEff.Initialize(4, posResetFx );*/ var lightBolt = agentInsList[1].GetComponent(); if (lightBolt == null) { lightBolt = agentInsList[1].gameObject.AddComponent(); } lightBolt.Initialize(2, lightBoltFx, lightHitFx, agentInsList[1], agentInsList[0]); } } /* // TEST CODE TO DELETE: if( Input.GetKeyDown( KeyCode.S )) { this.moveAllAgentToCenter(); } if( Input.GetKeyDown( KeyCode.D)) { Targetter.bSearchTarget = !Targetter.bSearchTarget; }*/ } /// /// 对当前Agent同一列内一定区域内的怪物进行攻击: /// /// public void StartExplodeAttack(Agent ag, float damage) { WaveLineAgentInsMgr tmgr; if (!ag.opponentAgent) tmgr = this.agentWaveLineArray[ag.waveLineID]; else tmgr = this.oppoAgentWaveLineArray[ag.waveLineID]; if (tmgr.getAgentInsNum() <= 1) return; List listAg = tmgr.listAgent; Vector3 tpos = ag.transform.position; for (int ti = listAg.Count - 1; ti >= 0; ti--) { Agent eag = listAg[ti]; if (eag == ag) continue; Vector3 fpos = eag.transform.position; tpos.y = 0; fpos.y = 0; if (Vector3.Distance(tpos, fpos) < 8) { eag.TakeDamage(damage, fpos, null); if (!eag.opponentAgent) { if (GameUI.instanceExists) GameUI.instance.generateBloodText(fpos, damage, false, false); else if (EndlessGameUI.instanceExists) EndlessGameUI.instance.generateBloodText(fpos, damage, false, false); } } } /* foreach (Agent eag in listAg) { if (eag == ag) continue; Vector3 fpos = eag.transform.position; tpos.y = 0; fpos.y = 0; if (Vector3.Distance(tpos, fpos) < 8) { eag.TakeDamage(damage, fpos, null); GameUI.instance.generateBloodText(fpos, damage, false, false); } }*/ } /// /// 开启链式攻击. /// /// public void StartChainAttack(Agent chainStart, IAlignmentProvider alignment, float chainAttackHurt) { List opList = null; if (chainStart.opponentAgent) opList = oppoAgentInsList; else opList = agentInsList; int maxCnt = opList.Count; List listBlood = new List(); for (int ti = 0; ti < maxCnt - 1; ti++) { if (opList[ti] != chainStart) continue; int chainAttackNum = 0; for (int tj = ti + 1; tj < maxCnt; tj++) { var lightBolt = opList[tj].GetComponent(); if (lightBolt == null) { lightBolt = opList[tj].gameObject.AddComponent(); lightBolt.Initialize(2, lightBoltFx, lightHitFx, opList[tj], opList[tj - 1]); listBlood.Add(opList[tj]); } // 最多两个受到影响: chainAttackNum++; if (chainAttackNum >= 3) break; } } // TEST CODE: 最终应该是由服务器说了算的伤害. // 每一个被链式攻击的怪物,飘血. foreach (Agent ag in listBlood) { int tid = ag.liveID; Damager damager = ag.GetComponent(); ag.TakeDamage(chainAttackHurt, ag.position, alignment); // 处理飘字效果: if ((ag.liveID == tid) && (!ag.opponentAgent)) { if (GameUI.instanceExists) GameUI.instance.generateBloodText(ag.position, chainAttackHurt, false, false); else if (EndlessGameUI.instanceExists) EndlessGameUI.instance.generateBloodText(ag.position, chainAttackHurt, false, false); } } listBlood.Clear(); } protected void addWaveLineAgent(Agent ag) { if (ag.opponentAgent) oppoAgentWaveLineArray[ag.waveLineID].addAgentIns(ag); else agentWaveLineArray[ag.waveLineID].addAgentIns(ag); } protected void delWaveLineAgent(Agent ag) { if (ag.opponentAgent) oppoAgentWaveLineArray[ag.waveLineID].delAgentIns(ag); else agentWaveLineArray[ag.waveLineID].delAgentIns(ag); } /// /// 管理器增加Agent. /// /// public void addAgent(Agent ag) { addWaveLineAgent(ag); if (!ag.opponentAgent) { this.agentInsList.Add(ag); } else { this.oppoAgentInsList.Add(ag); } } /// /// 更新当前管理器内所有怪物的移动速度 /// /// public void ScaleAgentSpeed(float fscale) { for (int ti = 0; ti < agentInsList.Count; ti++) agentInsList[ti].SetMoveSpeedScale(fscale); for (int ti = 0; ti < oppoAgentInsList.Count; ti++) oppoAgentInsList[ti].SetMoveSpeedScale(fscale); } /// /// 管理器减少一个Agent,临时缓存队列也需要更新数据 /// /// public void removeAgent(Agent ag) { delWaveLineAgent(ag); if (!ag.opponentAgent) { this.agentInsList.Remove(ag); this.agentListMaxHp.Remove(ag); if (agentMaxHp == ag) agentMaxHp = null; } else { this.oppoAgentInsList.Remove(ag); this.oppoAgentListMaxHp.Remove(ag); if (oppoAgentMaxHp) oppoAgentMaxHp = null; } } /// /// 获取最前面的Agent. /// /// public Agent getMostFrontAgent() { return null; } /// /// 获取血量最多的Agent. /// /// public Agent getMostHealthAgent() { return null; } }