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; /// /// 用于布阵 /// public class PrepareTeamManager : Singlenton { 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 _onStageUnits = new(); //key:prefabPath private Dictionary> _modelPool = new(); private Dictionary _gameObjectToPathDic = new(); #region API public event Action OnAddModel; public event Action OnRemoveModel; public event Action 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 _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 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 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(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); } }