#if UNITY_EDITOR using System; using System.Collections.Generic; using System.IO; using System.Linq; using cfg; using Newtonsoft.Json; using SimpleJSON; using UnityEditor; #endif using UnityEngine; using Random = System.Random; namespace Script.EditorScript { [ExecuteInEditMode] public class RandomPropsTemp : MonoBehaviour { #if UNITY_EDITOR [Tooltip("棋子容器")] public GameObject CubeContainer; [Tooltip("最终导出的模板数量")] public int TempCount = 20; [Tooltip("模板生成上线")] public int TempMaxCount = 10000; public InspectorEntry[] RandomPropsList; [NonSerialized] public List> ResultTemps = new List>(); /// /// 索引 为key,用来支持 随机道具 配置都是一样的道具 /// private Dictionary> _allPropCanPutDic = new Dictionary>(); private CubeScript[] _allCube; private Tables _tables; private Tables GetTable() { if (_tables == null) { _tables = new Tables((string fileName) => { return JSON.Parse( File.ReadAllText(Application.dataPath + "/ABPackage/pkgFirstPackage/Data/" + fileName + ".json")); }); } return _tables; } public void ApplyId() { for (int i = 0; i < RandomPropsList.Length; i++) { if (RandomPropsList[i].PropId <= 0) { Debug.LogError("随机道具id==0,请检查配置!!"); continue; } if (!GetTable().TbDiggingItemList.DataMap.TryGetValue(RandomPropsList[i].PropId, out DiggingItemList info)) { Debug.LogError("随机模板 道具id配置错误 请检查!!! 错误id:" + RandomPropsList[i].PropId); continue; } string templateName = GetTable().TbDiggingItemList.Get(RandomPropsList[i].PropId).GridTemplate; string templateUrl = $"Assets/AssetsPackage/art/DgSand/Scriptable/CubeConfig/{templateName}.asset"; CubeConfigData asset = AssetDatabase.LoadAssetAtPath(templateUrl); if (asset == null) { Debug.LogError("资源id 的模板 没找到,请检查配置!!" + RandomPropsList[i].PropId); return; } RandomPropsList[i].resource = asset; } Debug.LogError("随机道具id 已经启用"); } public void GenerateTempData() { ResultTemps.Clear(); _allPropCanPutDic.Clear(); _allCube = CubeContainer.GetComponentsInChildren(); List allValidCubes = FindAllValidCubes(); Debug.LogWarning("空格子数量:" + allValidCubes.Count); //分别存储每种道具 所有的摆放位置 CountPlacements(allValidCubes, RandomPropsList, 0); //计算出所有道具同时可以存在的组合 List> allValidCombination = CalculateAllPlacements(); Debug.LogWarning("有效组合的总个数:" + allValidCombination.Count); if (allValidCombination.Count == 0) { EditorUtility.DisplayDialog("有效组合的总个数为 0", "请扩大Temp最大数量,重新执行", "确定"); } foreach (var validCombination in allValidCombination) { Debug.LogWarning("Valid Combination:"); foreach (var propTemp in validCombination) { Debug.LogWarning($"PropId: {propTemp.PropId}, angle: {propTemp.ConfigData.PropDirection},Position: ({propTemp.x}, {propTemp.y})"); } } // 最终随机出 最多TempCount 个模板进行存储 if (allValidCombination.Count < TempCount) { ResultTemps = allValidCombination; } else { ResultTemps = GetRandomSelection(allValidCombination, TempCount); } } private List GetRandomSelection(List list, int count) { Random random = new Random(); return list.OrderBy(x => random.Next()).Take(count).ToList(); } /// /// 计算每种道具 所有能摆放的位置 /// /// /// /// private void CountPlacements(List validCubes, InspectorEntry[] props, int propIndex) { if (propIndex >= props.Length) { Debug.LogWarning("所有道具位置处理完毕"); return; } List tempFlagList = new List(); InspectorEntry prop = props[propIndex]; foreach (var rotatedProp in GetRotations(prop.resource)) { for (int i = 0; i < validCubes.Count; i++) { List useCube = CheckPropNeedGridData(rotatedProp, validCubes[i].gameObject); if (useCube == null) { continue; } bool canPut = GetPropIfCanPut(validCubes, useCube); if (canPut) { PropTemp temp = new PropTemp(); temp.x = (int)validCubes[i].gameObject.transform.localPosition.x; temp.y = (int)validCubes[i].gameObject.transform.localPosition.y; temp.PropId = prop.PropId; temp.ConfigData = rotatedProp.Copy(); temp.SetEmployCube(useCube); tempFlagList.Add(temp); Debug.Log("!!!!!!!!!!!!propId::" + prop.PropId + " angle::" + temp.ConfigData.PropDirection + " x::" + temp.x + " y::" + temp.y); } } } _allPropCanPutDic[propIndex] = tempFlagList; Debug.LogWarning("所有数据:propId:" + prop.PropId + " 模板数量::" + _allPropCanPutDic[propIndex].Count); CountPlacements(validCubes, props, ++propIndex); } #region 计算所有道具 位置的组合 private List> CalculateAllPlacements() { List> allCombinations = new List>(); GenerateCombinations(_allPropCanPutDic, new List(), allCombinations, 0); List> validCombinations = new List>(); foreach (var combination in allCombinations) { if (IsValidCombination(combination)) { validCombinations.Add(combination); } } return validCombinations; } private void GenerateCombinations(Dictionary> allPropCanPutDic, List currentCombination, List> allCombinations, int currentIndex) { if (allCombinations.Count >= TempMaxCount) { Debug.LogError("到达模板数量上线,开始检查模板合法性"); return; } if (currentIndex >= allPropCanPutDic.Count) { allCombinations.Add(new List(currentCombination)); return; } //int propId = allPropCanPutDic.Keys.ElementAt(currentIndex); foreach (var propTemp in allPropCanPutDic[currentIndex]) { if (allCombinations.Count >= TempMaxCount) { Debug.Log($"到达模板数量上线 {allCombinations.Count},开始检查模板合法性"); return; } currentCombination.Add(propTemp); GenerateCombinations(allPropCanPutDic, currentCombination, allCombinations, currentIndex + 1); currentCombination.RemoveAt(currentCombination.Count - 1); } } /// /// 是否是 有效的组合 /// /// /// private bool IsValidCombination(List currentCombination) { Dictionary dic = new Dictionary(); for (int i = 0; i < currentCombination.Count; i++) { List cubes = currentCombination[i].GetEmployCubes(); foreach (var cube in cubes) { if (dic.TryGetValue(cube.GetInstanceID(), out bool value)) { return false; } else { dic.Add(cube.GetInstanceID(), true); } } } return true; } #endregion #region 辅助方法 private IEnumerable GetRotations(CubeConfigData prop) { yield return GetDataByRotate(prop, 0); yield return GetDataByRotate(prop, 90); yield return GetDataByRotate(prop, 180); yield return GetDataByRotate(prop, 270); } private CubeConfigData GetDataByRotate(CubeConfigData prop, int angle) { prop.PropDirection = angle; return prop; } /// /// 检查是否能放下道具 /// /// /// /// private bool GetPropIfCanPut(List validCubes, List useCube) { for (int i = 0; i < useCube.Count; i++) { bool isOk = false; for (int j = 0; j < validCubes.Count; j++) { if (validCubes[j] == useCube[i]) { isOk = true; break; } } if (!isOk) { return false; } } return true; } /// /// 找到所有没有被道具占据的空Cube /// /// public List FindAllValidCubes() { List allInvalidCube = new List(); for (int i = 0; i < _allCube.Length; i++) { if (!_allCube[i].IsBorder && _allCube[i].ConfigData != null && _allCube[i].PropId > 0) { CubeConfigData gridData = _allCube[i].ConfigData; //格子下道具绑定格子 List cubes = CheckPropNeedGridData(gridData, _allCube[i].gameObject); if (cubes != null) { allInvalidCube = allInvalidCube.Concat(cubes).ToList(); } else { Debug.LogWarning("找到配置的道具 放在空格子上,检查配置"); } } } //找到所有没有被道具占据的空Cube List allvalidCube = new List(); bool finded = false; for (int i = 0; i < _allCube.Length; i++) { CubeScript cur = _allCube[i]; finded = false; if (!_allCube[i].IsBorder) { for (int j = 0; j < allInvalidCube.Count; j++) { if (cur == allInvalidCube[j]) { finded = true; } } if (!finded) { allvalidCube.Add(cur); } } } return allvalidCube; } /// /// 格子下道具绑定格子 /// public List CheckPropNeedGridData(CubeConfigData data, GameObject startObj) { int rows = data.GetArray().GetLength(0); int cols = data.GetArray().GetLength(1); List cubes = new List(); // 起始 Vector3 startPoint = startObj.transform.localPosition; int allCount = 0; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { int value = data.GetArray()[i, j]; if (value > 0) { allCount++; // 初始位置 Vector3 positionB = new Vector3(j, i, 0); //空间转换 Vector3 endPosition = startPoint + GetRotatePoint(data.PropDirection, Vector3.zero, positionB); // Debug.LogWarning($"获取Grid::{endPosition.x}" + " col::" + endPosition.y); CubeScript grid = GetGridItemByRowAndCol((int)Mathf.Round(endPosition.x), (int)Mathf.Round(endPosition.y)); if (grid != null) { cubes.Add(grid); } } } } if (cubes.Count == allCount) { return cubes; } else { return null; } } public CubeScript GetGridItemByRowAndCol(int row, int col) { for (int i = 0; i < _allCube.Length; i++) { if (_allCube[i].transform.localPosition.x == row && _allCube[i].transform.localPosition.y == col) { return _allCube[i]; } } return null; } /// /// 获取旋转后道具的位置 /// /// /// /// /// private Vector3 GetRotatePoint(int angles, Vector3 positionA, Vector3 positionB) { return RotatePointAroundPivot(positionB, positionA, new Vector3(0, 0, -angles)); } private Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 angles) { Vector3 dir = point - pivot; // 获取点到枢轴的向量 dir = Quaternion.Euler(angles) * dir; // 旋转向量 point = dir + pivot; // 将点移动回枢轴 return point; } #endregion #endif } public class PropTemp { #if UNITY_EDITOR public int x; public int y; public int PropId; public CubeConfigData ConfigData; //使用的格子 private List _EmployCubes = new List(); public List GetEmployCubes() { return _EmployCubes; } public void AddEmployCube(CubeScript value) { _EmployCubes.Add(value); } public void SetEmployCube(List value) { _EmployCubes = value; } public string ToJson() { var settings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }; return JsonConvert.SerializeObject(new { x = x, y = y, PropId = PropId, ConfigData = ConfigData }, settings); } #endif } }