355 lines
12 KiB
C#
355 lines
12 KiB
C#
|
using Thousandto.Core.Asset;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.IO;
|
|||
|
using System.Text;
|
|||
|
using UnityEditor;
|
|||
|
using UnityEditor.SceneManagement;
|
|||
|
using UnityEngine;
|
|||
|
using UnityEngine.SceneManagement;
|
|||
|
|
|||
|
namespace Thousandto.Editor.Test
|
|||
|
{
|
|||
|
public enum CollectTypeDefine
|
|||
|
{
|
|||
|
SkyBox, //天空盒子
|
|||
|
Grass, //草
|
|||
|
Effect, //场景特效
|
|||
|
Mass, //其他杂七杂八的物件
|
|||
|
}
|
|||
|
|
|||
|
public struct Thing
|
|||
|
{
|
|||
|
public string Name { get; set; }
|
|||
|
public CollectTypeDefine CType { get; set; }
|
|||
|
public GameObject Go { get; set; }
|
|||
|
//当前物件的边界信息
|
|||
|
public Bounds Bounds { get; set; }
|
|||
|
//网格中的索引
|
|||
|
public int Index { get; set; }
|
|||
|
};
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 收集场景中的物件,以分块区域来划分,生成新的prefab
|
|||
|
/// </summary>
|
|||
|
public class CollectThings
|
|||
|
{
|
|||
|
List<MyTerrainData> _allTerrainDatas = new List<MyTerrainData>();
|
|||
|
|
|||
|
List<Thing> _grassThings = new List<Thing>();
|
|||
|
List<Thing> _skyBoxThings = new List<Thing>();
|
|||
|
List<Thing> _effectThings = new List<Thing>();
|
|||
|
//跨mesh的普通物件
|
|||
|
List<Thing> _otherThings = new List<Thing>();
|
|||
|
|
|||
|
//一些没有跨mesh存在的物件,则集中存放到一起,保存成一个新的prefab
|
|||
|
Dictionary<MyTerrainData, List<Thing>> _thingInOneTerrainDict = new Dictionary<MyTerrainData, List<Thing>>();
|
|||
|
|
|||
|
private string _curMapName = "";
|
|||
|
|
|||
|
//记录各个分块
|
|||
|
Dictionary<int, Rect> _resolutionDict = new Dictionary<int, Rect>();
|
|||
|
//<index, <thingType, thingList>>
|
|||
|
Dictionary<int, Dictionary<int, List<Thing>>> _collectThingDict = new Dictionary<int, Dictionary<int, List<Thing>>>();
|
|||
|
|
|||
|
private int _mapSize = 0;
|
|||
|
private int _blockSize = 0;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 设置分辨率
|
|||
|
/// </summary>
|
|||
|
/// <param name="mapSize">地图大小</param>
|
|||
|
/// <param name="blockSize">分块大小</param>
|
|||
|
public void SetResolution(int mapSize, int blockSize)
|
|||
|
{
|
|||
|
_mapSize = mapSize;
|
|||
|
_blockSize = blockSize;
|
|||
|
|
|||
|
float countf = mapSize / (float)blockSize;
|
|||
|
int count = mapSize / blockSize;
|
|||
|
|
|||
|
if (countf - count > 0.1f)
|
|||
|
count++;
|
|||
|
|
|||
|
_resolutionDict.Clear();
|
|||
|
|
|||
|
for (int i = 0; i < count; ++i)
|
|||
|
{
|
|||
|
for(int j = 0; j < count; ++j)
|
|||
|
{
|
|||
|
Rect rect = new Rect(i * blockSize, j * blockSize, blockSize, blockSize);
|
|||
|
int key = TerrainConfigLoader.CalcIndex(i, j);
|
|||
|
_resolutionDict.Add(key, rect);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void Collect(string mapName = "")
|
|||
|
{
|
|||
|
if(string.IsNullOrEmpty(mapName))
|
|||
|
{
|
|||
|
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
|
|||
|
if (File.Exists(path))
|
|||
|
{
|
|||
|
EditorSceneManager.OpenScene(path);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if(mapName != EditorSceneManager.GetActiveScene().name)
|
|||
|
{
|
|||
|
var path = ConfigDefine.GetSceneFile(mapName);
|
|||
|
if (File.Exists(path))
|
|||
|
EditorSceneManager.OpenScene(path);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//删除旧的thing prefab
|
|||
|
DeleteOldThingPrefabs();
|
|||
|
|
|||
|
var scene = EditorSceneManager.GetActiveScene();
|
|||
|
var name = scene.name;
|
|||
|
_curMapName = name;
|
|||
|
_allTerrainDatas = LoadAllSplitedTerrain(name);
|
|||
|
if (!CollectThingsInRoot())
|
|||
|
return;
|
|||
|
AssetDatabase.StartAssetEditing();
|
|||
|
var configList = SaveThings(_collectThingDict);
|
|||
|
AssetDatabase.StopAssetEditing();
|
|||
|
|
|||
|
if(configList.Count > 0)
|
|||
|
{
|
|||
|
var savePath = ConfigDefine.GetConfigPath(TerrainConfigDefine.THING_CONFIG_FILENAME);
|
|||
|
File.WriteAllLines(savePath, configList.ToArray());
|
|||
|
}
|
|||
|
|
|||
|
AssetDatabase.SaveAssets();
|
|||
|
AssetDatabase.Refresh();
|
|||
|
}
|
|||
|
|
|||
|
public static List<MyTerrainData> LoadAllSplitedTerrain(string mapName)
|
|||
|
{
|
|||
|
List<MyTerrainData> list = new List<MyTerrainData>();
|
|||
|
string storePath = ConfigDefine.GetSaveTerrainPath(mapName);
|
|||
|
if (!Directory.Exists(storePath))
|
|||
|
{
|
|||
|
Utils.ShowErrorMsgBox("加载小块地图网格", "找不到存储路径:" + storePath);
|
|||
|
return list;
|
|||
|
}
|
|||
|
|
|||
|
var fileList = Directory.GetFiles(storePath, "*.obj");
|
|||
|
for(int i = 0; i < fileList.Length; ++i)
|
|||
|
{
|
|||
|
list.Add(MyTerrainData.CreateTerrainDataFromFileName(fileList[i]));
|
|||
|
}
|
|||
|
|
|||
|
return list;
|
|||
|
}
|
|||
|
|
|||
|
public bool CollectThingsInRoot(string root = "SceneRoot")
|
|||
|
{
|
|||
|
var rootGo = GameObject.Find(root);
|
|||
|
if(rootGo == null)
|
|||
|
{
|
|||
|
Utils.ShowErrorMsgBox("获取场景中所有GameObject", "没有找到跟节点SceneRoot");
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
List<GameObject> gos = new List<GameObject>();
|
|||
|
FindGameObjects(rootGo, gos);
|
|||
|
for(int i = 0; i < gos.Count; ++i)
|
|||
|
{
|
|||
|
string fullName = Utils.GetGameObjectHierarchyPath(gos[i]);
|
|||
|
if (gos[i].transform.childCount > 0 && gos[i].transform.position == Vector3.zero && gos[i].transform.localScale == Vector3.one)
|
|||
|
continue;
|
|||
|
|
|||
|
Thing thing = new Thing();
|
|||
|
thing.CType = GetThingTypeFromName(fullName);
|
|||
|
thing.Go = gos[i];
|
|||
|
thing.Name = fullName;
|
|||
|
thing.Bounds = GetThingBounds(gos[i]);
|
|||
|
//thing.RelateToMeshs = CalcRelativeToTerrainMeshes(thing, _allTerrainDatas);
|
|||
|
if (thing.Bounds.size == Vector3.zero)
|
|||
|
thing.Index = Utils.CalcIndex(thing.Go.transform.position, _blockSize);
|
|||
|
else
|
|||
|
thing.Index = Utils.CalcIndex(Utils.GetGameObjectCenter(thing), _blockSize);
|
|||
|
|
|||
|
Dictionary<int, List<Thing>> typeToThing;
|
|||
|
if(!_collectThingDict.TryGetValue(thing.Index, out typeToThing))
|
|||
|
{
|
|||
|
typeToThing = new Dictionary<int, List<Thing>>();
|
|||
|
_collectThingDict.Add(thing.Index, typeToThing);
|
|||
|
}
|
|||
|
|
|||
|
if(thing.CType != CollectTypeDefine.SkyBox)
|
|||
|
{
|
|||
|
Utils.AddToDict(typeToThing, (int)thing.CType, thing);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
_skyBoxThings.Add(thing);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
private List<string> SaveThings(Dictionary<int, Dictionary<int, List<Thing>>> dataDict)
|
|||
|
{
|
|||
|
CreateNewPrefab("skybox", _skyBoxThings);
|
|||
|
List<string> configList = new List<string>();
|
|||
|
|
|||
|
var itorRoot = dataDict.GetEnumerator();
|
|||
|
while(itorRoot.MoveNext())
|
|||
|
{
|
|||
|
var rootGo = new GameObject("Thing_" + itorRoot.Current.Key);
|
|||
|
var itor = itorRoot.Current.Value.GetEnumerator();
|
|||
|
while(itor.MoveNext())
|
|||
|
{
|
|||
|
var rootName = GetRootName(itor.Current.Key);
|
|||
|
var thingList = itor.Current.Value;
|
|||
|
if(thingList != null)
|
|||
|
{
|
|||
|
var go = CopyToGameObject(rootName, thingList);
|
|||
|
go.transform.parent = rootGo.transform;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
string savePath = ConfigDefine.GetSavePrefabPath(rootGo.name + ".prefab");
|
|||
|
configList.Add(string.Format("{0}", itorRoot.Current.Key));
|
|||
|
|
|||
|
PrefabUtility.CreatePrefab(savePath, rootGo);
|
|||
|
AssetDatabase.ImportAsset(savePath);
|
|||
|
|
|||
|
GameObject.DestroyImmediate(rootGo);
|
|||
|
|
|||
|
}
|
|||
|
EditorUtility.ClearProgressBar();
|
|||
|
|
|||
|
return configList;
|
|||
|
}
|
|||
|
|
|||
|
private string GetRootName(int thingType)
|
|||
|
{
|
|||
|
CollectTypeDefine cType = (CollectTypeDefine)thingType;
|
|||
|
switch(cType)
|
|||
|
{
|
|||
|
case CollectTypeDefine.Effect:
|
|||
|
return "scene_effect";
|
|||
|
case CollectTypeDefine.Grass:
|
|||
|
return "grass";
|
|||
|
case CollectTypeDefine.SkyBox:
|
|||
|
return "skybox";
|
|||
|
}
|
|||
|
|
|||
|
return "default";
|
|||
|
}
|
|||
|
|
|||
|
private GameObject CopyToGameObject(string rootName, List<Thing> things)
|
|||
|
{
|
|||
|
GameObject go = new GameObject(rootName);
|
|||
|
|
|||
|
for (int i = 0; i < things.Count; ++i)
|
|||
|
{
|
|||
|
var inst = GameObject.Instantiate(things[i].Go);
|
|||
|
inst.name = things[i].Go.name;
|
|||
|
inst.transform.parent = go.transform;
|
|||
|
|
|||
|
Utils.CopyTransProperty(inst.transform, things[i].Go.transform);
|
|||
|
Utils.CopyMesh(inst.transform, things[i].Go.transform);
|
|||
|
}
|
|||
|
|
|||
|
return go;
|
|||
|
}
|
|||
|
|
|||
|
private string CreateNewPrefab(string rootName, List<Thing> things)
|
|||
|
{
|
|||
|
GameObject go = new GameObject(rootName);
|
|||
|
|
|||
|
for(int i = 0; i < things.Count; ++i)
|
|||
|
{
|
|||
|
var inst = GameObject.Instantiate(things[i].Go);
|
|||
|
inst.name = things[i].Go.name;
|
|||
|
inst.transform.parent = go.transform;
|
|||
|
|
|||
|
Utils.CopyTransProperty(inst.transform, things[i].Go.transform);
|
|||
|
Utils.CopyMesh(inst.transform, things[i].Go.transform);
|
|||
|
}
|
|||
|
|
|||
|
string savePath = ConfigDefine.GetSavePrefabPath(rootName + ".prefab");
|
|||
|
|
|||
|
PrefabUtility.CreatePrefab(savePath, go);
|
|||
|
AssetDatabase.ImportAsset(savePath);
|
|||
|
|
|||
|
GameObject.DestroyImmediate(go);
|
|||
|
|
|||
|
return savePath;
|
|||
|
}
|
|||
|
|
|||
|
private void FindGameObjects(GameObject root, List<GameObject> refList)
|
|||
|
{
|
|||
|
List<GameObject> retList = refList;
|
|||
|
Transform rootTran = root.transform;
|
|||
|
if (rootTran.childCount == 0)
|
|||
|
{
|
|||
|
retList.Add(rootTran.gameObject);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
for (int i = 0; i < rootTran.childCount; ++i)
|
|||
|
{
|
|||
|
var temp = rootTran.GetChild(i);
|
|||
|
{
|
|||
|
FindGameObjects(temp.gameObject, refList);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private static CollectTypeDefine GetThingTypeFromName(string name)
|
|||
|
{
|
|||
|
if (name.IndexOf("sky", System.StringComparison.CurrentCultureIgnoreCase) >= 0)
|
|||
|
return CollectTypeDefine.SkyBox;
|
|||
|
if (name.IndexOf("grass", System.StringComparison.CurrentCultureIgnoreCase) >= 0)
|
|||
|
return CollectTypeDefine.Grass;
|
|||
|
if (name.IndexOf("effect", System.StringComparison.CurrentCultureIgnoreCase) >= 0)
|
|||
|
return CollectTypeDefine.Effect;
|
|||
|
|
|||
|
return CollectTypeDefine.Mass;
|
|||
|
}
|
|||
|
|
|||
|
private static bool IsBoxcollider(GameObject go)
|
|||
|
{
|
|||
|
return go.GetComponentInChildren<BoxCollider>() != null;
|
|||
|
}
|
|||
|
|
|||
|
private static Bounds GetThingBounds(GameObject go)
|
|||
|
{
|
|||
|
var mf = go.GetComponentInChildren<MeshFilter>();
|
|||
|
if (mf == null || mf.sharedMesh == null)
|
|||
|
{
|
|||
|
var boxcollider = go.GetComponentInChildren<BoxCollider>();
|
|||
|
if (boxcollider == null)
|
|||
|
{
|
|||
|
Transform trans = go.transform;
|
|||
|
Bounds bounds = new Bounds(trans.position, Vector3.zero);
|
|||
|
return bounds;
|
|||
|
}
|
|||
|
//boxcollider.bounds是世界坐标,这里需要相对坐标
|
|||
|
return new Bounds(boxcollider.center, boxcollider.size);
|
|||
|
}
|
|||
|
|
|||
|
return mf.sharedMesh.bounds;
|
|||
|
}
|
|||
|
|
|||
|
private static void DeleteOldThingPrefabs()
|
|||
|
{
|
|||
|
var path = ConfigDefine.GetSavePrefabPath();
|
|||
|
var fileList = Directory.GetFiles(path, "*.prefab");
|
|||
|
for(int i = 0; i < fileList.Length; ++i)
|
|||
|
{
|
|||
|
if (fileList[i].StartsWith("Thing_"))
|
|||
|
File.Delete(fileList[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|