Last active
February 23, 2023 16:15
-
-
Save Denchyaknow/246fa0459fa72d62d8af61944ea55b2b to your computer and use it in GitHub Desktop.
Template_QuadTree (Spawns) a spatial partitioning data structure to store your spawn points, so you can make queries to find the closest spawn point to a given point in a efficient way.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.Linq; | |
using UnityEngine; | |
namespace HunyLand.Utils | |
{ | |
/// <summary> | |
/// QuadTree (Spawns) a spatial partitioning data structure to store your spawn points, | |
/// so you can make queries to find the closest spawn point to a given point in a efficient way. | |
/// Mage: Dencho | |
/// </summary> | |
public class QuadTree<T> where T : BaseSpawn | |
{ | |
private const int MAX_OBJECTS = 10;//The MAX_OBJECTS and MAX_LEVELS constants can be adjusted to suit the specific needs of your game. | |
private const int MAX_LEVELS = 5; | |
private int level; | |
private List<T> objects; | |
private Bounds bounds; | |
private QuadTree<T>[] children; | |
public QuadTree(int level, Bounds bounds) | |
{ | |
this.level = level; | |
this.objects = new List<T>(); | |
this.bounds = bounds; | |
this.children = new QuadTree<T>[4]; | |
} | |
public void Clear() | |
{ | |
objects.Clear(); | |
for (int i = 0; i < children.Length; i++) | |
{ | |
if (children[i] != null) | |
{ | |
children[i].Clear(); | |
children[i] = null; | |
} | |
} | |
} | |
public void Insert(T spawn) | |
{ | |
if (children[0] != null) | |
{ | |
int index = GetIndex(spawn.transform.position); | |
if (index != -1) | |
{ | |
children[index].Insert(spawn); | |
return; | |
} | |
} | |
objects.Add(spawn); | |
if (objects.Count > MAX_OBJECTS && level < MAX_LEVELS) | |
{ | |
if (children[0] == null) | |
{ | |
Split(); | |
} | |
int i = 0; | |
while (i < objects.Count) | |
{ | |
int index = GetIndex(objects[i].transform.position); | |
if (index != -1) | |
{ | |
children[index].Insert(objects[i]); | |
objects.RemoveAt(i); | |
} | |
else | |
{ | |
i++; | |
} | |
} | |
} | |
} | |
public bool Remove(T spawn) | |
{ | |
if (children[0] != null) | |
{ | |
int index = GetIndex(spawn.transform.position); | |
if (index != -1 && children[index].Remove(spawn)) | |
{ | |
return true; | |
} | |
} | |
if (objects.Remove(spawn)) | |
{ | |
return true; | |
} | |
return false; | |
} | |
public List<T> Retrieve(Vector3 position) | |
{ | |
List<T> spawnInRange = new List<T>(); | |
int index = GetIndex(position); | |
if (index != -1 && children[0] != null) | |
{ | |
spawnInRange = children[index].Retrieve(position); | |
} | |
spawnInRange.AddRange(objects.Where(spawn => spawn.IsAvailable() && (spawn.transform.position - position).sqrMagnitude <= spawn.range * spawn.range)); | |
return spawnInRange; | |
} | |
private void Split() | |
{ | |
float subWidth = (bounds.extents.x / 2); | |
float subHeight = (bounds.extents.z / 2); | |
float x = bounds.center.x; | |
float y = bounds.center.z; | |
children[0] = new QuadTree<T>(level + 1, new Bounds(new Vector3(x + subWidth, 0, y + subHeight), new Vector3(subWidth, subHeight, 0))); | |
children[1] = new QuadTree<T>(level + 1, new Bounds(new Vector3(x - subWidth, 0, y + subHeight), new Vector3(subWidth, subHeight, 0))); | |
children[2] = new QuadTree<T>(level + 1, new Bounds(new Vector3(x - subWidth, 0, y - subHeight), new Vector3(subWidth, subHeight, 0))); | |
children[3] = new QuadTree<T>(level + 1, new Bounds(new Vector3(x + subWidth, 0, y - subHeight), new Vector3(subWidth, subHeight, 0))); | |
} | |
private int GetIndex(Vector3 position) | |
{ | |
int index = -1; | |
double verticalMidpoint = bounds.center.x; | |
double horizontalMidpoint = bounds.center.z; | |
bool topQuadrant = (position.z > horizontalMidpoint); | |
bool bottomQuadrant = (position.z < horizontalMidpoint); | |
bool leftQuadrant = (position.x < verticalMidpoint); | |
bool rightQuadrant = (position.x > verticalMidpoint); | |
if (topQuadrant) | |
{ | |
if (leftQuadrant) | |
{ | |
index = 0; | |
} | |
else if (rightQuadrant) | |
{ | |
index = 1; | |
} | |
} | |
else if (bottomQuadrant) | |
{ | |
if (leftQuadrant) | |
{ | |
index = 2; | |
} | |
else if (rightQuadrant) | |
{ | |
index = 3; | |
} | |
} | |
return index; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment