using System; using System.Collections.Generic; using Core.Extensions; using Core.Utilities; using JetBrains.Annotations; using KTGMGemClient; using TowerDefense.Agents; using TowerDefense.Agents.Data; using TowerDefense.Nodes; using UnityEngine; namespace TowerDefense.Level { /// /// A Wave is a TimedBehaviour, that uses the RepeatingTimer to spawn enemies /// public class Wave : TimedBehaviour { /// /// 当前的Wave可以刷新出来的agent类型. /// public List agentConfigurationList; /// /// 当前波总刷怪时间. /// public float totalWaveTime = 10; /// /// 当前波的总刷怪数目 /// public int totalAgentNum = 20; /// /// A list of instructions on how to spawn enemies /// public List spawnInstructions; /// /// The index of the current enemy to spawn /// protected int m_CurrentIndex; /// /// The RepeatingTimer used to spawn enemies /// protected RepeatingTimer m_SpawnTimer; /// /// The event that is fired when a Wave is completed /// public event Action waveCompleted; /// /// 在Wave初始化的初始化当前的Wave. /// protected Node startingNode; /// /// 当前Wave对应的BossAgent. /// protected Agent bossAgent = null; /// /// 接下来要创建的Agent是否死亡后再生 /// protected bool bReSpawnState = true; /// /// 当前的兵线是否已经停止. /// protected bool bWaveStoped = false; /// /// 怪物刷新速度的缩放. /// protected float spawnTimeScale = 1.0f; /// /// 怪物移动速度的缩放 /// protected float monsterMoveScale = 1.0f; /// /// BOSS是否已经创建 /// public bool bBossCreated { set; get; } /// /// 当前Wave对应的兵线ID,需要赋值给当前WaveLine生成的Agent /// public int waveLineID { get;set; } /// /// Wave内普通怪物对应的血量,这个数据是动态更新的 /// public float commonAgentHealth { set; get; } /// /// 初始化刷怪指令 /// protected virtual void initAgentInstructionList() { //if (this.agentConfigurationList.Count <= 0) return; //int len = this.agentConfigurationList.Count; this.spawnInstructions.Clear(); //this.preProcessSpawnInstruction(); ConstructSpawnInstruction(); } /// /// 根据配置文件来刷新出来相应的怪物数据。 /// protected void ConstructSpawnInstruction() { SpawnInstruction ts; List listRes = JsonDataCenter.GetList(); int maxLen = listRes.Count; for (int ti = 0; ti < maxLen; ti++) { ts = new SpawnInstruction(); resource res = listRes[ti]; // 根据数据来刷新出来普通怪。 if (res.type == 0) ts.agentConfiguration = this.agentConfigurationList[0]; else ts.agentConfiguration = this.agentConfigurationList[6]; ts.delayToSpawn = this.GetTimeFromRes( res,1 ) / 1000.0f * spawnTimeScale; ts.hp = res.hp; ts.gold = 10; ts.speed = res.speed; this.spawnInstructions.Add(ts); } } /// /// 根据新的数据来更新相应的SpawnInstruction. /// /// public void UpdateSpawnInstruction(int fid) { if (spawnInstructions.Count == 0) return; List listRes = JsonDataCenter.GetList(); int maxLen = listRes.Count; //if (spawnInstructions.Count != maxLen) // Debug.Log("这时候还没有初始化."); for (int idx = m_CurrentIndex; idx < maxLen; idx++) { resource res = listRes[idx]; SpawnInstruction instruct = spawnInstructions[idx]; instruct.delayToSpawn = GetTimeFromRes(res, fid) /1000.0f * spawnTimeScale; // 设置当前的出怪间隔. if (idx == m_CurrentIndex) m_SpawnTimer.SetTime(instruct.delayToSpawn); } } /// /// 更新刷怪指令的刷怪时间. /// /// protected void UpdateSpawnTime(float spScale ) { if (spawnInstructions.Count == 0) return; List listRes = JsonDataCenter.GetList(); int maxLen = listRes.Count; //if (spawnInstructions.Count != maxLen) // Debug.Log("这时候还没有初始化."); for (int idx = m_CurrentIndex; idx < maxLen; idx++) { resource res = listRes[idx]; SpawnInstruction instruct = spawnInstructions[idx]; instruct.delayToSpawn = instruct.delayToSpawn * spScale; // 设置当前的出怪间隔. if (idx == m_CurrentIndex) m_SpawnTimer.SetTime(instruct.delayToSpawn); } } /// /// Initializes the Wave /// public virtual void Init( Node snode,int waveLine ) { // 初始化自定义的Spawn Instruction. this.initAgentInstructionList(); this.startingNode = snode; bBossCreated = false; waveLineID = waveLine; bWaveStoped = false; m_SpawnTimer = new RepeatingTimer(spawnInstructions[0].delayToSpawn, SpawnCurrent); StartTimer(m_SpawnTimer); } /// /// 不同的塔给出不同的时间. /// /// /// /// protected int GetTimeFromRes( resource data,int fid) { if (fid == 1) return data.firetime; else if (fid == 2) return data.watertime; else if (fid == 3) return data.woodtime; return 1000000; } public void InitNode( Node snode,int waveline ) { this.startingNode = snode; this.waveLineID = waveline; } /// /// 只能手动SpawnAgent /// /// /// public void PrepareToSpawnAgent( Node snode,int waveline) { this.startingNode = snode; waveLineID = waveline; } protected override void Update() { base.Update(); // 更新怪物的刷新速度和移动速度: if (this.spawnTimeScale.Equals(WaveManager.SPAWNMONSTER_TIMESCALE) && this.monsterMoveScale.Equals(WaveManager.MONSTERMOVE_TIMESCALE)) return; float spawnScale = WaveManager.SPAWNMONSTER_TIMESCALE / spawnTimeScale; this.UpdateSpawnTime(spawnScale); spawnTimeScale = WaveManager.SPAWNMONSTER_TIMESCALE; monsterMoveScale = WaveManager.MONSTERMOVE_TIMESCALE; } /// /// 停止当前的兵线出兵. /// public void stopWave() { StopTimer(m_SpawnTimer); bWaveStoped = true; } /// /// Handles spawning the current agent and sets up the next agent for spawning /// 在场景内孵化出来一个Boss,这个核心函数最后被规则性的数据接管: /// protected virtual void SpawnCurrent() { if( bWaveStoped) { Debug.Log("当前处于兵线停止的状态."); return; } try { Spawn(); }catch( Exception e) { Debug.Log("出错信息:" + e.ToString()); } if (!TrySetupNextSpawn()) { SafelyBroadcastWaveCompletedEvent(); // this is required so wave progress is still accurate m_CurrentIndex = spawnInstructions.Count; StopTimer(m_SpawnTimer); } } /// /// Spawns the current agent /// protected void Spawn() { if (spawnInstructions.Count <= m_CurrentIndex) return; SpawnInstruction sp = spawnInstructions[m_CurrentIndex]; SpawnAgent(sp.agentConfiguration, this.startingNode,sp.hp,sp.speed,sp.gold ); } /// /// Tries to setup the next spawn /// /// true if there is another spawn instruction, false if not protected bool TrySetupNextSpawn() { bool hasNext = spawnInstructions.Next(ref m_CurrentIndex); if (hasNext) { SpawnInstruction nextSpawnInstruction = spawnInstructions[m_CurrentIndex]; if (nextSpawnInstruction.delayToSpawn <= 0f) { SpawnCurrent(); } else { m_SpawnTimer.SetTime(nextSpawnInstruction.delayToSpawn); } } return hasNext; } /// /// 从Tower的AttributeId获取到怪物的数据 /// /// /// protected List GetMonsterDataFromAttributeId(int id) { geminfo tgem = new geminfo(); if (JsonDataCenter.gemInfoDic.TryGetValue(id, out tgem)) return tgem.summon; else { Debug.Log("找不到对应ID的Gem:" + id); return null; } } public static int GetFidFromAttribute( int attid) { return (int)Math.Floor((attid - 101) / 4.0f) + 1; } /// /// Spawns the agent /// /// The agent to spawn /// The starting node that the agent uses protected virtual Agent SpawnAgent(AgentConfiguration agentConfig, Node node, float health = 0, float speed = 0, float gold = 0,bool boss = false ) { Vector3 spawnPosition = node.GetRandomPointInNodeArea(); // 获取塔位数据,根据塔位数据来做相应的怪物数据处理: int attid = 0; int level = 0; if (node.bOpponentSide) { attid = LevelManager.instance.GetTowerAttID(waveLineID); level = LevelManager.instance.GetTowerLevel(waveLineID); } else { attid = OpponentMgr.instance.GetTowerAttID(waveLineID); level = OpponentMgr.instance.GetTowerLevel(waveLineID); } List summon = null; if( !boss ) summon = GetMonsterDataFromAttributeId(attid); bool twiceSpawn = false; if ( (summon != null)&&(!boss) ) { // 按属性需不在场景内生成小怪. monster tm = JsonDataCenter.GetMonsterData(summon[0], level + 1); int fid = GetFidFromAttribute( attid ); agentConfig = agentConfigurationList[fid]; health = tm.hp * health; speed = tm.speed * speed; if (summon[1] > 1) twiceSpawn = true; gold = tm.gold; } if (boss) level = -1; // 获取可用的实例. var poolable = Poolable.TryGetPoolable(agentConfig.agentPrefab.gameObject); if (poolable == null) { return null; } // 获取实例对应的Agen抽象接口,然后设置当前Agent对应的数据。 var agentInstance = poolable.GetComponent(); if (twiceSpawn) spawnPosition.x -= 2.0f; agentInstance.transform.position = spawnPosition; agentInstance.Initialize(); agentInstance.SetNode(node,waveLineID); agentInstance.opponentAgent = node.bOpponentSide; agentInstance.transform.rotation = node.transform.rotation; // 动态设置刷出来怪物的Health float fhp = health; if (fhp <= 0) fhp = commonAgentHealth * agentConfig.healthScale; agentInstance.SetAgentData( fhp ,speed * monsterMoveScale,(int)gold ); agentInstance.bRespawn = this.bReSpawnState; agentInstance.healthBar.SetHealthLevel(level); // 如果是对手,则需要Y轴旋转180度. if (agentInstance.opponentAgent) { agentInstance.transform.Rotate(45, 180, 0); agentInstance.healthBar.transform.localPosition = new Vector3(0, 0.88f, -0.62f); } else agentInstance.healthBar.transform.localPosition = new Vector3(0, 1.5f, 0); // 加入Manager统一管理. AgentInsManager.instance.addAgent(agentInstance); // 再生成一个,位置变一变,不要重合在一起: if( twiceSpawn) { poolable = Poolable.TryGetPoolable(agentConfig.agentPrefab.gameObject); if (poolable == null) return null; // 获取实例对应的Agen抽象接口,然后设置当前Agent对应的数据。 agentInstance = poolable.GetComponent(); spawnPosition.x += 4.0f; agentInstance.transform.position = spawnPosition; agentInstance.Initialize(); agentInstance.SetNode(node, waveLineID); agentInstance.opponentAgent = node.bOpponentSide; agentInstance.transform.rotation = node.transform.rotation; agentInstance.SetAgentData(fhp, speed * monsterMoveScale, (int)gold); agentInstance.bRespawn = this.bReSpawnState; agentInstance.healthBar.SetHealthLevel(level); // 加入Manager统一管理. AgentInsManager.instance.addAgent(agentInstance); // 如果是对手,则需要Y轴旋转180度. if (agentInstance.opponentAgent) { agentInstance.transform.Rotate(45, 180, 0); agentInstance.healthBar.transform.localPosition = new Vector3(0, 0.88f, -0.62f); } else agentInstance.healthBar.transform.localPosition = new Vector3(0, 1.5f, 0); } return agentInstance; } /// /// 插入一个普通怪,使用Wave内的第一个数据 /// /// public void SpawnCommonAgent( int idspawn,float health,float speed,int gold ) { //try { var agentConfig = agentConfigurationList[idspawn]; this.bReSpawnState = false; Agent ag = SpawnAgent(agentConfig, this.startingNode, health, speed, gold ,true ); this.bReSpawnState = true; /*}catch( System.Exception e) { Debug.Log("发布怪物出错:" + e.ToString() + " 怪物ID:" + idspawn ); }*/ } /// /// Launch the waveCompleted event /// 其实就是执行当前Wave完成Action,名字起的过于复杂了。 /// protected void SafelyBroadcastWaveCompletedEvent() { if (waveCompleted != null) { waveCompleted(); } } } }