538 lines
14 KiB
C#
538 lines
14 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines;
|
||
using Common;
|
||
using DamageNumbersPro;
|
||
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 Unity.Mathematics;
|
||
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,
|
||
Waiting= 5,
|
||
}
|
||
|
||
public class GameManager : NetworkBehaviour
|
||
{
|
||
public static GameManager Ins { get; private set; }
|
||
|
||
#region 预制体
|
||
public GameObject redDoorPre;
|
||
public GameObject blueDoorPre;
|
||
public GameObject AirdropPlanePre;//空投飞机
|
||
public GameObject[] airdropItems;//空头道具
|
||
|
||
public GameObject startGameItemPre;
|
||
|
||
public GameObject damageNumberPre;
|
||
public GameObject redDamageNumberPre;
|
||
|
||
// 怪物ui预制体
|
||
public GameObject EnemyUIPre;
|
||
|
||
#endregion
|
||
|
||
#region 实例化后物体
|
||
|
||
public GameObject redDoor;
|
||
public GameObject blueDoor;
|
||
|
||
#endregion
|
||
|
||
// json数据库
|
||
private JsonLiteDB DB;
|
||
|
||
// 怪物信息集合
|
||
public Dictionary<EnemyType, Dictionary<int, EnemyInfo>> EnemyInfos = new Dictionary<EnemyType, Dictionary<int, EnemyInfo>>();
|
||
|
||
// 枪械信息集合
|
||
public Dictionary<GunType, Dictionary<int, GunInfo>> GunInfos = new Dictionary<GunType, Dictionary<int, GunInfo>>();
|
||
|
||
/// <summary>
|
||
/// 所有敌人UI
|
||
/// </summary>
|
||
public Dictionary<int, PlayerUI> EnemyUIList = new Dictionary<int, PlayerUI>();
|
||
|
||
public Dictionary<string, SettleInfo> SettleInfos = new Dictionary<string, SettleInfo>();
|
||
|
||
public List<Player> allPlayers = new List<Player>();
|
||
|
||
// 游玩结束时间
|
||
[NonSerialized]
|
||
[SyncVar]
|
||
public long vistEnd = 0;
|
||
// 总游玩时长
|
||
private int vistAllTime = (int)(60 * 10f);
|
||
[SyncVar]
|
||
public string settleData = "";
|
||
|
||
[SyncVar]
|
||
public GameState gameState = GameState.None;
|
||
|
||
[NonSerialized]
|
||
[SyncVar]
|
||
public int blueScore = 0;
|
||
[NonSerialized]
|
||
[SyncVar]
|
||
public int redScore = 0;
|
||
|
||
void Awake()
|
||
{
|
||
Ins = this;
|
||
}
|
||
|
||
void Start()
|
||
{
|
||
if (isClient)
|
||
{
|
||
AuthorPanel.Show();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建门
|
||
/// </summary>
|
||
[Server]
|
||
public void CreateDoor(Transform redPos, Transform bluePos,Transform startGamePos)
|
||
{
|
||
SetGameState(GameState.Waiting);
|
||
if(!isServer)
|
||
return;
|
||
//创建红色门
|
||
redDoor = Instantiate(redDoorPre,redPos.position,Quaternion.identity);
|
||
NetworkServer.Spawn(redDoor);
|
||
|
||
//创建蓝色门
|
||
blueDoor = Instantiate(blueDoorPre,bluePos.position,Quaternion.identity);
|
||
NetworkServer.Spawn(blueDoor);
|
||
|
||
//创建开始球
|
||
GameObject gameStartObj = Instantiate(startGameItemPre,startGamePos.position,Quaternion.identity);
|
||
NetworkServer.Spawn(gameStartObj);
|
||
|
||
//测试枪械
|
||
//GameLocal.Ins.self.GivePistol();
|
||
}
|
||
|
||
[Server]
|
||
// public void CreateDamageNumber(float damage ,Vector3 pos,bool isCritical)
|
||
// {
|
||
// if (damageNumberPre == null || redDamageNumberPre == null)
|
||
// {
|
||
// Debug.LogWarning("伤害字体预制体未设置!");
|
||
// return;
|
||
// }
|
||
//
|
||
// GameObject prefab = isCritical ? redDamageNumberPre : damageNumberPre;
|
||
// GameObject obj = Instantiate(prefab, pos, Quaternion.identity);
|
||
//
|
||
// // DamageNumbersPro 的核心组件
|
||
// var dmg = obj.GetComponent<DamageNumberNetwork>();
|
||
// if (dmg != null)
|
||
// {
|
||
// dmg.worldPos = pos;
|
||
// dmg.damageValue = isCritical? damage*2 : damage;
|
||
// dmg.OnStartClient();
|
||
// }
|
||
//
|
||
// // 网络生成(让客户端也能看到)
|
||
// NetworkServer.Spawn(obj);
|
||
// CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
// {
|
||
// NetworkServer.Destroy(obj);
|
||
// }, 10);
|
||
//
|
||
// }
|
||
|
||
[ClientRpc]
|
||
public void RpcShowDamageNumber(float damage, Vector3 pos, bool isCritical)
|
||
{
|
||
GameObject prefab = isCritical ? redDamageNumberPre : damageNumberPre;
|
||
if (prefab == null) return;
|
||
|
||
GameObject obj = Instantiate(prefab, pos, Quaternion.identity);
|
||
var dmg = obj.GetComponent<DamageNumberNetwork>();
|
||
if (dmg != null)
|
||
{
|
||
dmg.worldPos = pos;
|
||
dmg.damageValue = isCritical? damage*2 : damage;
|
||
dmg.OnStartClient();
|
||
}
|
||
Destroy(obj, 10f);
|
||
}
|
||
|
||
[Server]
|
||
public void GameStart()
|
||
{
|
||
AutoAssignTeams();
|
||
gameState = GameState.Playing;
|
||
vistEnd = (long)(DateTime.Now.Subtract(new DateTime(1970, 1, 1))).TotalSeconds + vistAllTime;
|
||
_airdropTime = 25;
|
||
_curAirdropTime = _airdropTime;
|
||
RpcShowHUD();
|
||
ChangeBgmRpc(1);
|
||
StartAirDrop();
|
||
//AstarPath.active.Scan();
|
||
NetworkServer.Destroy(redDoor);
|
||
NetworkServer.Destroy(blueDoor);
|
||
|
||
// 延迟1s后给所有人发放武器
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
foreach (var item in NetworkServer.connections.Values)
|
||
{
|
||
Player player = item.identity.GetComponent<Player>();
|
||
if (player != null)
|
||
{
|
||
player.HideInvincible();
|
||
}
|
||
}
|
||
RpcShowSettle();
|
||
}, 1f);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
GameOver();
|
||
}, vistAllTime);
|
||
}
|
||
|
||
[Server]
|
||
public void RegisterPlayer(Player p)
|
||
{
|
||
if (!allPlayers.Contains(p))
|
||
allPlayers.Add(p);
|
||
}
|
||
|
||
|
||
// ★ 玩家离开游戏时调用(在Player.OnStopServer里调用)
|
||
[Server]
|
||
public void UnRegisterPlayer(Player p)
|
||
{
|
||
if (allPlayers.Contains(p))
|
||
allPlayers.Remove(p);
|
||
}
|
||
|
||
// ★ 游戏开始时调用 → 自动分配队伍
|
||
[Server]
|
||
public void AutoAssignTeams()
|
||
{
|
||
int redCount = 0;
|
||
int blueCount = 0;
|
||
|
||
// 计算已分配队伍的人数
|
||
foreach (var p in allPlayers)
|
||
{
|
||
if (p.teamType == TeamType.Red) redCount++;
|
||
else if (p.teamType == TeamType.Blue) blueCount++;
|
||
}
|
||
|
||
// 遍历玩家 → 给没选队伍的自动分配
|
||
foreach (var p in allPlayers)
|
||
{
|
||
if (p.teamType != TeamType.None)
|
||
continue;
|
||
|
||
// 队伍数量对比
|
||
if (redCount < blueCount)
|
||
{
|
||
p.teamType = TeamType.Red;
|
||
redCount++;
|
||
}
|
||
else if (blueCount < redCount)
|
||
{
|
||
p.teamType = TeamType.Blue;
|
||
blueCount++;
|
||
}
|
||
else
|
||
{
|
||
// 一样多 → 随机
|
||
if (Random.value > 0.5f)
|
||
{
|
||
p.teamType = TeamType.Red;
|
||
redCount++;
|
||
}
|
||
else
|
||
{
|
||
p.teamType = TeamType.Blue;
|
||
blueCount++;
|
||
}
|
||
}
|
||
GivePistol(p.index);
|
||
}
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void RpcShowSettle()
|
||
{
|
||
GameLocal.Ins.Settle.SetActive(true);
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void GivePistol(int index)
|
||
{
|
||
Debug.Log("创建武器中...");
|
||
foreach (var item in NetworkServer.connections.Values)
|
||
{
|
||
Player player = item.identity.GetComponent<Player>();
|
||
if (player != null&&player.index == index)
|
||
{
|
||
player.GivePistol();
|
||
player.GiveArmor();
|
||
}
|
||
}
|
||
}
|
||
|
||
[Server]
|
||
public void SetGameState(GameState state)
|
||
{
|
||
gameState = state;
|
||
}
|
||
|
||
[Server]
|
||
public void GameOver()
|
||
{
|
||
gameState = GameState.Settle;
|
||
if (blueScore >= redScore)
|
||
{
|
||
RpcShowWin(true);
|
||
}
|
||
else
|
||
{
|
||
RpcShowWin(false);
|
||
}
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void RpcShowWin(bool isBlue)
|
||
{
|
||
GameLocal.Ins.Settle.SetActive(false);
|
||
if (isBlue)
|
||
{
|
||
GameLocal.Ins.BlueWin.SetActive(true);
|
||
}
|
||
else
|
||
{
|
||
GameLocal.Ins.RedWin.SetActive(true);
|
||
}
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void RpcShow()
|
||
{
|
||
SettlePanel.Show();
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void ChangeBgmRpc(int i)
|
||
{
|
||
GameLocal.Ins.BGMState.StateChange(i);
|
||
}
|
||
|
||
[Server]
|
||
public void CreateAirdropPlane(Vector3 startPos, Vector3 endPos)
|
||
{
|
||
GameObject airdropPlane = Instantiate(AirdropPlanePre,startPos,quaternion.identity);
|
||
NetworkServer.Spawn(airdropPlane);
|
||
AirdropPlane airdropPlaneScript = airdropPlane.GetComponent<AirdropPlane>();
|
||
airdropPlaneScript.OnSpawn(endPos);
|
||
}
|
||
|
||
[Server]
|
||
public void CreateAirDropItem(int id ,Vector3 startPos)
|
||
{
|
||
GameObject airdropItem = Instantiate(airdropItems[id],startPos,quaternion.identity);
|
||
NetworkServer.Spawn(airdropItem);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 痛击场上所有敌方单位
|
||
/// </summary>
|
||
[Command(requiresAuthority = false)]
|
||
public void DamageAllEnemy()
|
||
{
|
||
|
||
}
|
||
|
||
/// <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);
|
||
|
||
TableReader infoReader = DB["GunsInfo"].GetReader();
|
||
while (infoReader.Read())
|
||
{
|
||
GunInfo info = new GunInfo(infoReader);
|
||
GunInfos.TryGetValue((GunType)info.Type, out Dictionary<int, GunInfo> infoList);
|
||
if (infoList == null)
|
||
{
|
||
Dictionary<int, GunInfo> list = new Dictionary<int, GunInfo>();
|
||
list.Add(info.Lvl, info);
|
||
GunInfos.Add((GunType)info.Type, list);
|
||
}
|
||
else
|
||
{
|
||
infoList.Add(info.Lvl, info);
|
||
}
|
||
}
|
||
|
||
Debug.Log("游戏数值更新 -> complete");
|
||
}
|
||
|
||
[Server]
|
||
public void CreateEnemyUI(Enemy enemy)
|
||
{
|
||
GameObject enemyUI = Instantiate(EnemyUIPre);
|
||
NetworkServer.Spawn(enemyUI);
|
||
PlayerUI enemyUIScript = enemyUI.GetComponent<PlayerUI>();
|
||
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();
|
||
}
|
||
|
||
[Server]
|
||
public void AddData(int playerIndex)
|
||
{
|
||
SettleInfos.Add(playerIndex.ToString(), new SettleInfo());
|
||
}
|
||
|
||
#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()
|
||
{
|
||
if (isServer)
|
||
{
|
||
return (int)(vistEnd - NetworkTime.time);
|
||
}
|
||
else
|
||
{
|
||
return (int)(vistEnd - NetworkClient.connection.remoteTimeStamp);
|
||
}
|
||
}
|
||
|
||
// 时分秒
|
||
public string FormatTime(int totalSeconds)
|
||
{
|
||
//确保时间不为负
|
||
totalSeconds = Mathf.Max(0, 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);
|
||
}
|
||
|
||
[SyncVar]
|
||
private int syncRemainingTime;
|
||
|
||
private float _airdropTime;//空投时间
|
||
private float _curAirdropTime;//当前空头时间
|
||
private bool _isStartAirdrop;//是否开始倒计时空投
|
||
|
||
public void StartAirDrop()
|
||
{
|
||
_isStartAirdrop = true;
|
||
}
|
||
|
||
public void StopAirDrop()
|
||
{
|
||
_isStartAirdrop = false;
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
if (isServer&& gameState==GameState.Playing&&_isStartAirdrop)
|
||
{
|
||
//服务器计算剩余时间并同步
|
||
//syncRemainingTime = GetLessTimeSeconds();
|
||
_curAirdropTime+=Time.deltaTime;
|
||
if (_curAirdropTime >= _airdropTime)
|
||
{
|
||
int airdropPosId = Random.Range(0, 4);
|
||
int endAirdropPosId =0;
|
||
if (airdropPosId == 0)
|
||
endAirdropPosId = 1;
|
||
if (airdropPosId == 1)
|
||
endAirdropPosId = 0;
|
||
if (airdropPosId == 2)
|
||
endAirdropPosId = 3;
|
||
if (airdropPosId == 3)
|
||
endAirdropPosId = 2;
|
||
CreateAirdropPlane(GameLocal.Ins.startPlanePos[airdropPosId].position,GameLocal.Ins.startPlanePos[endAirdropPosId].position);
|
||
_curAirdropTime = 0;
|
||
StopAirDrop();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|