370 lines
11 KiB
C#
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
|
|
} |