Files
back_cantanBuilding/Assets/Scripts/SandDigEditorScript/RandomPropsTemp.cs
2026-05-26 16:15:54 +08:00

466 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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<List<PropTemp>> ResultTemps = new List<List<PropTemp>>();
/// <summary>
/// 索引 为key,用来支持 随机道具 配置都是一样的道具
/// </summary>
private Dictionary<int, List<PropTemp>> _allPropCanPutDic = new Dictionary<int, List<PropTemp>>();
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<CubeConfigData>(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<CubeScript>();
List<CubeScript> allValidCubes = FindAllValidCubes();
Debug.LogWarning("空格子数量:" + allValidCubes.Count);
//分别存储每种道具 所有的摆放位置
CountPlacements(allValidCubes, RandomPropsList, 0);
//计算出所有道具同时可以存在的组合
List<List<PropTemp>> 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<T> GetRandomSelection<T>(List<T> list, int count)
{
Random random = new Random();
return list.OrderBy(x => random.Next()).Take(count).ToList();
}
/// <summary>
/// 计算每种道具 所有能摆放的位置
/// </summary>
/// <param name="validCubes"></param>
/// <param name="props"></param>
/// <param name="propIndex"></param>
private void CountPlacements(List<CubeScript> validCubes, InspectorEntry[] props, int propIndex)
{
if (propIndex >= props.Length)
{
Debug.LogWarning("所有道具位置处理完毕");
return;
}
List<PropTemp> tempFlagList = new List<PropTemp>();
InspectorEntry prop = props[propIndex];
foreach (var rotatedProp in GetRotations(prop.resource))
{
for (int i = 0; i < validCubes.Count; i++)
{
List<CubeScript> 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<List<PropTemp>> CalculateAllPlacements()
{
List<List<PropTemp>> allCombinations = new List<List<PropTemp>>();
GenerateCombinations(_allPropCanPutDic, new List<PropTemp>(), allCombinations, 0);
List<List<PropTemp>> validCombinations = new List<List<PropTemp>>();
foreach (var combination in allCombinations)
{
if (IsValidCombination(combination))
{
validCombinations.Add(combination);
}
}
return validCombinations;
}
private void GenerateCombinations(Dictionary<int, List<PropTemp>> allPropCanPutDic, List<PropTemp> currentCombination, List<List<PropTemp>> allCombinations, int currentIndex)
{
if (allCombinations.Count >= TempMaxCount)
{
Debug.LogError("到达模板数量上线,开始检查模板合法性");
return;
}
if (currentIndex >= allPropCanPutDic.Count)
{
allCombinations.Add(new List<PropTemp>(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);
}
}
/// <summary>
/// 是否是 有效的组合
/// </summary>
/// <param name="currentCombination"></param>
/// <returns></returns>
private bool IsValidCombination(List<PropTemp> currentCombination)
{
Dictionary<int, bool> dic = new Dictionary<int, bool>();
for (int i = 0; i < currentCombination.Count; i++)
{
List<CubeScript> 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<CubeConfigData> 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;
}
/// <summary>
/// 检查是否能放下道具
/// </summary>
/// <param name="validCubes"></param>
/// <param name="useCube"></param>
/// <returns></returns>
private bool GetPropIfCanPut(List<CubeScript> validCubes, List<CubeScript> 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;
}
/// <summary>
/// 找到所有没有被道具占据的空Cube
/// </summary>
/// <returns></returns>
public List<CubeScript> FindAllValidCubes()
{
List<CubeScript> allInvalidCube = new List<CubeScript>();
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<CubeScript> cubes = CheckPropNeedGridData(gridData, _allCube[i].gameObject);
if (cubes != null)
{
allInvalidCube = allInvalidCube.Concat(cubes).ToList();
}
else
{
Debug.LogWarning("找到配置的道具 放在空格子上,检查配置");
}
}
}
//找到所有没有被道具占据的空Cube
List<CubeScript> allvalidCube = new List<CubeScript>();
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;
}
/// <summary>
/// 格子下道具绑定格子
/// </summary>
public List<CubeScript> CheckPropNeedGridData(CubeConfigData data, GameObject startObj)
{
int rows = data.GetArray().GetLength(0);
int cols = data.GetArray().GetLength(1);
List<CubeScript> cubes = new List<CubeScript>();
// 起始
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;
}
/// <summary>
/// 获取旋转后道具的位置
/// </summary>
/// <param name="angles"></param>
/// <param name="positionA"></param>
/// <param name="positionB"></param>
/// <returns></returns>
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<CubeScript> _EmployCubes = new List<CubeScript>();
public List<CubeScript> GetEmployCubes()
{
return _EmployCubes;
}
public void AddEmployCube(CubeScript value)
{
_EmployCubes.Add(value);
}
public void SetEmployCube(List<CubeScript> 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
}
}