1241 lines
36 KiB
C#
1241 lines
36 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines;
|
||
using Common;
|
||
using DragonLi.Core;
|
||
using Mirror;
|
||
using UnityEngine;
|
||
using UnityEngine.PlayerLoop;
|
||
using XPlugin.Data.JsonLiteDB;
|
||
using static XPlugin.Data.JsonLiteDB.JsonLiteDB;
|
||
using LitJson;
|
||
using Pathfinding;
|
||
using DarkTonic.MasterAudio;
|
||
using NaughtyAttributes;
|
||
using UnityEngine.UIElements;
|
||
using Random = UnityEngine.Random;
|
||
|
||
|
||
/// <summary>
|
||
/// 游戏状态
|
||
/// </summary>
|
||
public enum GameState
|
||
{
|
||
None = 0,
|
||
Playing = 1,
|
||
/// <summary>
|
||
/// 胜利
|
||
/// </summary>
|
||
Victory = 2,
|
||
/// <summary>
|
||
/// 失败
|
||
/// </summary>
|
||
Failur = 3,
|
||
Settle=4,
|
||
/// <summary>
|
||
/// 准备阶段
|
||
/// </summary>
|
||
Wave=5,
|
||
/// <summary>
|
||
/// 冲锋阶段
|
||
/// </summary>
|
||
EndEvent,
|
||
}
|
||
|
||
public enum GameEnemyEventType
|
||
{
|
||
None=0,//普通事件
|
||
Snipe=1,//狙击事件
|
||
Mortar=2,//迫击炮事件
|
||
MachineGun=3,//机关枪事件
|
||
SubmachineGun=4,//冲锋枪事件
|
||
Grenade=5,//手榴弹事件
|
||
Biochemical=6,//生化兵事件
|
||
Tank=7,//坦克兵事件
|
||
Bomber=8,//轰炸机事件
|
||
HelpNpc=9,//拯救平民事件
|
||
BulletUp=10,//子弹拾取事件
|
||
CleanUp=11,//清场事件
|
||
LastGame=12,//最终冲锋事件
|
||
}
|
||
|
||
public enum GameMode
|
||
{
|
||
OnePlayer=0,
|
||
TwoPlayers=1,
|
||
}
|
||
|
||
|
||
public class GameManager : NetworkBehaviour
|
||
{
|
||
public static GameManager Ins { get; private set; }
|
||
|
||
#region 预制体
|
||
public GameObject DoorPre;
|
||
public GameObject itemPropPre;
|
||
public GameObject mortarBulletPre;
|
||
public GameObject gqBulletPre;
|
||
public GameObject gqMuzzleBulletPre;
|
||
// 炮塔预制体集合
|
||
//public GameObject[] TowerPres;
|
||
// 怪物预制集合
|
||
public GameObject[] EnemyPres;
|
||
|
||
public GameObject[] playerAiPres;
|
||
|
||
public GameObject playerEndAiPres;
|
||
|
||
public GameObject explosionPre;
|
||
|
||
public GameObject enemyGrenadePre;
|
||
|
||
public GameObject enemyGasBombPre;
|
||
|
||
public GameObject enemyEndAiPre;
|
||
|
||
public GameObject enemyPlanePre;
|
||
|
||
public GameObject[] playerNpcPre;
|
||
// 怪物ui预制体
|
||
public GameObject EnemyUIPre;
|
||
#endregion
|
||
// json数据库
|
||
private JsonLiteDB DB;
|
||
// 怪物信息集合
|
||
//public Dictionary<EnemyType, EnemyInfo> EnemyInfos = new Dictionary<EnemyType, EnemyInfo>();
|
||
|
||
public Dictionary<int,AiInfo> PlayerAiInfos = new Dictionary<int,AiInfo>();
|
||
|
||
// 炮塔信息集合
|
||
public Dictionary<TowerType, Dictionary<int, TowerInfo>> TowerInfos = new Dictionary<TowerType, Dictionary<int, TowerInfo>>();
|
||
// 枪械信息集合
|
||
//public Dictionary<GunType, GunInfo> GunInfos = new Dictionary<GunType, GunInfo>();
|
||
// 子弹信息集合
|
||
public Dictionary<BulletType, BulletInfo> BulletInfos = new Dictionary<BulletType,BulletInfo>();
|
||
|
||
public Dictionary<int,AiInfo> AiInfos = new Dictionary<int,AiInfo>();
|
||
|
||
public Dictionary<int,RoundInfo> RoundInfos = new Dictionary<int,RoundInfo>();
|
||
|
||
// 剧情信息
|
||
public Dictionary<int, CombatUnitInfo> CombatUnitInfos = new Dictionary<int, CombatUnitInfo>();
|
||
|
||
private List<GameObject> curGunPropList = new List<GameObject>();
|
||
|
||
public Dictionary<int, Player> players = new Dictionary<int, Player>();
|
||
|
||
public GameMode gameMode = GameMode.OnePlayer;
|
||
|
||
/// <summary>
|
||
/// 敌人自增
|
||
/// </summary>
|
||
private int enemyIndex = 0;
|
||
|
||
/// <summary>
|
||
/// 所有敌人
|
||
/// </summary>
|
||
public Dictionary<int, Enemy> EnemyList = new Dictionary<int, Enemy>();
|
||
|
||
public Dictionary<int,PlayerAI> PlayerAiList = new Dictionary<int,PlayerAI>();
|
||
|
||
/// <summary>
|
||
/// 所有敌人UI
|
||
/// </summary>
|
||
public Dictionary<int, EnemyUI> EnemyUIList = new Dictionary<int, EnemyUI>();
|
||
|
||
/// <summary>
|
||
/// 所有炮塔
|
||
/// </summary>
|
||
public Dictionary<int, Tower> TowerList = new Dictionary<int, Tower>();
|
||
|
||
public Dictionary<TowerType, List<Tower>> TowerList2 = new Dictionary<TowerType, List<Tower>>();
|
||
|
||
public Dictionary<string, SettleInfo> SettleInfos = new Dictionary<string, SettleInfo>();
|
||
|
||
//public List<Enemy> curEnemyList = new List<Enemy>();
|
||
|
||
[SyncVar]
|
||
public bool isStart;
|
||
/// <summary>
|
||
/// 波次自增
|
||
/// </summary>
|
||
[SyncVar]
|
||
public int roundIndex = 0;
|
||
// 游玩结束时间
|
||
[NonSerialized]
|
||
[SyncVar]
|
||
public long vistEnd = 0;
|
||
// 总游玩时长
|
||
private int vistAllTime = (int)(60*12 );
|
||
[SyncVar]
|
||
public string settleData = "";
|
||
|
||
[SyncVar]
|
||
public GameState gameState = GameState.None;
|
||
[SoundGroup] public string JointIn;
|
||
[SoundGroup] public string roundSound;
|
||
|
||
public int roundWaveTime;
|
||
public int curRoundWaveTime;
|
||
|
||
void Awake()
|
||
{
|
||
Ins = this;
|
||
}
|
||
|
||
void Start()
|
||
{
|
||
if (isClient)
|
||
{
|
||
isStart = false;
|
||
CreateDoor();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建门
|
||
/// </summary>
|
||
public void CreateDoor()
|
||
{
|
||
UpdateConf();
|
||
if(!isServer)
|
||
return;
|
||
GameObject door = Instantiate(DoorPre);
|
||
door.transform.position = GameLocal.Ins.doorPos.position.ReflectVectorXOZ();
|
||
NetworkServer.Spawn(door);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建初回合
|
||
/// </summary>
|
||
public void CreateFirstRound()
|
||
{
|
||
RpcShowHUD();
|
||
roundIndex = 0;
|
||
PlaySound2DRPC("1.0");
|
||
// CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
// {
|
||
// PlaySound2DRPC("1.1");
|
||
// }, 10f);
|
||
CreatePlayerAi();
|
||
//SetGameState(GameState.Wave);
|
||
RpcMessageRound();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建下一回合
|
||
/// </summary>
|
||
public void CreateNextRound()
|
||
{
|
||
roundIndex++;
|
||
roundWaveTime = 3;
|
||
curRoundWaveTime = 1;
|
||
RpcMessageRound();
|
||
}
|
||
|
||
[Server]
|
||
public void GameStart()
|
||
{
|
||
gameState = GameState.Playing;
|
||
gameMode=players.Count<=1 ? GameMode.OnePlayer : GameMode.TwoPlayers;
|
||
vistEnd = (long)(DateTime.Now.Subtract(new DateTime(1970, 1, 1))).TotalSeconds + vistAllTime;
|
||
isStart = true;
|
||
ChangeBgmRpc(0);
|
||
AstarPath.active.Scan();
|
||
CreateFirstRound();
|
||
// 延迟1s后给所有人发放武器
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
GivePistol(GunType.Pistol);
|
||
}, 1f);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
//GameOver(GameState.Settle);
|
||
StartSpecialEvent(GameEnemyEventType.CleanUp);
|
||
}, vistAllTime);
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void GivePistol(GunType type)
|
||
{
|
||
Debug.Log("创建武器中...");
|
||
GameLocal.Ins.self.PickUpGun(type, -999);
|
||
}
|
||
|
||
[Server]
|
||
public void SetGameState(GameState state)
|
||
{
|
||
gameState = state;
|
||
}
|
||
|
||
//1.游戏时间到
|
||
//2.所有怪物被消灭
|
||
//3.玩家被消灭
|
||
//以上都要跳出结算
|
||
|
||
[Server]
|
||
public void GameOver()
|
||
{
|
||
RpcShow();
|
||
DamageAllEnemy();
|
||
isStart = false;
|
||
PlaySound2DRPC("1.60");
|
||
}
|
||
|
||
[Server]
|
||
public void PlayEndEvent()
|
||
{
|
||
Debug.LogError("开启End事件");
|
||
gameState = GameState.EndEvent;
|
||
GivePistol(GunType.MeleeWeapon);
|
||
foreach (var item in PlayerAiList.Values)
|
||
{
|
||
item.EndEvent();
|
||
}
|
||
PlaySound2DRPC("1.61");
|
||
OpenDoor();
|
||
for (int i = 0; i < 7; i++)
|
||
{
|
||
Transform[] targetPos = GameLocal.Ins.enemyEndPos;
|
||
GameObject enemy = Instantiate(enemyEndAiPre);
|
||
NetworkServer.Spawn(enemy);
|
||
int posId =i/3;
|
||
enemy.transform.position = GameLocal.Ins.enemyStartPos[posId].position;
|
||
enemy.transform.eulerAngles = targetPos[posId].eulerAngles;
|
||
enemyIndex++;
|
||
Enemy enemyScript = enemy.GetComponent<Enemy>();
|
||
enemyScript.OnSpawn(enemyIndex, 3, 1,GameLocal.Ins.pkPos.position);
|
||
enemyScript.ai.maxSpeed = 2;
|
||
EnemyList.Add(enemyIndex, enemyScript);
|
||
|
||
GameObject playerAi = Instantiate(playerEndAiPres);
|
||
NetworkServer.Spawn(playerAi);
|
||
playerAi.transform.position = GameLocal.Ins.endPlayerStartPos.position;
|
||
playerAi.transform.eulerAngles = AiInfos[1].EulerAngles;
|
||
PlayerAI playerAI = playerAi.GetComponent<PlayerAI>();
|
||
playerAI.OnSpawn(i+2,PlayerAIType.EndPlayerAi, 1,enemy);
|
||
playerAI.ai.maxSpeed = 2;
|
||
PlayerAiList.Add(i+2, playerAI);
|
||
}
|
||
curRoundEnemyCount = EnemyList.Count;
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void OpenDoor()
|
||
{
|
||
GameLocal.Ins.OpenDoor();
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void RpcShowWin(bool isBlue)
|
||
{
|
||
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void RpcShow()
|
||
{
|
||
SettlePanel.Show();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 下一波进攻开始
|
||
/// </summary>
|
||
[Server]
|
||
public void RpcMessageRound()
|
||
{
|
||
if(!isStart)
|
||
return;
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
if(!isStart|| gameState== GameState.EndEvent)
|
||
return;
|
||
PlaySound2DRPC("1.4");
|
||
}, curRoundWaveTime);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
if(!isStart|| gameState== GameState.EndEvent)
|
||
return;
|
||
GetRoundEnemy();
|
||
SetGameState(GameState.Playing);
|
||
}, roundWaveTime);
|
||
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void ShowHudRoundTime()
|
||
{
|
||
DragonLi.Core.EventDispatcher.TriggerEvent("NewWaveStart", roundIndex);
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void ChangeBgmRpc(int i)
|
||
{
|
||
GameLocal.Ins.BGMState.StateChange(i);
|
||
}
|
||
|
||
public int curRoundEnemyCount;
|
||
/// <summary>
|
||
/// 创建敌方单位
|
||
/// </summary>
|
||
[Server]
|
||
IEnumerator CreateEnemy(RoundInfo info)
|
||
{
|
||
curRoundEnemyCount = info.EnemyList.Count;
|
||
for (int i = 0; i < info.EnemyList.Count; i++)
|
||
{
|
||
int enemyId = info.EnemyList[i];
|
||
bool isUerInfoAngles = (EnemyType)enemyId == EnemyType.Mortar;
|
||
Transform[] targetPos = GameLocal.Ins.enemyEndPos;
|
||
GameObject enemy = Instantiate(EnemyPres[enemyId-3]);
|
||
NetworkServer.Spawn(enemy);
|
||
int posId =i/3;
|
||
int posX=i%3==0? 0: i%3==1 ? 1 : -1;
|
||
if (isUerInfoAngles)
|
||
posX = 0;
|
||
switch ((EnemyType)enemyId)
|
||
{
|
||
case EnemyType.Ordinary:
|
||
case EnemyType.Sniper:
|
||
break;
|
||
case EnemyType.Mortar:
|
||
targetPos = GameLocal.Ins.mortarPos;
|
||
break;
|
||
}
|
||
enemy.transform.position = GameLocal.Ins.enemyStartPos[posId].position;
|
||
enemy.transform.eulerAngles =isUerInfoAngles? AiInfos[i+3].EulerAngles: targetPos[posId].eulerAngles;
|
||
enemyIndex++;
|
||
Enemy enemyScript = enemy.GetComponent<Enemy>();
|
||
Vector3 endPos = targetPos[posId].position + new Vector3(0, 0, posX);
|
||
if (enemyScript.type == EnemyType.Riflemen)
|
||
{
|
||
endPos = GameLocal.Ins.riflemenPos.position;
|
||
}
|
||
enemyScript.OnSpawn(enemyIndex, info.EnemyList[i], 1,endPos);
|
||
EnemyList.Add(enemyIndex, enemyScript);
|
||
yield return new WaitForSeconds(0.5f);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建辅助AI
|
||
/// </summary>
|
||
public void CreatePlayerAi()
|
||
{
|
||
for (int i = 0; i < 2; i++)
|
||
{
|
||
GameObject playerAi = Instantiate(playerAiPres[i]);
|
||
NetworkServer.Spawn(playerAi);
|
||
playerAi.transform.position = GameLocal.Ins.playerAiPos[i].position;
|
||
playerAi.transform.eulerAngles = AiInfos[i+1].EulerAngles;
|
||
PlayerAI enemyScript = playerAi.GetComponent<PlayerAI>();
|
||
enemyScript.OnSpawn(i,(PlayerAIType)i, 1,GameLocal.Ins.playerAiEndPos[i].gameObject);
|
||
PlayerAiList.Add(i, enemyScript);
|
||
}
|
||
// else if(gameMode == GameMode.TwoPlayers)
|
||
// {
|
||
// GameObject playerAi = Instantiate(playerAiPres[0]);
|
||
// NetworkServer.Spawn(playerAi);
|
||
// playerAi.transform.position = GameLocal.Ins.playerAiPos[0].position;
|
||
// playerAi.transform.eulerAngles = AiInfos[1].EulerAngles;
|
||
// PlayerAI enemyScript = playerAi.GetComponent<PlayerAI>();
|
||
// enemyScript.OnSpawn(0,0, 1,GameLocal.Ins.playerAiEndPos[0].gameObject);
|
||
// PlayerAiList.Add(0, enemyScript);
|
||
// }
|
||
}
|
||
|
||
#region 创造敌人道具
|
||
|
||
[Server]
|
||
public void CreateExplosion(Vector3 pos,EnemyType type)
|
||
{
|
||
if(!isServer)
|
||
return;
|
||
var ex= Instantiate(explosionPre, pos, Quaternion.identity);
|
||
NetworkServer.Spawn(ex);
|
||
ex.GetComponent<Explosion>().Init(type);
|
||
}
|
||
|
||
public void CreateGrenade(Vector3 startPos)
|
||
{
|
||
if(!isServer)
|
||
return;
|
||
var ex= Instantiate(enemyGrenadePre, startPos, Quaternion.identity);
|
||
NetworkServer.Spawn(ex);
|
||
float x=Random.Range(-3,3);
|
||
float z=Random.Range(-3,3);
|
||
ex.GetComponent<Grenade>().Init(startPos, GameLocal.Ins.endMortarPos.position+new Vector3(x,0,z));
|
||
}
|
||
|
||
public void CreateGasBomb(Vector3 startPos)
|
||
{
|
||
if(!isServer)
|
||
return;
|
||
var ex= Instantiate(enemyGasBombPre, startPos, Quaternion.identity);
|
||
NetworkServer.Spawn(ex);
|
||
float x=Random.Range(-3,3);
|
||
float z=Random.Range(-3,3);
|
||
ex.GetComponent<Grenade>().Init(startPos,GameLocal.Ins.endMortarPos.position+new Vector3(x,0,z));
|
||
}
|
||
|
||
public void CreateEnemyPlane(Transform startPos)
|
||
{
|
||
if(!isServer)
|
||
return;
|
||
var ex= Instantiate(enemyPlanePre, startPos.position, Quaternion.identity);
|
||
NetworkServer.Spawn(ex);
|
||
}
|
||
public void CreateItemProp(Transform pos)
|
||
{
|
||
if(!isStart)
|
||
return;
|
||
var item= Instantiate(itemPropPre);
|
||
NetworkServer.Spawn(item);
|
||
item.transform.position=new Vector3(pos.position.x,0.5f,pos.position.z);
|
||
item.GetComponent<ItemProp>().SetItemProp(ItemPropType.Hp);
|
||
}
|
||
|
||
#endregion
|
||
|
||
public List<Enemy> GetRoundEnemy()
|
||
{
|
||
List<Enemy> curEnemyList = new List<Enemy>();
|
||
int curRoundIndex=roundIndex>= RoundInfos.Count? Random.Range(1,RoundInfos.Count):roundIndex;
|
||
var roundInfo=RoundInfos[curRoundIndex];
|
||
// curRoundIndex=5;
|
||
// roundInfo= RoundInfos[curRoundIndex];
|
||
StartEvent(roundInfo);
|
||
if (roundIndex%5==0&&roundIndex!=0)
|
||
{
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
StartSpecialEvent(GameEnemyEventType.HelpNpc);
|
||
}, 5);
|
||
}
|
||
return curEnemyList;
|
||
}
|
||
|
||
public GameEnemyEventType curEnemyEventType;
|
||
public void StartEvent(RoundInfo info)
|
||
{
|
||
curEnemyEventType = (GameEnemyEventType)info.Belong;
|
||
StartCoroutine(CreateEnemy(info));
|
||
switch (curEnemyEventType)
|
||
{
|
||
case GameEnemyEventType.SubmachineGun:
|
||
case GameEnemyEventType.None:
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
Debug.LogError("播放音效:1.10");
|
||
PlayerAiList[0].PlaySound3DRPC("1.10",true);
|
||
EnemyShowOutline(EnemyType.Ordinary);
|
||
EnemyShowOutline(EnemyType.Charge);
|
||
}, 10);
|
||
break;
|
||
case GameEnemyEventType.Snipe:
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.14",true);
|
||
}, 5);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.15",true);
|
||
EnemyShowOutline(EnemyType.Sniper);
|
||
}, 7);
|
||
break;
|
||
case GameEnemyEventType.Mortar:
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.20",true);
|
||
StartCoroutine(CreateMortarBullet());
|
||
}, 7);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.21",true);
|
||
EnemyShowOutline(EnemyType.Mortar);
|
||
}, 10);
|
||
break;
|
||
case GameEnemyEventType.MachineGun:
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.24",true);
|
||
StartCoroutine(CreateGQBullet());
|
||
}, 7);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.25",true);
|
||
EnemyShowOutline( EnemyType.Riflemen);
|
||
}, 10);
|
||
break;
|
||
case GameEnemyEventType.Grenade:
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.35",true);
|
||
}, 5);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.38",true);
|
||
EnemyShowOutline(EnemyType.Grenade);
|
||
}, 7);
|
||
break;
|
||
case GameEnemyEventType.Biochemical:
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.40",true);
|
||
}, 5);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.42",true);
|
||
EnemyShowOutline(EnemyType.Virus);
|
||
}, 7);
|
||
break;
|
||
case GameEnemyEventType.Bomber:
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.56",true);
|
||
EnemyShowOutline(EnemyType.Commander);
|
||
EnemyShowOutline(EnemyType.Mortar);
|
||
EnemyShowOutline(EnemyType.Grenade);
|
||
EnemyShowOutline(EnemyType.Virus);
|
||
EnemyShowOutline(EnemyType.Riflemen);
|
||
StartCoroutine(CreateGQBullet());
|
||
StartCoroutine(CreateMortarBullet());
|
||
}, 10);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.59",true);
|
||
|
||
}, 20);
|
||
break;
|
||
}
|
||
}
|
||
|
||
public void StartSpecialEvent(GameEnemyEventType type)
|
||
{
|
||
switch (type)
|
||
{
|
||
case GameEnemyEventType.HelpNpc:
|
||
CreateNpc();
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.67",true);
|
||
}, 5);
|
||
break;
|
||
case GameEnemyEventType.CleanUp:
|
||
CreateEnemyEndBullet();
|
||
break;
|
||
}
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
// if (Input.GetKeyDown(KeyCode.Space))
|
||
// {
|
||
// StartSpecialEvent(GameEnemyEventType.HelpNpc);
|
||
// CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
// {
|
||
// StartSpecialEvent(GameEnemyEventType.CleanUp);
|
||
// }, 5);
|
||
// }
|
||
}
|
||
|
||
IEnumerator CreateMortarBullet()
|
||
{
|
||
Transform insPos=GameLocal.Ins.insMortarPos;
|
||
Transform endPos=GameLocal.Ins.endMortarPos;
|
||
bool isHaveMortar = IsHaveTypeEnemy(EnemyType.Mortar);
|
||
while (isHaveMortar)
|
||
{
|
||
var item= Instantiate(mortarBulletPre);
|
||
NetworkServer.Spawn(item);
|
||
item.transform.position=insPos.position;
|
||
int rangeIndexX = Random.Range(-5, 5);
|
||
int rangeIndexZ = Random.Range(-2, 2);
|
||
item.GetComponent<EnemyMortarBullet>().Init(insPos.position,endPos.position+new Vector3(rangeIndexX,0,rangeIndexZ));
|
||
yield return new WaitForSeconds(AiInfos[(int)EnemyType.Mortar].FiringRate);
|
||
isHaveMortar = IsHaveTypeEnemy(EnemyType.Mortar);
|
||
}
|
||
}
|
||
|
||
IEnumerator CreateGQBullet()
|
||
{
|
||
Transform insPos=GameLocal.Ins.gQPos;
|
||
Vector3 endPos=GameLocal.Ins.riflemenEndPos.position;
|
||
bool isHaveMortar = IsHaveTypeEnemy(EnemyType.Riflemen);
|
||
while (isHaveMortar)
|
||
{
|
||
var item= Instantiate(gqBulletPre);
|
||
NetworkServer.Spawn(item);
|
||
item.transform.position=insPos.position;
|
||
|
||
int rangeIndexZ = Random.Range(-2, 2);
|
||
item.GetComponent<Bullet>().OnSpawn(endPos+new Vector3(rangeIndexZ,0,rangeIndexZ),20);
|
||
|
||
var itemMuzzle= Instantiate(gqMuzzleBulletPre);
|
||
NetworkServer.Spawn(itemMuzzle);
|
||
itemMuzzle.transform.position=insPos.position;
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
NetworkServer.Destroy(itemMuzzle.gameObject);
|
||
}, 1);
|
||
yield return new WaitForSeconds(AiInfos[(int)EnemyType.Riflemen].FiringRate);
|
||
isHaveMortar = IsHaveTypeEnemy(EnemyType.Riflemen);
|
||
}
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void OpenEndBullet()
|
||
{
|
||
GameLocal.Ins.OpenEndBullet();
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void DownEndBullet()
|
||
{
|
||
GameLocal.Ins.DownEndBullet();
|
||
}
|
||
|
||
public List<Enemy> NpcEnemyList = new List<Enemy>();
|
||
public void CreateNpc()
|
||
{
|
||
if (!isStart)
|
||
return;
|
||
|
||
for (int posId = 0; posId < 2; posId++) // npcPos[0] 和 npcPos[1]
|
||
{
|
||
List<GameObject> npcList = new List<GameObject>();
|
||
|
||
// === 生成 3 个 NPC ===
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
int id = Random.Range(0, playerNpcPre.Length);
|
||
|
||
// 在 npcPos 附近生成,带随机偏移
|
||
Vector3 randomOffset = new Vector3(Random.Range(-1f, 1f), 0, Random.Range(-1f, 1f));
|
||
Vector3 npcPos = GameLocal.Ins.npcPos[posId].position + randomOffset;
|
||
|
||
var npc = Instantiate(playerNpcPre[id], npcPos, Quaternion.identity);
|
||
NetworkServer.Spawn(npc);
|
||
|
||
npc.GetComponent<NPC>().OnSpawn(i, GameLocal.Ins.npcEndPos.gameObject, false);
|
||
|
||
npcList.Add(npc);
|
||
}
|
||
|
||
// === 敌人生成逻辑 ===
|
||
// NPC 的平均位置(大致在3个 NPC 中心点)
|
||
Vector3 centerPos = Vector3.zero;
|
||
foreach (var npc in npcList)
|
||
centerPos += npc.transform.position;
|
||
centerPos /= npcList.Count;
|
||
|
||
// 前进方向
|
||
Vector3 forward = GameLocal.Ins.npcPos[posId].forward;
|
||
// 敌人在前进方向的反方向(后面)
|
||
Vector3 backOffset = -forward * 3f; // 敌人与NPC中心点的间隔,数值可调
|
||
|
||
for (int j = 0; j < 2; j++)
|
||
{
|
||
// 敌人横向展开
|
||
Vector3 sideOffset = Vector3.Cross(Vector3.up, forward).normalized * (j == 0 ? -1.5f : 1.5f);
|
||
|
||
Vector3 enemyPos = centerPos + backOffset + sideOffset;
|
||
|
||
var enemy = Instantiate(EnemyPres[0], enemyPos, Quaternion.identity);
|
||
NetworkServer.Spawn(enemy);
|
||
|
||
enemy.GetComponent<Enemy>().OnSpawn(-j, 3, -1, GameLocal.Ins.npcPos[posId].position);
|
||
enemy.GetComponent<Enemy>().isOutLine = true;
|
||
NpcEnemyList.Add(enemy.GetComponent<Enemy>());
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
public void CreateEnemyEndBullet()
|
||
{
|
||
PlayerAiList[0].PlaySound3DRPC("1.65",true);
|
||
OpenEndBullet();
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
foreach (var item in EnemyList.Values)
|
||
{
|
||
item.Die(null,transform);
|
||
}
|
||
foreach (var item in NpcEnemyList)
|
||
{
|
||
item.Die(null,transform);
|
||
}
|
||
}, 5);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
PlayEndEvent();
|
||
DownEndBullet();
|
||
}, 8);
|
||
}
|
||
|
||
public bool IsHaveTypeEnemy(EnemyType curType)
|
||
{
|
||
foreach (var enemy in EnemyList.Values)
|
||
{
|
||
if (enemy.type == curType)
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
public void EnemyShowOutline(EnemyType type)
|
||
{
|
||
foreach (var enemy in EnemyList.Values)
|
||
{
|
||
if (enemy.type == type)
|
||
{
|
||
enemy.isOutLine = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除敌方单位
|
||
/// </summary>
|
||
[Server]
|
||
public void DeleteEnemy(int id,bool isNpcEnemy)
|
||
{
|
||
if (isNpcEnemy)
|
||
{
|
||
foreach (var item in NpcEnemyList)
|
||
{
|
||
if (item.id == id)
|
||
{
|
||
NpcEnemyList.Remove(item);
|
||
NetworkServer.Destroy(item.gameObject);
|
||
return;
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
GameObject enemy = EnemyList[id].gameObject;
|
||
|
||
EnemyList.Remove(id);
|
||
|
||
curRoundEnemyCount--;
|
||
|
||
NetworkServer.Destroy(enemy);
|
||
ChangePlayerAiCountdownTime();
|
||
if (curRoundEnemyCount<=0)
|
||
{
|
||
CreateNextRound();
|
||
if (gameState == GameState.EndEvent)
|
||
{
|
||
gameState = GameState.Victory;
|
||
GameOver();
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 痛击场上所有敌方单位
|
||
/// </summary>
|
||
[Command(requiresAuthority = false)]
|
||
public void DamageAllEnemy()
|
||
{
|
||
foreach (Enemy enemy in EnemyList.Values)
|
||
{
|
||
enemy.ApplyDamage(999999, null, null);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新配置表
|
||
/// </summary>
|
||
public void UpdateConf()
|
||
{
|
||
string text = Resources.Load<TextAsset>("Data").text;
|
||
if (text != null)
|
||
{
|
||
ParseGameJson(text);
|
||
}
|
||
}
|
||
|
||
public void ParseGameJson(string text)
|
||
{
|
||
DB = new JsonLiteDB();
|
||
DB.Load(text);
|
||
|
||
roundWaveTime = 15;
|
||
curRoundWaveTime = 12;
|
||
|
||
AiInfos.Clear();
|
||
RoundInfos.Clear();
|
||
TableReader infoReader = DB["AiInfo"].GetReader();
|
||
// EnemyInfos.Clear();
|
||
// while (infoReader.Read())
|
||
// {
|
||
// EnemyInfo info = new EnemyInfo(infoReader);
|
||
// EnemyInfos.Add((EnemyType)info.Type,info);
|
||
// }
|
||
//
|
||
// infoReader = DB["TowersInfo"].GetReader();
|
||
// while (infoReader.Read())
|
||
// {
|
||
// TowerInfo info = new TowerInfo(infoReader);
|
||
// TowerInfos.TryGetValue((TowerType)info.Type, out Dictionary<int, TowerInfo> infoList);
|
||
// if (infoList == null)
|
||
// {
|
||
// Dictionary<int, TowerInfo> list = new Dictionary<int, TowerInfo>();
|
||
// list.Add(info.Lvl, info);
|
||
// TowerInfos.Add((TowerType)info.Type, list);
|
||
// }
|
||
// else
|
||
// {
|
||
// infoList.Add(info.Lvl, info);
|
||
// }
|
||
// }
|
||
|
||
// infoReader = DB["GunsInfo"].GetReader();
|
||
// GunInfos.Clear();
|
||
// while (infoReader.Read())
|
||
// {
|
||
// GunInfo info = new GunInfo(infoReader);
|
||
// GunInfos.Add((GunType)info.Type,info);
|
||
// }
|
||
//
|
||
// infoReader = DB["BulletsInfo"].GetReader();
|
||
// BulletInfos.Clear();
|
||
// while (infoReader.Read())
|
||
// {
|
||
// BulletInfo info = new BulletInfo(infoReader);
|
||
// BulletInfos.Add((BulletType)info.Type,info);
|
||
// }
|
||
|
||
infoReader = DB["AiInfo"].GetReader();
|
||
while (infoReader.Read())
|
||
{
|
||
AiInfo info = new AiInfo(infoReader);
|
||
AiInfos.Add(info.ID,info);
|
||
}
|
||
|
||
infoReader = DB["RoundInfo"].GetReader();
|
||
while (infoReader.Read())
|
||
{
|
||
RoundInfo info = new RoundInfo(infoReader);
|
||
RoundInfos.Add(info.ID,info);
|
||
}
|
||
|
||
// infoReader = DB["StoryProgressInfo"].GetReader();
|
||
// while (infoReader.Read())
|
||
// {
|
||
// CombatUnitInfo info = new CombatUnitInfo(infoReader);
|
||
// CombatUnitInfos.Add(info.Belong,info);
|
||
// CombatUnitInfos.TryGetValue(info.Belong, out info);
|
||
// }
|
||
|
||
Debug.Log("游戏数值更新 -> complete");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取范围内敌人
|
||
/// </summary>
|
||
public int GetRangeEnemyId(Vector3 pos, float radius)
|
||
{
|
||
int res = -1;
|
||
foreach (Enemy enemy in EnemyList.Values)
|
||
{
|
||
float dis = Vector3.Distance(enemy.transform.position, pos);
|
||
if (dis <= radius)
|
||
{
|
||
radius = dis;
|
||
res = enemy.id;
|
||
break;
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取最近的Ai
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public GameObject GetPlayerAi(Transform curTransform)
|
||
{
|
||
if (PlayerAiList.Count==0 )
|
||
return null;
|
||
GameObject nearestPlayer = null;
|
||
float minDistance = float.MaxValue;
|
||
|
||
foreach (var player in PlayerAiList)
|
||
{
|
||
if (player.Value == null|| player.Key<=1|| player.Value.isGet) continue;
|
||
|
||
// 计算XZ平面距离(使用你的 ReflectVectorXOZ 方法)
|
||
float dis = Vector3.Distance(
|
||
player.Value.transform.position.ReflectVectorXOZ(),
|
||
curTransform.position.ReflectVectorXOZ()
|
||
);
|
||
|
||
if (dis < minDistance)
|
||
{
|
||
minDistance = dis;
|
||
player.Value.isGet = true;
|
||
nearestPlayer = player.Value.gameObject;
|
||
}
|
||
}
|
||
|
||
return nearestPlayer;
|
||
}
|
||
|
||
public GameObject GetPlayer(Transform curTransform)
|
||
{
|
||
if (players == null || players.Count == 0)
|
||
return null;
|
||
|
||
GameObject nearestPlayer = null;
|
||
float minDistance = float.MaxValue;
|
||
|
||
foreach (var player in players.Values)
|
||
{
|
||
if (player == null) continue;
|
||
|
||
// 计算XZ平面距离(使用你的 ReflectVectorXOZ 方法)
|
||
float dis = Vector3.Distance(
|
||
player.transform.position.ReflectVectorXOZ(),
|
||
curTransform.position.ReflectVectorXOZ()
|
||
);
|
||
|
||
if (dis < minDistance)
|
||
{
|
||
minDistance = dis;
|
||
nearestPlayer = player.gameObject;
|
||
}
|
||
}
|
||
|
||
return nearestPlayer;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取最近敌人
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public GameObject GetEnemy(Transform playerAi)
|
||
{
|
||
GameObject nearestPlayer = null;
|
||
float minDis = 999;
|
||
foreach (var enemy in EnemyList.Values)
|
||
{
|
||
if (enemy == null) continue;
|
||
|
||
// 计算XZ平面距离(使用你的 ReflectVectorXOZ 方法)
|
||
float dis = Vector3.Distance(
|
||
enemy.transform.position.ReflectVectorXOZ(),
|
||
playerAi.position.ReflectVectorXOZ()
|
||
);
|
||
|
||
if (dis < minDis)
|
||
{
|
||
nearestPlayer = enemy.gameObject;
|
||
minDis = dis;
|
||
}
|
||
}
|
||
return nearestPlayer;
|
||
}
|
||
|
||
public void ChangePlayerAiCountdownTime()
|
||
{
|
||
foreach (var ai in PlayerAiList.Values)
|
||
{
|
||
ai.ChangeKillEnemyTime();
|
||
}
|
||
}
|
||
|
||
public Transform GetPlayerPos()
|
||
{
|
||
int rand = Random.Range(0, 100);
|
||
|
||
if (players.Count >= 2) // 双人模式
|
||
{
|
||
if (rand < 45) // 0-44
|
||
return players[0].transform; // 玩家A
|
||
else if (rand < 90) // 45-89
|
||
return players[1].transform; // 玩家B
|
||
else // 90-99
|
||
return PlayerAiList[0].transform; // 队友A
|
||
}
|
||
else // 单人模式
|
||
{
|
||
if (rand < 60) // 0-59
|
||
return players[0].transform; // 玩家
|
||
else if (rand < 80) // 60-79
|
||
return PlayerAiList[0].transform; // 队友A
|
||
else // 80-99
|
||
return PlayerAiList[1].transform; // 队友B
|
||
}
|
||
}
|
||
|
||
[Server]
|
||
public void CreateEnemyUI(Enemy enemy)
|
||
{
|
||
GameObject enemyUI = Instantiate(EnemyUIPre);
|
||
NetworkServer.Spawn(enemyUI);
|
||
EnemyUI enemyUIScript = enemyUI.GetComponent<EnemyUI>();
|
||
enemyUIScript.Init(enemy);
|
||
EnemyUIList.Add(enemy.id, enemyUIScript);
|
||
}
|
||
|
||
[Server]
|
||
public void DeleteEnemyUI(int id)
|
||
{
|
||
GameObject enemyUI = EnemyUIList[id].gameObject;
|
||
EnemyUIList.Remove(id);
|
||
NetworkServer.Destroy(enemyUI);
|
||
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void RpcShowHUD()
|
||
{
|
||
HUDPanel.Show();
|
||
}
|
||
|
||
#region 空投道具
|
||
/// <summary>
|
||
/// 修复炮塔
|
||
/// </summary>
|
||
public void RepairTower()
|
||
{
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 进入联控
|
||
/// </summary>
|
||
[Server]
|
||
public void JoinControlTower(int playerIndex)
|
||
{
|
||
PlayJointMusic();
|
||
|
||
// 修改所有炮塔模式
|
||
foreach (Tower tower in TowerList.Values)
|
||
{
|
||
if (tower.controllerId == -1)
|
||
{
|
||
tower.controllerId = playerIndex;
|
||
tower.mode = TowerMode.Joint;
|
||
}
|
||
}
|
||
TriggerEvent("JoinControlStart", playerIndex);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
ChangeBgmRpc(0);
|
||
foreach (Tower tower in TowerList.Values)
|
||
{
|
||
if (tower.mode == TowerMode.Joint)
|
||
{
|
||
tower.controllerId = playerIndex;
|
||
tower.mode = tower.originalMode;
|
||
}
|
||
TriggerEvent("JoinControlEnd", playerIndex);
|
||
}
|
||
}, 30f);
|
||
}
|
||
#endregion
|
||
|
||
[ClientRpc]
|
||
public void TriggerEvent(string key, int param)
|
||
{
|
||
DragonLi.Core.EventDispatcher.TriggerEvent(key, param);
|
||
}
|
||
|
||
public void AddScore(string index, int damage)
|
||
{
|
||
if (SettleInfos.ContainsKey(index))
|
||
{
|
||
SettleInfos[index].Score += damage;
|
||
}
|
||
string jsonStr = JsonMapper.ToJson(SettleInfos);
|
||
settleData = jsonStr;
|
||
}
|
||
|
||
public void SetTitle(string index, string title)
|
||
{
|
||
if (SettleInfos.ContainsKey(index))
|
||
{
|
||
SettleInfos[index].Title = title;
|
||
}
|
||
|
||
Debug.Log(SettleInfos);
|
||
}
|
||
|
||
public void SetPlayerName(string index)
|
||
{
|
||
if (SettleInfos.ContainsKey(index))
|
||
{
|
||
SettleInfos[index].playerName = int.Parse(index);
|
||
}
|
||
}
|
||
|
||
[Server]
|
||
public void AddData(int playerIndex)
|
||
{
|
||
SettleInfos.Add(playerIndex.ToString(), new SettleInfo());
|
||
}
|
||
|
||
public string SerializeSettleInfos()
|
||
{
|
||
return JsonUtility.ToJson(SettleInfos);
|
||
}
|
||
|
||
public bool IsHaveEnemy()
|
||
{
|
||
return EnemyList.Count > 0;
|
||
}
|
||
|
||
#region 工具
|
||
public string GetLessTimeStr()
|
||
{
|
||
string res = "";
|
||
if (isStart)
|
||
{
|
||
res = FormatTime((int)(vistEnd - DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds));
|
||
}
|
||
return res;
|
||
}
|
||
|
||
public int GetLessTimeSeconds()
|
||
{
|
||
return (int)(vistEnd - DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds);
|
||
}
|
||
|
||
// 时分秒
|
||
public string FormatTime(int totalSeconds)
|
||
{
|
||
int hours = totalSeconds / 3600;
|
||
// string hh = hours < 10 ? "0" + hours : hours.ToString();
|
||
int minutes = (totalSeconds - hours * 3600) / 60;
|
||
string mm = minutes < 10f ? "0" + minutes : minutes.ToString();
|
||
int seconds = totalSeconds - hours * 3600 - minutes * 60;
|
||
string ss = seconds < 10 ? "0" + seconds : seconds.ToString();
|
||
return string.Format("{0}:{1}", mm, ss);
|
||
}
|
||
#endregion
|
||
|
||
public void PlaySound2DRPC(string sound)
|
||
{
|
||
MasterAudio.PlaySound(sound);
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void PlaySound3DRPC(string sound,Transform tran,bool isStop)
|
||
{
|
||
if(isStop)
|
||
MasterAudio.StopAllSoundsOfTransform(tran);
|
||
MasterAudio.PlaySound3DAtTransform(sound, tran);
|
||
}
|
||
|
||
public void PlayJointMusic()
|
||
{
|
||
MasterAudio.PlaySound(JointIn);
|
||
GameLocal.Ins.BGMState.StateChange(2);
|
||
}
|
||
}
|
||
|