using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class BigWorldEditor : EditorWindow
{
[MenuItem(“BigWorldMenu/BigWorld”)]
static void ShowWindow()
{
var window = GetWindow();
window.titleContent = new GUIContent(“BigWorld”);//窗口左上方的名字
window.Show();
}
//每个地图分块的高和宽
int chunkwidth = 20;
int chunkheight = 20;
//为了保证每个小的地形和物体都能被分配到每个分块的地图里面,尽可能初始分块的时候设置大一点
int gridz = 10;
int gridx = 10;
//地图中空的父节点
Transform mapRoot;
private void OnGUI()
{
//定义一个集合列表存储一下每一个分块地图
List<Transform> Chunks = new List<Transform>();
//创建一个UI空间,可以拖拽一个场景中的对象
mapRoot = (Transform)EditorGUILayout.ObjectField("根节点",mapRoot,typeof(Transform),true);//true才可以从场景托物体进来 不然只能从asset中拖物体
if (GUILayout.Button("分割地形"))
{
BuildingRoot buildingRoot = mapRoot.GetComponent<BuildingRoot>();//获取地图根节点的脚本
for (int i = -gridx / 2; i < gridx / 2; i++)//axis - x
{
for (int j = -gridz / 2; j < gridz /2; j++)//axis - z
{
//创建分块地图对应的每个空的根节点
GameObject chunk = new GameObject(string.Format("Chunk{0} - {1}",i,j));
chunk.transform.SetParent(mapRoot);//根节点是BuildingRoot
chunk.transform.localScale = Vector3.one;//指定空节点对象的大小
//每一个分块的位置点都放在每一个小块的中心点.
chunk.transform.position = new Vector3(i * chunkwidth + chunkwidth / 2, 0, j * chunkheight + chunkheight / 2);
//每一个小分块都添加到对应的集合列表中
Chunks.Add(chunk.transform);
}
}
//获取到场景中所有第一层的子节点(所有的terrain对象和cube对象)
List<Transform> children = new List<Transform>();
for (int i = 0; i < mapRoot.childCount; i++)//遍历根节点下面所有的子节点
{
Transform child = mapRoot.GetChild(i);
//不需要把创建的每一个分块的节点(chunk0-0),不需要添加到集合列表中
if (child.name.Contains("Ch"))
{
continue;
}
children.Add(child);
}
//根据距离实现地图分块
for (int i = 0; i < children.Count; i++)
{
//调用分块的方法
SetParentChunk(children[i],Chunks);
}
buildingRoot.chunkDates.Clear();//清空集合
//保存到Resources/Chunks文件夹下面,后面实现动态加载
for (int i = 0; i < Chunks.Count; i++)//遍历每一个分块地图,观察有没有子对象,如果有子物体在,就是需要的地图块,把它作为预制体
{
if(Chunks[i].childCount != 0)
{
string fileResourcesPath = "Chunks/" + Chunks[i].name;
PrefabUtility.SaveAsPrefabAsset(Chunks[i].gameObject, Application.dataPath + "/Resources/" + fileResourcesPath + ".prefab");
//为每一个分块地图的属性进行赋值
ChunkData chunkData = new ChunkData();
chunkData.id = i;//只要Id不重复即可
chunkData.position = Chunks[i].position;//地图在场景中的位置记录下来
chunkData.prefabPath = fileResourcesPath;
buildingRoot.chunkDates.Add(chunkData);
}
DestroyImmediate(Chunks[i].gameObject);//销毁掉场景中原来的地图小分块 ---编辑器模式下可以用DestroyImmediate
}
}
}
//第一个参数指的是:每一个要分配进去的Terrain或者Cube,第二个参数指的是地图分块的集合列表
void SetParentChunk(Transform mapchild,List<Transform> chunks)
{
int index = 0;//距离比较近的一个小分块的索引
float distance = float.MaxValue;//参考距离
for (int i = 0; i < chunks.Count; i++)//遍历每一个分块的根节点
{
Vector3 childPos = mapchild.position;
if (mapchild.name.Contains("Terrain"))//如果子对象是每一个地形,修改它的位置放在地图小块中心点的位置
{
childPos += new Vector3(chunkwidth /2,0,chunkheight / 2);
}
float tempDis = Vector3.Distance(childPos,chunks[i].position);//求出每个对象距离分块的地图的距离
if(tempDis < distance)
{
distance = tempDis;
index = i;
}
}
//找到距离每一个mapchild最近的一个地图块,设置为其对应的父节点
mapchild.SetParent(chunks[index]);
}
}
加粗样式using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BuildingRoot : MonoBehaviour
{
public List chunkDates = new List();//存储所有的分块地图的结合列表
int loadDistance = 100;//分块地图可以被加载出来的加载距离
int unloadDistance = 200;//分块地图可以被卸载的卸载距离,通常卸载的距离大于加载距离
Dictionary<int, GameObject> LoadedChunks = new Dictionary<int, GameObject>();//已经被加载出来的分块地图的列表
public Transform player;//玩家
//思想:1.通过判断玩家和分块地图之间的距离,如果超过卸载距离且该分块地图已经被加载进来,就可以销毁,从集合列表移除
//2.如果玩家和分块地图之间的距离在加载距离范围内,并且该分块地图没有被加载进来,就相当于是第一次需要加载克隆分块地图的预制体
private void Update()
{
for (int i = 0; i < chunkDates.Count; i++)
{
float distance = Vector3.Distance(player.transform.position, chunkDates[i].position);
Debug.Log(distance);
if(distance > unloadDistance)//处理情况1
{
if (LoadedChunks.ContainsKey(chunkDates[i].id))//且该分块地图已经被加载进来
{
GameObject.Destroy(LoadedChunks[chunkDates[i].id]);//chunkDates[i].id是int类型的,是加载出来的分块地图的id属性
LoadedChunks.Remove(chunkDates[i].id);//从已经被加载出来的分块地图的列表中移除
}
}
else if (distance < loadDistance)//处理情况2
{
if (!LoadedChunks.ContainsKey(chunkDates[i].id))//且该分块地图没有被加载进来
{
//就相当于是第一次需要加载,克隆分块地图的预制体
GameObject prefab = Resources.Load<GameObject>(chunkDates[i].prefabPath);
GameObject obj = Instantiate(prefab);//克隆分块地图
obj.transform.SetParent(transform);//设置克隆出来的每一个分块地图的父节点为场景中的空的根节点的对象BuildingRoot
obj.transform.position = chunkDates[i].position;//位置赋值
LoadedChunks.Add(chunkDates[i].id, obj);//放到字典的集合列表里面 ,key 是id value是GameObject类型的每一个分块地图的对象
}
}
}
}
}
[Serializable]//为了在Inspector面板上可以看到类的属性的数据
public class ChunkData//封装一个分块地图的数据类
{
public int id;//加载的地图分块的编号
public Vector3 position;//地图分块的位置
public string prefabPath;//预制物体的路径
}