using System.Collections.Generic;
using System.Diagnostics;
public static void Main()
Quadtree quadtree = new Quadtree(-32, -32, 64, 64);
Character character1 = new Character(0, 0, quadtree);
Character character2 = new Character(0, 1, quadtree);
Random random = new Random();
for (int i = 0; i < 100; i++)
float x = random.Next(-32000, 32001);
float y = random.Next(-32000, 32001);
Character character = new Character(x / 1000, y / 1000, quadtree);
Stopwatch stopwatch = new Stopwatch();
List<CharacterPosition> charactersNearby = quadtree.FindCharactersInArea(character1, 20);
TimeSpan elapsedTime = stopwatch.Elapsed;
double milliseconds = elapsedTime.TotalMilliseconds;
Console.WriteLine($"執行時間: {milliseconds} 毫秒");
Console.WriteLine("在20單位距離內的角色數量:" + charactersNearby.Count);
foreach (var character in charactersNearby)
Console.WriteLine("X: " + character.x + ", Y: " + character.y);
character1.Move(150, 150);
private CharacterPosition position;
private Quadtree quadtree;
public Character(float x, float y, Quadtree quadtree)
position = new CharacterPosition(x, y);
this.quadtree = quadtree;
quadtree.AddCharacter(position);
public void Move(float newX, float newY)
quadtree.RemoveCharacter(position);
quadtree.AddCharacter(position);
public CharacterPosition GetPosition()
public CharacterPosition(float x, float y)
this.uid = Guid.NewGuid();
public List<CharacterPosition> characters;
public QuadTreeNode[] children;
public QuadTreeNode(float x, float y, float width, float height)
characters = new List<CharacterPosition>();
private QuadTreeNode root;
private int maxCharactersPerNode = 4;
private Dictionary<Guid, CharacterPosition> characterUIDMap = new Dictionary<Guid, CharacterPosition>();
public Quadtree(float x, float y, float width, float height)
root = new QuadTreeNode(x, y, width, height);
public void AddCharacter(CharacterPosition character)
characterUIDMap.Add(character.uid, character);
AddCharacterRecursive(root, character);
private void AddCharacterRecursive(QuadTreeNode node, CharacterPosition character)
if (node.children == null && node.characters.Count < maxCharactersPerNode)
node.characters.Add(character);
float subWidth = node.width / 2f;
float subHeight = node.height / 2f;
if (character.x < node.x + subWidth)
if (character.y < node.y + subHeight)
if (node.children == null)
AddCharacterRecursive(node.children[0], character);
if (node.children == null)
AddCharacterRecursive(node.children[1], character);
if (character.y < node.y + subHeight)
if (node.children == null)
AddCharacterRecursive(node.children[2], character);
if (node.children == null)
AddCharacterRecursive(node.children[3], character);
private void Subdivide(QuadTreeNode node)
float subWidth = node.width / 2f;
float subHeight = node.height / 2f;
node.children = new QuadTreeNode[4];
node.children[0] = new QuadTreeNode(x, y, subWidth, subHeight);
node.children[1] = new QuadTreeNode(x, y + subHeight, subWidth, subHeight);
node.children[2] = new QuadTreeNode(x + subWidth, y, subWidth, subHeight);
node.children[3] = new QuadTreeNode(x + subWidth, y + subHeight, subWidth, subHeight);
foreach (var character in node.characters)
AddCharacterRecursive(node.children[GetCharacterQuadrant(node, character)], character);
private int GetCharacterQuadrant(QuadTreeNode node, CharacterPosition character)
float subWidth = node.width / 2f;
float subHeight = node.height / 2f;
if (character.x < node.x + subWidth)
if (character.y < node.y + subHeight)
if (character.y < node.y + subHeight)
public void RemoveCharacter(CharacterPosition character)
characterUIDMap.Remove(character.uid);
RemoveCharacterRecursive(root, character);
private bool RemoveCharacterRecursive(QuadTreeNode node, CharacterPosition character)
if (node.characters.Remove(character))
if (node.children != null)
foreach (var child in node.children)
if (RemoveCharacterRecursive(child, character))
public List<CharacterPosition> FindCharactersInArea(Character character, float radius)
CharacterPosition position = character.GetPosition();
List<CharacterPosition> charactersInArea = new List<CharacterPosition>();
FindCharactersInAreaRecursive(root, position.x, position.y, radius, charactersInArea, character.GetUID());
private void FindCharactersInAreaRecursive(QuadTreeNode node, float centerX, float centerY, float radius, List<CharacterPosition> charactersInArea, Guid uidToExclude)
float closestX = Math.Max(node.x, Math.Min(centerX, node.x + node.width));
float closestY = Math.Max(node.y, Math.Min(centerY, node.y + node.height));
float distanceX = centerX - closestX;
float distanceY = centerY - closestY;
float distanceSquared = (distanceX * distanceX) + (distanceY * distanceY);
if (distanceSquared > radius * radius)
foreach (var character in node.characters)
if (character.uid == uidToExclude)
float dx = character.x - centerX;
float dy = character.y - centerY;
if ((dx * dx) + (dy * dy) <= radius * radius)
charactersInArea.Add(character);
if (node.children != null)
foreach (var child in node.children)
FindCharactersInAreaRecursive(child, centerX, centerY, radius, charactersInArea, uidToExclude);
private void ClearRecursive(QuadTreeNode node)
if (node.children != null)
foreach (var child in node.children)