fix:补充ai行为流程
This commit is contained in:
13
Assets/_DefendNJ/Scripts/Manager/DefendEventManager.cs
Normal file
13
Assets/_DefendNJ/Scripts/Manager/DefendEventManager.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class DefendEventManager : MonoBehaviour
|
||||
{
|
||||
public Dictionary<int,DefendEvent> defendEventDic = new Dictionary<int,DefendEvent>();
|
||||
|
||||
public void StartEvent(int id)
|
||||
{
|
||||
defendEventDic[id].StartEvent();
|
||||
}
|
||||
}
|
||||
11
Assets/_DefendNJ/Scripts/Manager/DefendEventManager.cs.meta
Normal file
11
Assets/_DefendNJ/Scripts/Manager/DefendEventManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2809f452877aef4d8b8ff4e955a57f9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
955
Assets/_DefendNJ/Scripts/Manager/GameManager.cs
Normal file
955
Assets/_DefendNJ/Scripts/Manager/GameManager.cs
Normal file
@@ -0,0 +1,955 @@
|
||||
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 enum GameMode
|
||||
{
|
||||
OnePlayer=0,
|
||||
TwoPlayers=1,
|
||||
}
|
||||
|
||||
|
||||
public class GameManager : NetworkBehaviour
|
||||
{
|
||||
public static GameManager Ins { get; private set; }
|
||||
|
||||
#region 预制体
|
||||
public GameObject DoorPre;
|
||||
public GameObject gunPropPre;
|
||||
public GameObject itemPropPre;
|
||||
// 炮塔预制体集合
|
||||
//public GameObject[] TowerPres;
|
||||
// 怪物预制集合
|
||||
public GameObject[] EnemyPres;
|
||||
|
||||
public GameObject[] playerAiPres;
|
||||
|
||||
public GameObject explosionPre;
|
||||
// 怪物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*15 );
|
||||
[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++;
|
||||
SetGameState(GameState.Wave);
|
||||
roundWaveTime = 5;
|
||||
curRoundWaveTime = 2;
|
||||
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(1);
|
||||
AstarPath.active.Scan();
|
||||
CreateFirstRound();
|
||||
// 延迟1s后给所有人发放武器
|
||||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||||
{
|
||||
GivePistol();
|
||||
}, 1f);
|
||||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||||
{
|
||||
//GameOver(GameState.Settle);
|
||||
|
||||
PlayEndEvent();
|
||||
}, 60f * 15f);
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void GivePistol()
|
||||
{
|
||||
Debug.Log("创建武器中...");
|
||||
GameLocal.Ins.self.PickUpGun(GunType.Pistol, -999);
|
||||
}
|
||||
|
||||
[Server]
|
||||
public void SetGameState(GameState state)
|
||||
{
|
||||
gameState = state;
|
||||
}
|
||||
|
||||
//1.游戏时间到
|
||||
//2.所有怪物被消灭
|
||||
//3.玩家被消灭
|
||||
//以上都要跳出结算
|
||||
|
||||
[Server]
|
||||
public void GameOver(GameState state)
|
||||
{
|
||||
RpcShow();
|
||||
DamageAllEnemy();
|
||||
gameState = state;
|
||||
isStart = false;
|
||||
// gameState = state;
|
||||
foreach (string key in SettleInfos.Keys)
|
||||
{
|
||||
string[] titles = { "初露锋芒", "小菜一碟", "熟手", "痛并快乐着", "不死传说"
|
||||
,"最强守护者", "独孤求败", "佛系玩家", "午时已到", "神枪手", "弹无虚发", "团队护盾", "我叫MT", "钢铁之躯","道具大师","行走的仓库","永不停歇" };
|
||||
SetTitle(key, titles[Random.Range(0, titles.Length)]);
|
||||
SetPlayerName(key);
|
||||
}
|
||||
string jsonStr = JsonMapper.ToJson(SettleInfos);
|
||||
settleData = jsonStr;
|
||||
// //结算页面
|
||||
// RpcShow();
|
||||
// if (blueScore >= redScore)
|
||||
// {
|
||||
// RpcShowWin(true);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// RpcShowWin(false);
|
||||
// }
|
||||
}
|
||||
|
||||
[Server]
|
||||
public void PlayEndEvent()
|
||||
{
|
||||
foreach (var item in PlayerAiList.Values)
|
||||
{
|
||||
item.EndEvent();
|
||||
}
|
||||
}
|
||||
|
||||
[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)
|
||||
return;
|
||||
PlaySound2DRPC("1.4");
|
||||
}, curRoundWaveTime);
|
||||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||||
{
|
||||
if(!isStart)
|
||||
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>
|
||||
IEnumerator CreateEnemy(RoundInfo info)
|
||||
{
|
||||
curRoundEnemyCount = info.EnemyList.Count;
|
||||
for (int i = 0; i < info.EnemyList.Count; i++)
|
||||
{
|
||||
GameObject enemy = Instantiate(EnemyPres[info.EnemyList[i]]);
|
||||
NetworkServer.Spawn(enemy);
|
||||
int posId =i/3;
|
||||
int posX=i%3==0? 0: i%3==1 ? 1 : -1;
|
||||
enemy.transform.position = GameLocal.Ins.enemyStartPos[posId].position;
|
||||
enemy.transform.eulerAngles = new Vector3(0, 0, 0);
|
||||
enemyIndex++;
|
||||
Enemy enemyScript = enemy.GetComponent<Enemy>();
|
||||
enemyScript.OnSpawn(enemyIndex, (EnemyType)info.EnemyList[i], 1,GameLocal.Ins.enemyStartPos[posId].position+new Vector3(posX,0,0));
|
||||
EnemyList.Add(enemyIndex, enemyScript);
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建辅助AI
|
||||
/// </summary>
|
||||
public void CreatePlayerAi()
|
||||
{
|
||||
if (gameMode == GameMode.OnePlayer)
|
||||
{
|
||||
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 = new Vector3(0, 0, 0);
|
||||
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 = new Vector3(0, 0, 0);
|
||||
PlayerAI enemyScript = playerAi.GetComponent<PlayerAI>();
|
||||
enemyScript.OnSpawn(0,0, 1,GameLocal.Ins.playerAiEndPos[0].gameObject);
|
||||
PlayerAiList.Add(0, enemyScript);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建Boss
|
||||
/// </summary>
|
||||
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);
|
||||
// curRoundEnemyCount++;
|
||||
}
|
||||
|
||||
public void CreateExplosion(Transform pos)
|
||||
{
|
||||
if(!isServer)
|
||||
return;
|
||||
var ex= Instantiate(explosionPre, pos.position, Quaternion.identity);
|
||||
NetworkServer.Spawn(ex);
|
||||
ex.GetComponent<Explosion>().Init(0);
|
||||
}
|
||||
|
||||
[SyncVar]
|
||||
public int gunProp1;
|
||||
[SyncVar]
|
||||
public int gunProp2;
|
||||
|
||||
[Server]
|
||||
public void CreateGunProp()
|
||||
{
|
||||
if(!isStart)
|
||||
return;
|
||||
List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 };
|
||||
gunProp1 = numbers[Random.Range(0, numbers.Count)];
|
||||
numbers.Remove(gunProp1);
|
||||
gunProp2 = numbers[Random.Range(0, numbers.Count)];
|
||||
|
||||
var gun1= Instantiate(gunPropPre, GameLocal.Ins.gunPropPos[0]);
|
||||
NetworkServer.Spawn(gun1);
|
||||
gun1.GetComponent<WeaponProp>().Init((GunType)gunProp1);
|
||||
curGunPropList.Add(gun1);
|
||||
|
||||
var gun2= Instantiate(gunPropPre, GameLocal.Ins.gunPropPos[1]);
|
||||
NetworkServer.Spawn(gun2);
|
||||
gun2.GetComponent<WeaponProp>().Init((GunType)gunProp2);
|
||||
curGunPropList.Add(gun2);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/// <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 <= 2)
|
||||
{
|
||||
var combatUnitInfo= RoundInfos[0];
|
||||
StartCoroutine(CreateEnemy(combatUnitInfo));
|
||||
}
|
||||
else
|
||||
{
|
||||
int curRoundIndex=Random.Range(1,RoundInfos.Count);
|
||||
var roundInfo= RoundInfos[curRoundIndex];
|
||||
StartCoroutine(CreateEnemy(roundInfo));
|
||||
}
|
||||
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(4, 8); // 4-7
|
||||
|
||||
// 随机添加怪物直到接近目标
|
||||
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];
|
||||
}
|
||||
|
||||
Debug.LogError("生成的敌人数量:"+targetCount);
|
||||
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;
|
||||
int hpItemPropIndex = 15;
|
||||
int randomItemPropIndex = Random.Range(1, 101);
|
||||
|
||||
if(randomItemPropIndex<hpItemPropIndex)
|
||||
CreateItemProp(enemy.transform);
|
||||
|
||||
EnemyList.Remove(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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// 获取最近的玩家
|
||||
/// </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.Values)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取最近敌人
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public GameObject GetEnemy(Transform playerAi)
|
||||
{
|
||||
if ( curEnemyList.Count == 0)
|
||||
return null;
|
||||
|
||||
GameObject nearestPlayer = null;
|
||||
float minDis = 999;
|
||||
foreach (var enemy in curEnemyList)
|
||||
{
|
||||
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);
|
||||
ChangePlayerAiCountdownTime();
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
public bool IsHaveEnemy()
|
||||
{
|
||||
return curEnemyList.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);
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/_DefendNJ/Scripts/Manager/GameManager.cs.meta
Normal file
11
Assets/_DefendNJ/Scripts/Manager/GameManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9deac3e9432775f428406d0fd530d351
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
253
Assets/_DefendNJ/Scripts/Manager/TrueGearEffectManager.cs
Normal file
253
Assets/_DefendNJ/Scripts/Manager/TrueGearEffectManager.cs
Normal file
@@ -0,0 +1,253 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
using TruegearSdk;
|
||||
using UnityEngine;
|
||||
|
||||
public class TrueGearEffectManager : MonoBehaviour
|
||||
{
|
||||
|
||||
public static TrueGearEffectManager Ins;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Ins = this;
|
||||
|
||||
isAvailableIndex = 20;
|
||||
GetConnectIndex = 20;
|
||||
AddHitPart();
|
||||
#if !UNITY_EDITOR
|
||||
StartRequestTrueGear();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
private void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void StartRequestTrueGear()
|
||||
{
|
||||
TruegearAndroidConnector androidConnector = new TruegearAndroidConnector();
|
||||
androidConnector.InitShellJavaObject();
|
||||
androidConnector.RequestPermission();
|
||||
Debug.Log("开始连接");
|
||||
StartCoroutine(TrueGearAndroidConnector());
|
||||
}
|
||||
|
||||
public bool isGetConnect;
|
||||
|
||||
private int isAvailableIndex = 0;
|
||||
private int GetConnectIndex;
|
||||
IEnumerator TrueGearAndroidConnector()
|
||||
{
|
||||
TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance;
|
||||
bool res = androidConnector.IsAvailable();
|
||||
Debug.Log("蓝牙是否授权成功:"+res);
|
||||
while (!res&& isAvailableIndex>0)
|
||||
{
|
||||
yield return new WaitForSeconds(1f);
|
||||
Debug.Log("蓝牙尝试连接中....");
|
||||
androidConnector.InitShellJavaObject();
|
||||
androidConnector.RequestPermission();
|
||||
res = androidConnector.IsAvailable();
|
||||
isAvailableIndex--;
|
||||
}
|
||||
|
||||
if (isAvailableIndex <= 0)
|
||||
{
|
||||
Debug.Log("蓝牙授权失败");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("蓝牙授权成功");
|
||||
StartScanTrueGear();
|
||||
while (!isGetConnect&& GetConnectIndex>0)
|
||||
{
|
||||
GetScanedDevices();
|
||||
StartConnect();
|
||||
yield return new WaitForSeconds(1);
|
||||
Debug.Log("正在重新连接...");
|
||||
GetConnectIndex--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//搜索设备
|
||||
public void StartScanTrueGear()
|
||||
{
|
||||
TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance;
|
||||
bool res = androidConnector.IsAvailable();
|
||||
if (res)
|
||||
androidConnector.StartScan();
|
||||
Debug.Log("OnStartScanClick" + res);
|
||||
}
|
||||
|
||||
//获取设备列表
|
||||
public void GetScanedDevices()
|
||||
{
|
||||
TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance;
|
||||
bool res = androidConnector.IsAvailable();
|
||||
Debug.Log("OnGetScanedDevicesClick" + res);
|
||||
if (!res)
|
||||
return;
|
||||
List<DeviceData> res1 = androidConnector.GetScanedDevices();
|
||||
string str = "";
|
||||
foreach (var item in res1)
|
||||
{
|
||||
str += (string.Format("{0}, {1} ", item.name, item.address));
|
||||
}
|
||||
Debug.Log("OnGetScanedDevicesClick " + str);
|
||||
}
|
||||
|
||||
//开始连接设备
|
||||
public void StartConnect()
|
||||
{
|
||||
TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance;
|
||||
bool res = androidConnector.IsAvailable();
|
||||
Debug.Log("OnStartConnectClick" + res);
|
||||
if (!res)
|
||||
return;
|
||||
|
||||
List<DeviceData> res1 = androidConnector.GetScanedDevices();
|
||||
Debug.Log(res1.ToString());
|
||||
foreach (var item in res1)
|
||||
{
|
||||
{
|
||||
androidConnector.ConnectToDevice(item.address);
|
||||
Debug.Log(string.Format("Device Connect: {0}, {1}", item.name, item.address));
|
||||
isGetConnect = true;
|
||||
ChangeElectricalLevel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
Debug.Log("No device found");
|
||||
}
|
||||
|
||||
public void ChangeElectricalLevel()
|
||||
{
|
||||
TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance;
|
||||
bool isZD= androidConnector.ModifyElectricalPercent(80);
|
||||
Debug.LogError("是否震动:"+isZD);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断开连接
|
||||
/// </summary>
|
||||
public void CloseConnect()
|
||||
{
|
||||
TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance;
|
||||
androidConnector.DisconnectFromDevice();
|
||||
}
|
||||
|
||||
private void OnApplicationQuit()
|
||||
{
|
||||
//断开连接
|
||||
Debug.Log("断开连接");
|
||||
#if !UNITY_EDITOR
|
||||
CloseConnect();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 触发TrueGear震动
|
||||
/// </summary>
|
||||
/// <param name="effectName">效果名,可自定义</param>
|
||||
/// <param name="motorIndex">作用的电机ID列表</param>
|
||||
/// <param name="startTime">起始时间,单位ms</param>
|
||||
/// <param name="endTime">结束时间,单位ms</param>
|
||||
/// <param name="startIntensity">起始强度(0-100)</param>
|
||||
/// <param name="endIntensity">结束强度(0-100)</param>
|
||||
/// <param name="intensityMode">强度模式:Const/Fade/FadeInAndOut</param>
|
||||
/// <param name="actionType">震动位置</param>
|
||||
public void PlayVibrationEffect(
|
||||
string effectName,
|
||||
List<int> motorIndex,
|
||||
int startTime = 0,
|
||||
int endTime = 300,
|
||||
int startIntensity = 30,
|
||||
int endIntensity = 30,
|
||||
string intensityMode = "Const",
|
||||
string actionType="Shake"
|
||||
)
|
||||
{
|
||||
string indexStr = string.Join(",", motorIndex);
|
||||
Debug.Log(indexStr);
|
||||
string json = $@"
|
||||
{{
|
||||
""name"":""{effectName}"",
|
||||
""uuid"":""{effectName}"",
|
||||
""keep"":""False"",
|
||||
""priority"": 0,
|
||||
""tracks"":[
|
||||
{{
|
||||
""start_time"":{startTime},
|
||||
""end_time"":{endTime},
|
||||
""stop_name"":"""",
|
||||
""start_intensity"":{startIntensity},
|
||||
""end_intensity"":{endIntensity},
|
||||
""intensity_mode"":""{intensityMode}"",
|
||||
""action_type"":""{actionType}"",
|
||||
""once"":""True"",
|
||||
""interval"":1,
|
||||
""index"":[{indexStr}]
|
||||
}}
|
||||
]
|
||||
}}";
|
||||
|
||||
SendPlayEffectByContent(json);
|
||||
}
|
||||
|
||||
public void SendPlayEffectByContent(string jsonStr)
|
||||
{
|
||||
TruegearAndroidConnector androidConnector = TruegearAndroidConnector.Instance;
|
||||
bool res = androidConnector.IsAvailable();
|
||||
Debug.Log("OnTestClick" + res);
|
||||
if (!res)
|
||||
return;
|
||||
androidConnector.SendPlayEffectByContent(jsonStr);
|
||||
}
|
||||
public List<string> hitParts=new List<string>();
|
||||
|
||||
public void AddHitPart()
|
||||
{
|
||||
hitParts.Add("leftUp");
|
||||
hitParts.Add("leftDown");
|
||||
hitParts.Add("rightUp");
|
||||
hitParts.Add("rightDown");
|
||||
hitParts.Add("rightAim");
|
||||
}
|
||||
public void OnHit(bool isUp, int index,bool isArm)
|
||||
{
|
||||
//ChangeElectricalLevel();
|
||||
List<int> motorIDs = new List<int>();
|
||||
string hitPart= hitParts[index];
|
||||
switch (hitPart)
|
||||
{
|
||||
case "leftUp":
|
||||
motorIDs.AddRange( isUp?new int[] { 0, 1, 4,5 }: new int[] { 100, 101, 104,105 }); break;
|
||||
case "leftDown":
|
||||
motorIDs.AddRange(isUp?new int[] { 8, 9, 12,13 }: new int[] { 108, 109, 112,113 }); break;
|
||||
case "rightUp":
|
||||
motorIDs.AddRange(isUp?new int[] { 2,3,6,7}: new int[] { 102, 103, 106,107 }); break;
|
||||
case "rightDown":
|
||||
motorIDs.AddRange(isUp?new int[] { 10,11,14,15}: new int[] { 114, 115, 118,119 }); break;
|
||||
case "rightAim":
|
||||
Debug.Log("xxzz");
|
||||
motorIDs.AddRange(new int[] { 0,100}); break;
|
||||
default:
|
||||
motorIDs.Add(0); break;
|
||||
}
|
||||
PlayVibrationEffect(
|
||||
effectName: $"Hit_{hitPart}",
|
||||
motorIndex: motorIDs,
|
||||
startIntensity: isArm?20:50,
|
||||
endIntensity: isArm?20:50,
|
||||
endTime: 400,
|
||||
actionType: isArm? "Electrical" :"Shake"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7c907821bb6e484689d92d3dc05f5a0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user