松散四叉树

松散四叉树的核心思想
每个子节点的实际大小是标准四叉树的2倍,但逻辑上的划分点不变。

这样,对象即使稍微移动,仍然可能停留在同一个节点中,不需要频繁删除/重新插入。

当查询时,虽然子节点范围更大,但整体查询速度仍然优于普通四叉树。

示意图(普通 vs. 松散四叉树)
普通四叉树:
+----+----+
| 1 | 2 |
+----+----+
| 3 | 4 |
+----+----+
(对象跨越 2,3 节点,需要存储在多个子节点)

松散四叉树(每个子区域放大2倍):
+----+----+
| 1 | 2 |
+----+----+
| 3 | 4 |
+----+----+
(对象跨越区域,但仍然存储在 1 个子节点)

优势
✅ 适合动态对象:

允许对象在一定范围内移动,而无需频繁调整四叉树结构。

比普通四叉树更适合游戏场景(如怪物 AI、子弹碰撞等)。

✅ 查询更高效:

避免对象存储在多个子节点,减少不必要的查询。

✅ 插入/删除性能更好:

由于松散范围,减少了对象需要重新插入的次数。

`
class LooseQuadtree {
class Node {
float x, y, size;
List objects = new ArrayList<>();
Node[] children;

    Node(float x, float y, float size) {
        this.x = x;
        this.y = y;
        this.size = size * 2;  // 扩大节点范围(松散)
        this.children = null;
    }
    
    boolean contains(GameObject obj) {
        return obj.x >= x - size / 2 && obj.x <= x + size / 2 &&
               obj.y >= y - size / 2 && obj.y <= y + size / 2;
    }
}

private Node root;

public LooseQuadtree(float x, float y, float size) {
    root = new Node(x, y, size);
}

public void insert(GameObject obj) {
    insert(root, obj);
}

private void insert(Node node, GameObject obj) {
    if (!node.contains(obj)) return; // 物体不在该节点范围内

    if (node.children == null) {  // 叶子节点
        node.objects.add(obj);
        return;
    }

    // 递归插入到子节点
    for (Node child : node.children) {
        insert(child, obj);
    }
}

public List<GameObject> queryRange(float qx, float qy, float qsize) {
    return queryRange(root, qx, qy, qsize);
}

private List<GameObject> queryRange(Node node, float qx, float qy, float qsize) {
    List<GameObject> results = new ArrayList<>();

    if (node == null) return results;
    if (!intersects(node, qx, qy, qsize)) return results;

    results.addAll(node.objects);

    if (node.children != null) {
        for (Node child : node.children) {
            results.addAll(queryRange(child, qx, qy, qsize));
        }
    }

    return results;
}

private boolean intersects(Node node, float qx, float qy, float qsize) {
    return !(node.x - node.size / 2 > qx + qsize / 2 ||
             node.x + node.size / 2 < qx - qsize / 2 ||
             node.y - node.size / 2 > qy + qsize / 2 ||
             node.y + node.size / 2 < qy - qsize / 2);
}

}

class GameObject {
float x, y;
}

`

posted @ 2025-03-26 23:07  ZhangSir游戏老兵  阅读(90)  评论(0)    收藏  举报