269 lines
7.9 KiB
C#
269 lines
7.9 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Cysharp.Threading.Tasks;
|
|
using Framework;
|
|
using Gameplay;
|
|
using Gameplay.Character;
|
|
using Gameplay.Level;
|
|
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;
|
|
|
|
//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;
|
|
}
|
|
|
|
//之前已经布置过的模型重新放置上来
|
|
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 (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);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (currPrefabOnStageIndex >= 0 && !CanMultiple)
|
|
{
|
|
//如果台上已经有当前选择模型,则和点击位置的模型(可能是空)互换位置
|
|
SwapModel(currPrefabOnStageIndex, cellIndex);
|
|
}
|
|
else
|
|
{
|
|
//如果台上没有当前选择的模型,则替换掉当前点击位置的模型
|
|
AddModel(CurrPrefabPath, cellIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
var model = await GetAModel(prefabPath);
|
|
model.SetActive(true);
|
|
model.SetLayerEx(LayerMask.NameToLayer("UIView"));
|
|
SetModelPosition(model, cellIndex);
|
|
_onStageUnits.Add(cellIndex, model);
|
|
OnAddModel?.Invoke(cellIndex, prefabPath);
|
|
}
|
|
|
|
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);
|
|
}
|
|
} |