using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
public class TreeData
{
// 현재 영역의 Level
public int level = 0;
public int maxValue = 2;
public int currentValue = 0;
public Rect area;
public List<TreeData> nodeList;
// 다음 Level의 영역을 생성한다.
public void NextLevelNode()
{
if (nodeList != null)
return;
nodeList = new List<TreeData>();
Rect[] lRectArrer = Split();
for (int i = 0; i < 4; ++i)
{
TreeData lTreeData = new TreeData();
lTreeData.level = level + 1;
lTreeData.area = lRectArrer[i];
nodeList.Add(lTreeData);
}
}
// 공간 분할함수
private Rect[] Split()
{
float subWidth = area.width *0.5f;
float subHeight = area.height * 0.5f;
float x = area.x;
float y = area.y;
Rect[] lRectArray = new Rect[4];
lRectArray[0] = new Rect( x - (subWidth * 0.5f), y + (subHeight * 0.5f), subWidth, subHeight);
lRectArray[1] = new Rect( x + (subWidth * 0.5f), y + (subHeight * 0.5f), subWidth, subHeight);
lRectArray[2] = new Rect( x + (subWidth * 0.5f), y - (subHeight * 0.5f), subWidth, subHeight);
lRectArray[3] = new Rect( x - (subWidth * 0.5f), y - (subHeight * 0.5f), subWidth, subHeight);
return lRectArray;
}
}
public class QuadTree : MonoBehaviour
{
public RectTransform quadMap;
public List<GameObject> objectList;
private TreeData _treeData;
private List<Color> colorList;
public void Start()
{
// 가장 기초적인 0Level의 영역
_treeData = new TreeData();
_treeData.currentValue = int.MaxValue; // 기초 영역이 사라지는걸 방지하기 위하여 현재영역이 가지고있는 object의 갯수는 int.MaxValue로 잡음
_treeData.level = 0;
_treeData.area = new Rect(quadMap.localPosition.y, quadMap.localPosition.y, quadMap.rect.width, quadMap.rect.height);
_treeData.NextLevelNode();
//* Gizmo 색상
colorList = new List<Color>();
for (int i = 0; i < 100; ++i)
{
colorList.Add(Random.ColorHSV());
}
//*/
}
public void Update()
{
NodeAreaCheck(_treeData);
}
// 객채가 n들어왔는지판단하는함수
private void NodeAreaCheck(TreeData pTreeData)
{
// 모든 Node를 순회하여 자기 공간안에 객체가 몇개있는지 파악
// 나의 공간에 객채가 n개있으면 분리
// 나와 같은 레벨의 공간들 전부 객체를 n개 가지고있지않다면 다시 합체
// 현재 나의 공간에 n개의 객체를 가지고 있지 않다면 나의 아래 node들이 n개의 객체를 가지고 있지 않다는 이야기 그러므로 다 지운다.
if (pTreeData == null || pTreeData.nodeList == null)
return;
foreach (var lNode in pTreeData.nodeList)
{
// lnode 객체갯수 확인
if (AreaInObjectCount(lNode) > lNode.maxValue)
{
lNode.NextLevelNode();
}
NodeAreaCheck(lNode);
}
if(pTreeData.currentValue <= pTreeData.maxValue)
pTreeData.nodeList = null;
}
// 자신의 영역에 있는 Object의 갯수를 반환
private int AreaInObjectCount(TreeData pTreeData)
{
pTreeData.currentValue = 0;
int lCount = objectList.Count;
for (int i = 0; i < lCount; ++i)
{
var lDis = Vector3.Distance(pTreeData.area.position, objectList[i].transform.localPosition);
if (lDis <= (pTreeData.area.height * 0.5f) + (objectList[i].transform.localScale.x * 0.5f))
{
pTreeData.currentValue++;
}
}
return pTreeData.currentValue;
}
//* 쿼드트리로 분리된 영역을 Gizmo로 그려준다.
void OnDrawGizmos()
{
Drawing(_treeData);
}
private void Drawing(TreeData pTreeData)
{
if (pTreeData == null || pTreeData.nodeList == null)
return;
foreach (var lNode in pTreeData.nodeList)
{
ColorSelect(pTreeData.level);
DrawRect(lNode.area);
Drawing(lNode);
}
}
void DrawRect(Rect rect)
{
Gizmos.DrawWireCube(new Vector3(rect.x + 1920, rect.y + 1080, 0.01f), new Vector3(rect.size.x, rect.size.y, 0.01f));
}
private void ColorSelect(int pLevel)
{
Gizmos.color = colorList[pLevel];
}
//*/
}