466 lines
16 KiB
C#
466 lines
16 KiB
C#
#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
|
||
}
|
||
}
|