Skip to content

Instantly share code, notes, and snippets.

@GeorgiyRyaposov
Created January 26, 2025 02:31
Show Gist options
  • Save GeorgiyRyaposov/880f3933971d5ad76ea9f5886a7be0d5 to your computer and use it in GitHub Desktop.
Save GeorgiyRyaposov/880f3933971d5ad76ea9f5886a7be0d5 to your computer and use it in GitHub Desktop.
Generic 2d quad tree implementation
using System.Collections.Generic;
using UnityEngine;
namespace Code.Scripts.Utils
{
public class QuadTree<T> where T : Component
{
private const int Capacity = 4;
private readonly Rect _bounds;
private readonly List<T> _items;
private QuadTree<T>[] _children;
public QuadTree(Rect bounds)
{
_bounds = bounds;
_items = new List<T>();
_children = null;
}
public void Insert(T item)
{
if (!_bounds.Contains(item.transform.position))
{
return;
}
if (_items.Count < Capacity)
{
_items.Add(item);
}
else
{
if (_children == null)
{
Subdivide();
}
foreach (var child in _children)
{
child.Insert(item);
}
}
}
public bool Remove(T item)
{
if (!_bounds.Contains(item.transform.position))
{
return false;
}
// Если объект находится в текущем узле, удаляем его
if (_items.Remove(item))
{
return true;
}
// Если узел имеет дочерние узлы, рекурсивно удаляем объект из них
if (_children != null)
{
foreach (var child in _children)
{
if (child.Remove(item))
{
return true;
}
}
}
return false;
}
// Разделение узла на 4 дочерних узла
private void Subdivide()
{
var halfWidth = _bounds.width / 2;
var halfHeight = _bounds.height / 2;
_children = new QuadTree<T>[4];
_children[0] = new QuadTree<T>(new Rect(_bounds.x, _bounds.y, halfWidth, halfHeight));
_children[1] = new QuadTree<T>(new Rect(_bounds.x + halfWidth, _bounds.y, halfWidth, halfHeight));
_children[2] = new QuadTree<T>(new Rect(_bounds.x, _bounds.y + halfHeight, halfWidth, halfHeight));
_children[3] = new QuadTree<T>(new Rect(_bounds.x + halfWidth, _bounds.y + halfHeight, halfWidth, halfHeight));
// Перераспределяем объекты в дочерние узлы
foreach (var obj in _items)
{
foreach (var child in _children)
{
child.Insert(obj);
}
}
_items.Clear();
}
// Поиск объектов в заданной области
public void Query(Rect area, List<T> found)
{
if (!_bounds.Overlaps(area))
{
return;
}
foreach (var obj in _items)
{
if (area.Contains(obj.transform.position))
{
found.Add(obj);
}
}
if (_children != null)
{
foreach (var child in _children)
{
child.Query(area, found);
}
}
}
public void Clear()
{
_items.Clear();
if (_children != null)
{
foreach (var child in _children)
{
child.Clear();
}
}
_children = null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment