目录
效果演示
扫描二维码关注公众号,回复:
15697498 查看本文章
代码部分
定义类
public class ObjData
{
public string uid;
public GameObject prefab;
public Vector3 pos;
public Vector3 ang;
public ObjData(GameObject prefab,Vector3 pos,Vector3 ang)
{
this.uid=System.Guid.NewGuid().ToString();
this.prefab = prefab;
this.pos = pos;
this.ang = ang;
}
}
Tree部分
using UnityEngine;
public class Tree
{
public Bounds Bounds;
private Node root;
public int maxDepth = 6;
public int maxChildCount = 4;
public Tree(Bounds bound)
{
this.Bounds = bound;
this.root = new Node(bound, 0, this);
}
//插入数据
public void InserData(ObjData data)
{
root.InserData(data);
}
public void DrawBound()
{
root.DrawBound();
}
public void TriggerMove(Plane[] planes)
{
root.TriggerMove(planes);
}
}
逻辑部分
using System.Collections.Generic;
using UnityEngine;
public class Node
{
public Bounds bound;
public int myDepth;//当前层数
public Tree tree;
public List<ObjData> datas= new List<ObjData>();//数据
public Node[] childs;//子节点
public Vector2[] bif = new Vector2[]
{
new Vector2(-1,1),
new Vector2(1,1),
new Vector2(-1,-1),
new Vector2(1,-1),
};
public Node(Bounds bound, int myDepth, Tree tree)
{
this.bound = bound;
this.myDepth = myDepth;
this.tree = tree;
}
public void InserData(ObjData data)
{
//层级没到上限 且 没有子节点 可以创建子节点
if(myDepth<tree.maxDepth&&childs==null)
{
creatChild();
}
if(childs!=null)
{
for (int i = 0; i < childs.Length; i++)
{
//判断数据的位置是否归属于该子节点的区域
if (childs[i].bound.Contains(data.pos))
{
//继续去下一层查找
childs[i].InserData(data);
break;
}
}
}
else
{
datas.Add(data);
}
}
private void creatChild()
{
childs = new Node[tree.maxChildCount];
for (int i = 0; i < tree.maxChildCount; i++)
{
//计算相对坐标
Vector3 center= new Vector3(bif[i].x * bound.size.x / 4, 0, bif[i].y*bound.size.z/4);
//计算大小
Vector3 size = new Vector3(bound.size.x / 2, 0, bound.size.z / 2);
//设置矩阵
Bounds childbound = new Bounds(center + bound.center, size);
//给子节点赋值
childs[i] = new Node(childbound, myDepth + 1, tree);
}
}
public void DrawBound()
{
//有数据画蓝色框框
if (datas.Count!=0)
{
Gizmos.color = Color.blue;
Gizmos.DrawWireCube(bound.center, bound.size - Vector3.one * 0.1f);
}
else//没数据画绿色框框
{
Gizmos.color = Color.green;
Gizmos.DrawWireCube(bound.center, bound.size - Vector3.one * 0.1f);
}
if(childs!=null)
{
for (int i = 0; i < childs.Length; i++)
{
childs[i].DrawBound();
}
}
}
public void TriggerMove(Plane[] planes)
{
//有子物体让子物体去判断是否重叠
if(childs!=null)
{
for (int i = 0; i < childs.Length; i++)
{
childs[i].TriggerMove(planes);
}
}
for (int i = 0; i < datas.Count; i++)
{
//判断矩阵与6个面是否重叠
datas[i].prefab.SetActive(GeometryUtility.TestPlanesAABB(planes, bound));
}
}
}
启动逻辑
using UnityEngine;
public class CreatCube : MonoBehaviour
{
public GameObject cube;
public Bounds mainBound;
Tree tree;//树
bool startEdnd = false;//是否初始化完毕
public Camera cam;//相机
Plane[] planes;//视椎体的6个面
void Start()
{
planes= new Plane[6];//开辟内存
//初始化场景最大分块
Bounds bounds = new Bounds(transform.position, new Vector3(100, 0, 100));
//创建树
tree = new Tree(bounds);
for (int x = -50; x < 50; x++)
{
for (int z = -50; z < 50; z++)
{
if(Random.Range(0,10)<1)
{
GameObject c=Instantiate(cube,transform);
c.transform.position=new Vector3(x,0,z);
c.transform.eulerAngles = new Vector3(0, Random.Range(0, 360), 0);
//将预制体数据存入树
tree.InserData(new ObjData(c,c.transform.position,c.transform.eulerAngles));
}
}
}
startEdnd = true;
}
void Update()
{
if(startEdnd)//判断初始化结束后
{
//给6个面赋值
GeometryUtility.CalculateFrustumPlanes(cam, planes);
//通过树判断是否显示
tree.TriggerMove(planes);
}
}
private void OnDrawGizmos()
{
if(startEdnd)//判断初始化结束后
{
//通过树绘制包围盒
tree.DrawBound();
}
else
{
Gizmos.DrawWireCube(mainBound.center, mainBound.size);
}
}
}