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