Files
MRCS/Assets/_MrCs/Scripts/Manager/GameManager.cs

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