#if UNITY_EDITOR using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using cfg; using Newtonsoft.Json; using SimpleJSON; using Unity.Collections; 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; [NonSerialized] public List> ResultTemps = new List>(); /// /// 索引 为key,用来支持 随机道具 配置都是一样的道具 /// private Dictionary> _allPropCanPutDic = new Dictionary>(); private CubeScript[] _allCube; private Tables _tables; private Tables GetTable() { if (_tables == null) { var cwd = Directory.GetParent(Directory.GetCurrentDirectory()); var dir = Path.Combine(cwd.FullName, "cfgData"); _tables = new Tables((string fileName) => { return JSON.Parse( File.ReadAllText(Path.Combine(dir, $"{fileName}.json"))); }); } return _tables; } public void GenerateTempData() { ResultTemps.Clear(); _allPropCanPutDic.Clear(); _allCube = CubeContainer.GetComponentsInChildren(); List RandomPropsList = _allCube.Where(entry => entry.PropId > 0 && entry.IsFrist).ToList(); 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, List props, int propIndex) { if (propIndex >= props.Count) { Debug.LogWarning("所有道具位置处理完毕"); return; } List tempFlagList = new List(); CubeScript prop = props[propIndex]; foreach (var rotatedProp in GetRotations(prop.ConfigData)) { 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)Math.Round(validCubes[i].gameObject.transform.localPosition.x); temp.y = (int)Math.Round(validCubes[i].gameObject.transform.localPosition.y); temp.PropId = prop.PropId; temp.ConfigData = rotatedProp.Copy(); temp.SetEmployCube(useCube); //tempFlagList.Add(temp); tempFlagList.Insert(UnityEngine.Random.Range(0, tempFlagList.Count), 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>(); List dic = new List(); GenerateCombinations(_allPropCanPutDic, new List(), allCombinations, 0, dic); 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, List dic) { 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; } dic = new List(dic); var newList = new List(); List cubes = propTemp.GetEmployCubes(); bool isTO = true; foreach (var cube in cubes) { if (dic.Contains(cube.GetInstanceID())) { isTO = false; break; } else { newList.Add(cube.GetInstanceID()); } } if (isTO) { dic.AddRange(newList); currentCombination.Add(propTemp); GenerateCombinations(allPropCanPutDic, currentCombination, allCombinations, currentIndex + 1, dic); dic.RemoveRange(dic.Count - newList.Count, newList.Count); 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 propP) { var prop = propP.Copy(); 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].IsFrist && _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)Math.Round(endPosition.x, MidpointRounding.AwayFromZero), (int)Math.Round(endPosition.y, MidpointRounding.AwayFromZero)); 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++) { Vector3 pos = _allCube[i].transform.localPosition; if ((int)Math.Round(pos.x, MidpointRounding.AwayFromZero) == row && (int)Math.Round(pos.y, MidpointRounding.AwayFromZero) == 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 }; var data = new { PropDirection = ConfigData.PropDirection, PropRows = ConfigData.PropRows, PropColumns = ConfigData.PropColumns, PropArr = ConfigData.PropArr }; return JsonConvert.SerializeObject(new { x = x, y = y, PropId = PropId, ConfigData = data }, settings); } #endif } }