NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Gameplay/PVP/PrepareTeamManager.cs

370 lines
11 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using Framework;
using Framework.Wrapper;
using Gameplay;
using Gameplay.Character;
using Gameplay.Level;
using Gameplay.Net;
using Gameplay.Unit;
using Gameplay.Utils;
using Gameplay.Vehicle.Impl;
using PhxhSDK;
using TGS;
using UnityEngine;
using Action = BehaviorDesigner.Runtime.Tasks.Action;
using Constants = PhxhSDK.Constants;
using Object = UnityEngine.Object;
/// <summary>
/// 用于布阵
/// </summary>
public class PrepareTeamManager : Singlenton<PrepareTeamManager>
{
private const string STAGE_ROOT_NAME = "StageRoot";
private Map _map;
private int _prepareRegionId;
private LevelData.CharacterToward _toward;
private TerrainGridSystem _tgs;
private Quaternion _rotation;
private bool _hasInit;
private Transform _stageRoot;
public const int MaxOnFightNum = 6;
private List<PVPUnitInfo> _pvpUnitInfos; //已上阵的阵容
public List<PVPUnitInfo> PvpUnitInfos => _pvpUnitInfos;
private int _onFightVehicleID;
private List<int> _onFightCharIDs = new();
//key:cellIndex
private Dictionary<int, GameObject> _onStageUnits = new();
//key:prefabPath
private Dictionary<string, List<GameObject>> _modelPool = new();
private Dictionary<GameObject, string> _gameObjectToPathDic = new();
#region API
public event Action<int, string> OnAddModel;
public event Action<int> OnRemoveModel;
public event Action<int, int> OnSwapModel;
//当前选择的预制体
public string CurrPrefabPath { get; set; }
//是否可以放置多个相同预制
public bool CanMultiple { get; set; }
public void Init(TerrainGridSystem tgs, MapData mapData, int prepareRegionID, LevelData.CharacterToward toward,
Camera camera,Dictionary<int,string> _initPrepareInfo = null)
{
if (_hasInit)
Dispose();
_tgs = tgs;
_map = MapUtils.LoadMap(tgs, mapData);
MapUtils.BindCameraController(camera, _map);
_tgs.showCells = true;
if (prepareRegionID < 0 || prepareRegionID >= mapData.regions.Count)
{
Debug.LogError($"找不到region!,regionID:{prepareRegionID}");
return;
}
_toward = toward;
_rotation = Quaternion.Euler(new Vector3(0, LevelUtils.SetCharaterToward(_toward), 0));
_hasInit = true;
_stageRoot = new GameObject(STAGE_ROOT_NAME).transform;
RevertPreparedModels(_initPrepareInfo);
InputManager.Instance.OnClick += OnClick;
}
public void Dispose()
{
_hasInit = false;
_map = null;
_tgs = null;
_onStageUnits.Clear();
_modelPool.Clear();
_gameObjectToPathDic.Clear();
Object.Destroy(_stageRoot.gameObject);
_stageRoot = null;
InputManager.Instance.OnClick -= OnClick;
OnAddModel = null;
OnRemoveModel = null;
OnSwapModel = null;
CurrPrefabPath = null;
CanMultiple = false;
_pvpUnitInfos.Clear();
_onFightCharIDs.Clear();
_onFightVehicleID = 0;
}
#region Model
//之前已经布置过的模型重新放置上来
public void RevertPreparedModels(Dictionary<int,string> preparedData)
{
if(preparedData == null)
return;
foreach (var kv in preparedData)
{
AddModel(kv.Value,kv.Key);
}
}
public void ShowPrepareRegion()
{
_tgs.showCells = true;
//todo 颜色从配置中获取
_map.SetRegionColor(_prepareRegionId, true, ColorEx.FromStr("#FF960072"));
}
public void HidePrepareRegion()
{
_tgs.showCells = false;
_map.SetRegionColor(_prepareRegionId, false, ColorEx.FromStr("#FF960072"));
}
#endregion
private void OnClick(Vector2 screenPos)
{
var cellIndex = GroundHitHelper.CalcHitCellIndex(screenPos, _tgs);
//点击非出战区
if (!_map.MapData.IsCellInsideRegion(cellIndex, _prepareRegionId))
{
CurrPrefabPath = null;
EventManager.Instance.Send(EventManager.EventName.OnUnSelectPvPUnit);
return;
}
//未选中时点击格子
if (string.IsNullOrEmpty(CurrPrefabPath) && _onStageUnits.ContainsKey(cellIndex))
{
var unitInfo = _pvpUnitInfos.Find(unit => unit.cellIndex == cellIndex);
if (unitInfo != null)
{
EventManager.Instance.Send(EventManager.EventName.OnSelectPvPUnit, unitInfo.unitID);
}
return;
}
if (cellIndex >= 0 && _map.MapData.IsCellInsideRegion(cellIndex, _prepareRegionId) &&
!string.IsNullOrEmpty(CurrPrefabPath))
{
//获得当前选择模型在台上的index
var currPrefabOnStageIndex = GetCellIndexOnStage(CurrPrefabPath);
if (_onStageUnits.TryGetValue(cellIndex, out var go))
{
//如果点击的位置已经有模型了
var pathOnStage = GameObjectToPath(go);
if (pathOnStage == CurrPrefabPath)
{
//台上的模型路径和当前选择的路径相同 下阵
RemoveModel(cellIndex);
var unit = _pvpUnitInfos.Find(unit => unit.cellIndex == cellIndex);
EventManager.Instance.Send(EventManager.EventName.OnPVPUnitRemove, unit);
return;
}
}
if (currPrefabOnStageIndex >= 0 && !CanMultiple)
{
//如果台上已经有当前选择模型,则和点击位置的模型(可能是空)互换位置
SwapModel(currPrefabOnStageIndex, cellIndex);
EventManager.Instance.Send(EventManager.EventName.OnUnSelectPvPUnit);
}
else
{
//如果台上没有当前选择的模型,则替换掉当前点击位置的模型
AddModel(CurrPrefabPath, cellIndex);
EventManager.Instance.Send(EventManager.EventName.OnUnSelectPvPUnit);
}
}
}
private string GameObjectToPath(GameObject go)
{
return _gameObjectToPathDic.GetValueOrDefault(go);
}
private int GetCellIndexOnStage(string prefabPath)
{
foreach (var kv in _onStageUnits)
{
var cellIndex = kv.Key;
var go = kv.Value;
if (_gameObjectToPathDic[go] == prefabPath)
{
return cellIndex;
}
}
return -1;
}
private async UniTask<GameObject> GetAModel(string prefabPath)
{
GameObject model = null;
if (_modelPool.TryGetValue(prefabPath, out var modelList))
{
if (modelList.Count > 0)
{
model = modelList[^1];
modelList.RemoveAt(modelList.Count - 1);
}
}
if (model == null)
{
var go = await AssetManager.Instance.LoadAssetAsync<GameObject>(prefabPath);
model = Object.Instantiate(go, _stageRoot);
_gameObjectToPathDic.Add(model, prefabPath);
}
return model;
}
private void ReturnModelToPool(GameObject model)
{
var path = _gameObjectToPathDic[model];
if (!_modelPool.TryGetValue(path, out var modelList))
{
modelList = new();
_modelPool.Add(path, modelList);
}
modelList.Add(model);
}
private async void AddModel(string prefabPath, int cellIndex)
{
if (_onStageUnits.ContainsKey(cellIndex))
{
RemoveModel(cellIndex);
}
OnAddModel?.Invoke(cellIndex, prefabPath);
var model = await GetAModel(prefabPath);
model.SetActive(true);
model.SetLayerEx(LayerMask.NameToLayer("UIView"));
SetModelPosition(model, cellIndex);
_onStageUnits.Add(cellIndex, model);
}
private void RemoveModel(int cellIndex)
{
if (_onStageUnits.TryGetValue(cellIndex, out var model))
{
model.SetActive(false);
_onStageUnits.Remove(cellIndex);
ReturnModelToPool(model);
OnRemoveModel?.Invoke(cellIndex);
}
}
private void SwapModel(int cellIndexLeft, int cellIndexRight)
{
if (cellIndexLeft == cellIndexRight ||
!_map.MapData.IsCellInsideRegion(cellIndexLeft, _prepareRegionId) ||
!_map.MapData.IsCellInsideRegion(cellIndexRight, _prepareRegionId))
return;
var leftModel = _onStageUnits.GetValueOrDefault(cellIndexLeft);
var rightModel = _onStageUnits.GetValueOrDefault(cellIndexRight);
_onStageUnits.Remove(cellIndexLeft);
_onStageUnits.Remove(cellIndexRight);
if (leftModel != null)
{
_onStageUnits.Add(cellIndexRight, leftModel);
SetModelPosition(leftModel, cellIndexRight);
}
if (rightModel != null)
{
_onStageUnits.Add(cellIndexLeft, rightModel);
SetModelPosition(rightModel, cellIndexLeft);
}
OnSwapModel?.Invoke(cellIndexLeft, cellIndexRight);
}
private void SetModelPosition(GameObject model, int cellIndex)
{
var positionWS = _map.TGSCellIndex2WorldPosition(cellIndex);
model.transform.SetPositionAndRotation(positionWS, _rotation);
}
#endregion
#region Data
private void _AddUnit(PVPUnitInfo unit)
{
_pvpUnitInfos?.Add(unit);
}
private void _RemoveUnit(PVPUnitInfo unit)
{
_pvpUnitInfos?.Remove(unit);
}
private void _InitUnitInfos()
{
var savedPrepareData = Actor.Instance.Pvp.TeamData;
_pvpUnitInfos = PVPUnitInfo.DeSerialize(savedPrepareData);
}
private PVPUnitInfo _CreatePVPUnitInfo(int cellIndex, uint id)
{
PVPUnitInfo unitInfo = new PVPUnitInfo();
var allCharacterInfosDic = CharacterDataInfoManager.Instance.DataDic;
unitInfo.unitID = id;
unitInfo.type = allCharacterInfosDic.ContainsKey(id)? Unit.UnitType.Charactor : Unit.UnitType.Vehicle;
unitInfo.cellIndex = cellIndex;
return unitInfo;
}
#endregion
#region API
public PVPUnitInfo CreateUnitInfo(int cellIndex, uint id)
{
return _CreatePVPUnitInfo(cellIndex, id);
}
public void AddUnit(PVPUnitInfo unit)
{
_AddUnit(unit);
}
public void RemoveUnit(PVPUnitInfo unit)
{
_RemoveUnit(unit);
}
public void InitUnitInfos()
{
_InitUnitInfos();
}
public void OnSelectUnit(uint uid)
{
EventManager.Instance.Send(EventManager.EventName.OnSelectPvPUnit, uid);
}
public void OnCancelSelectUnit()
{
EventManager.Instance.Send(EventManager.EventName.OnUnSelectPvPUnit);
}
#endregion
}