Files
Zombie/Assets/_Zombie/Scripts/GameManager.cs
2025-08-28 10:44:46 +08:00

835 lines
22 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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,
}
public class GameManager : NetworkBehaviour
{
public static GameManager Ins { get; private set; }
#region
public GameObject PowerCorePre;
public GameObject DoorPre;
public GameObject gunPropPre;
// 炮塔预制体集合
public GameObject[] TowerPres;
// 怪物预制集合
public GameObject[] EnemyPres;
public GameObject explosionPre;
// 怪物ui预制体
public GameObject EnemyUIPre;
#endregion
// json数据库
private JsonLiteDB DB;
// 怪物信息集合
public Dictionary<EnemyType, EnemyInfo> EnemyInfos = new Dictionary<EnemyType, EnemyInfo>();
// 炮塔信息集合
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 List<DefenseInfo> DefenseInfos = new List<DefenseInfo>();
// 剧情信息
public Dictionary<int, CombatUnitInfo> CombatUnitInfos = new Dictionary<int, CombatUnitInfo>();
private List<GameObject> curGunPropList = new List<GameObject>();
public List<Player> players = new List<Player>();
/// <summary>
/// 敌人自增
/// </summary>
private int enemyIndex = 0;
/// <summary>
/// 所有敌人
/// </summary>
public Dictionary<int, Enemy> EnemyList = new Dictionary<int, Enemy>();
/// <summary>
/// 所有敌人UI
/// </summary>
public Dictionary<int, EnemyUI> EnemyUIList = new Dictionary<int, EnemyUI>();
/// <summary>
/// 炮塔自增
/// </summary>
public int towerIndex = 0;
/// <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>();
/// <summary>
/// 波次自增
/// </summary>
[SyncVar]
public int roundIndex = 0;
// 游玩结束时间
[NonSerialized]
[SyncVar]
public long vistEnd = 0;
// 总游玩时长
private int vistAllTime = (int)(60 * 8f);
[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)
{
AuthorPanel.Show();
}
}
/// <summary>
/// 创建门
/// </summary>
public void CreateDoor()
{
UpdateConf();
GameObject door = Instantiate(DoorPre);
NetworkServer.Spawn(door);
door.transform.position = new Vector3(0, 0.05f, 0.2f);
}
/// <summary>
/// 创建初回合
/// </summary>
public void CreateFirstRound()
{
HUDPanel.Show();
roundIndex = 0;
roundWaveTime = 4;
curRoundWaveTime = 1;
SetGameState(GameState.Wave);
RpcMessageRound();
}
/// <summary>
/// 创建下一回合
/// </summary>
public void CreateNextRound()
{
roundIndex++;
SetGameState(GameState.Wave);
roundWaveTime = 15;
curRoundWaveTime = 12;
RpcMessageRound();
}
[Server]
public void GameStart()
{
gameState = GameState.Playing;
vistEnd = (long)(DateTime.Now.Subtract(new DateTime(1970, 1, 1))).TotalSeconds + vistAllTime;
ChangeBgmRpc(1);
// CreateTowers();
AstarPath.active.Scan();
// CreateFirstRound();
CreateFirstRound();
// 延迟1s后给所有人发放武器
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
GivePistol();
}, 1f);
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
GameOver(GameState.Settle);
}, 60f * 10f);
}
[ClientRpc]
public void GivePistol()
{
Debug.Log("创建武器中...");
foreach (Player player in players)
{
player.PickUpGun(GunType.Pistol, -999);
}
}
[Server]
public void SetGameState(GameState state)
{
gameState = state;
}
//1.游戏时间到
//2.所有怪物被消灭
//3.玩家被消灭
//以上都要跳出结算
[Server]
public void GameOver(GameState state)
{
// gameState = state;
// foreach (string key in SettleInfos.Keys)
// {
// string[] titles = { "小菜一碟", "轻松拿捏", "荣耀勇士", "掌控全场", "队伍灵魂"
// ,"荣耀勇士", "团队之星", "颜值担当", "枪法如神", "弹无虚发", "精准猎手", "铁血战士", "无畏先锋", "无所畏惧" };
// SetTitle(key, titles[UnityEngine.Random.Range(0, titles.Length)]);
// SetPlayerName(key);
// }
// string jsonStr = JsonMapper.ToJson(SettleInfos);
// settleData = jsonStr;
// //结算页面
// RpcShow();
// if (blueScore >= redScore)
// {
// RpcShowWin(true);
// }
// else
// {
// RpcShowWin(false);
// }
}
[ClientRpc]
public void RpcShowWin(bool isBlue)
{
}
[ClientRpc]
public void RpcShow()
{
SettlePanel.Show();
}
/// <summary>
/// 下一波进攻开始
/// </summary>
[ClientRpc]
public void RpcMessageRound()
{
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
DragonLi.Core.EventDispatcher.TriggerEvent("NewWaveStart", roundIndex);
}, curRoundWaveTime);
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
DesGunProList();
GetRoundEnemy();
PlaySound2DRPC(roundSound);
SetGameState(GameState.Playing);
}, roundWaveTime);
}
[ClientRpc]
public void ChangeBgmRpc(int i)
{
GameLocal.Ins.BGMState.StateChange(i);
}
/// <summary>
/// 创建炮塔
/// </summary>
public void CreateTowers()
{
foreach (DefenseInfo defenseInfo in DefenseInfos)
{
GameObject tower = Instantiate(TowerPres[(int)defenseInfo.TowerType]);
NetworkServer.Spawn(tower);
tower.transform.position = defenseInfo.BornPos;
tower.transform.eulerAngles = new Vector3(0, defenseInfo.BornAngleY, 0);
towerIndex++;
Tower towerScript = tower.GetComponent<Tower>();
towerScript.OnSpawn(towerIndex, defenseInfo.TowerType, 1);
TowerList.Add(towerIndex, towerScript);
TowerList2.TryGetValue(defenseInfo.TowerType, out List<Tower> towerList);
if (towerList == null)
{
List<Tower> list = new List<Tower>();
list.Add(towerScript);
TowerList2.Add(defenseInfo.TowerType, list);
}
else
{
towerList.Add(towerScript);
}
}
}
public int curRoundEnemyCount;
/// <summary>
/// 创建敌方单位
/// </summary>
IEnumerator CreateEnemy(CombatUnitInfo info)
{
curRoundEnemyCount = info.EnemyTypeList.Length;
for (int i = 0; i < info.EnemyTypeList.Length; i++)
{
GameObject enemy = Instantiate(EnemyPres[info.EnemyTypeList[i]]);
NetworkServer.Spawn(enemy);
int posId = Random.Range(0, 4);
int posX=Random.Range(-1, 1);
int posZ=Random.Range(-1, 1);
enemy.transform.position = GameLocal.Ins.enemyStartPos[posId].position+new Vector3(posX,0,posZ);
enemy.transform.eulerAngles = new Vector3(0, 0, 0);
enemyIndex++;
Enemy enemyScript = enemy.GetComponent<Enemy>();
enemyScript.OnSpawn(enemyIndex, (EnemyType)info.EnemyTypeList[i], 1);
EnemyList.Add(enemyIndex, enemyScript);
yield return new WaitForSeconds(info.BornTime);
}
}
public void CreateBoss()
{
GameObject enemy = Instantiate(EnemyPres[(int)EnemyType.ZombieBoss]);
NetworkServer.Spawn(enemy);
int posId = Random.Range(0, 4);
int posX=Random.Range(-1, 1);
int posZ=Random.Range(-1, 1);
enemy.transform.position = GameLocal.Ins.enemyStartPos[posId].position+new Vector3(posX,0,posZ);
enemy.transform.eulerAngles = new Vector3(0, 0, 0);
enemyIndex++;
Enemy enemyScript = enemy.GetComponent<Enemy>();
enemyScript.OnSpawn(enemyIndex, EnemyType.ZombieBoss, 1);
EnemyList.Add(enemyIndex, enemyScript);
}
public void CreateExplosion(Transform pos,int id)
{
var ex= Instantiate(explosionPre, pos.position, Quaternion.identity);
ex.GetComponent<Explosion>().Init(0);
}
[Server]
public void CreateGunProp()
{
Debug.Log("创建武器");
List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 };
int num1 = numbers[Random.Range(0, numbers.Count)];
numbers.Remove(num1);
int num2 = numbers[Random.Range(0, numbers.Count)];
var gun1= Instantiate(gunPropPre, GameLocal.Ins.gunPropPos[0]);
gun1.GetComponent<WeaponProp>().Init((GunType)num1,20);
curGunPropList.Add(gun1);
var gun2= Instantiate(gunPropPre, GameLocal.Ins.gunPropPos[1]);
gun2.GetComponent<WeaponProp>().Init((GunType)num2,20);
curGunPropList.Add(gun2);
}
/// <summary>
///删除枪械
/// </summary>
public void DesGunProList()
{
if(curGunPropList.Count<=0)
return;
NetworkServer.Destroy(curGunPropList[1]);
NetworkServer.Destroy(curGunPropList[0]);
curGunPropList.Clear();
}
public List<Enemy> GetRoundEnemy()
{
List<Enemy> curEnemyList = new List<Enemy>();
if (roundIndex <= 6)
{
var combatUnitInfo= CombatUnitInfos[roundIndex];
StartCoroutine(CreateEnemy(combatUnitInfo));
}
else
{
int curId = roundIndex;
CombatUnitInfo info = new CombatUnitInfo(curId, curId, GenerateMonsterTypes(), 1);
StartCoroutine(CreateEnemy(info));
}
if (roundIndex % 5 == 0&&roundIndex!=0)
{
CreateBoss();
}
return curEnemyList;
}
public int[] GenerateMonsterTypes()
{
int[] weights = { 2, 6, 1, 3 };
List<int> monsterTypes = new List<int>();
int totalWeight = 0;
int targetWeight = Random.Range(24, 27); // 24-26
int targetCount = Random.Range(5, 11); // 5-10
// 随机添加怪物直到接近目标
while (monsterTypes.Count < targetCount && totalWeight < targetWeight)
{
int index = GetRandomMonsterIndex(weights);
int weight = weights[index];
// 如果剩余位置不够,跳出
if (monsterTypes.Count == targetCount)
break;
// 如果加上这个怪物不会超过目标权重,添加
if (totalWeight + weight <= targetWeight)
{
monsterTypes.Add(index);
totalWeight += weight;
}
else
{
break;
}
}
// 如果权重还没达到目标,填充最小权重怪物
while (totalWeight < targetWeight && monsterTypes.Count < targetCount)
{
int minIndex = GetMinWeightIndex(weights);
monsterTypes.Add(minIndex);
totalWeight += weights[minIndex];
}
return monsterTypes.ToArray();
}
// 根据权重随机选择怪物
private int GetRandomMonsterIndex(int[] weights)
{
int sumWeight = 0;
foreach (var w in weights) sumWeight += w;
int randomValue = Random.Range(0, sumWeight);
int currentSum = 0;
for (int i = 0; i < weights.Length; i++)
{
currentSum += weights[i];
if (randomValue < currentSum)
return i;
}
return 0;
}
// 获取最小权重怪物的索引
private int GetMinWeightIndex(int[] weights)
{
int minIndex = 0;
for (int i = 1; i < weights.Length; i++)
{
if (weights[i] < weights[minIndex])
minIndex = i;
}
return minIndex;
}
/// <summary>
/// 删除敌方单位
/// </summary>
[Server]
public void DeleteEnemy(int id,Transform pos)
{
GameObject enemy = EnemyList[id].gameObject;
EnemyList.Remove(id);
if (id == 2)
{
CreateExplosion(pos,id);
}
curRoundEnemyCount--;
NetworkServer.Destroy(enemy);
if (curRoundEnemyCount<=0)
{
CreateGunProp();
CreateNextRound();
}
}
/// <summary>
/// 痛击场上所有敌方单位
/// </summary>
[Command(requiresAuthority = false)]
public void DamageAllEnemy()
{
foreach (Enemy enemy in EnemyList.Values)
{
enemy.ApplyDamage(999999, null, null);
}
}
public void CreateZombie(Vector3 pos, Vector3 angle)
{
}
public void CreateAir(EnemyType type, Vector3 pos, float angleY)
{
GameObject enemy = Instantiate(EnemyPres[(int)type]);
NetworkServer.Spawn(enemy);
enemy.transform.position = pos;
enemy.transform.eulerAngles = new Vector3(0, angleY, 0);
Airdrop enemyScript = enemy.GetComponent<Airdrop>();
enemyScript.OnSpawn(type, 1);
}
/// <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;
TableReader infoReader = DB["EnemysInfo"].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["DefensesInfo"].GetReader();
while (infoReader.Read())
{
DefenseInfo info = new DefenseInfo(infoReader);
DefenseInfos.Add(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>
/// 获取最近的玩家
/// </summary>
/// <returns></returns>
public GameObject GetPlayer()
{
if (players == null || players.Count == 0)
return null;
GameObject nearestPlayer = null;
float minDistance = float.MaxValue;
foreach (var player in players)
{
if (player == null) continue;
// 计算XZ平面距离使用你的 ReflectVectorXOZ 方法)
float dis = Vector3.Distance(
player.transform.position.ReflectVectorXOZ(),
transform.position.ReflectVectorXOZ()
);
if (dis < minDistance)
{
minDistance = dis;
nearestPlayer = player.gameObject;
}
}
return nearestPlayer;
}
public bool IsPlayerReady()
{
foreach (var player in players )
{
if (!player.isGameReady)
return false;
}
return true;
}
[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(1);
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);
}
#region
public string GetLessTimeStr()
{
string res = "";
if (gameState == GameState.Playing)
{
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
[ClientRpc]
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);
}
[ClientRpc]
public void PlayJointMusic()
{
MasterAudio.PlaySound(JointIn);
GameLocal.Ins.BGMState.StateChange(2);
}
}