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; } }; /// /// 收集场景中的物件,以分块区域来划分,生成新的prefab /// public class CollectThings { List _allTerrainDatas = new List(); List _grassThings = new List(); List _skyBoxThings = new List(); List _effectThings = new List(); //跨mesh的普通物件 List _otherThings = new List(); //一些没有跨mesh存在的物件,则集中存放到一起,保存成一个新的prefab Dictionary> _thingInOneTerrainDict = new Dictionary>(); private string _curMapName = ""; //记录各个分块 Dictionary _resolutionDict = new Dictionary(); //> Dictionary>> _collectThingDict = new Dictionary>>(); private int _mapSize = 0; private int _blockSize = 0; /// /// 设置分辨率 /// /// 地图大小 /// 分块大小 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 LoadAllSplitedTerrain(string mapName) { List list = new List(); 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 gos = new List(); 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> typeToThing; if(!_collectThingDict.TryGetValue(thing.Index, out typeToThing)) { typeToThing = new Dictionary>(); _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 SaveThings(Dictionary>> dataDict) { CreateNewPrefab("skybox", _skyBoxThings); List configList = new List(); 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 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 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 refList) { List 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() != null; } private static Bounds GetThingBounds(GameObject go) { var mf = go.GetComponentInChildren(); if (mf == null || mf.sharedMesh == null) { var boxcollider = go.GetComponentInChildren(); 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]); } } } }