You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Godot 如何实现不同尺寸面板/2D节点的无空隙随机屏幕排布

Godot 2D节点无空隙随机自动排布实现方案

你需要的无空隙填满效果本质是2D矩形装箱问题,以下是可直接在Godot中落地的实现方案:

核心实现步骤

  • 第一步:提前整理所有待排布节点的尺寸,优先按面积从大到小排序,同面积的节点可以随机打乱顺序,既能保证随机效果,又能避免大块节点最后塞不下产生留白。
  • 第二步:用单独数组维护当前的可用空余区域,初始状态下数组中只有一个和父容器/屏幕尺寸一致的完整矩形区域。
  • 第三步:每次放置节点时,遍历所有可用区域,找到第一个能容纳当前节点的区域,将节点的position设置为该区域的左上角坐标。
  • 第四步:节点放置完成后,将被占用的区域切割为两个新的空余区域:节点右侧的横向剩余区域、节点下方的纵向剩余区域,将两个新区域加入可用区域数组,同时删除已被占用的旧区域。

简化GDScript示例

extends Control

# 承载所有节点的父容器
@onready var container: Control = $Container
# 待排布的2D节点数组
var nodes_to_arrange: Array[Control] = []
# 存储可用空余区域的数组,每个元素为Rect2类型
var available_areas: Array[Rect2] = []

func _ready() -> void:
    # 读取所有子节点作为待排布节点
    nodes_to_arrange = container.get_children()
    # 初始化可用区域为父容器的完整尺寸
    available_areas.append(Rect2(Vector2.ZERO, container.size))
    
    # 节点排序:面积从大到小,同面积随机打乱
    nodes_to_arrange.sort_custom(func(a: Control, b: Control) -> bool:
        var area_a = a.size.x * a.size.y
        var area_b = b.size.x * b.size.y
        if area_a != area_b:
            return area_a > area_b
        return randi() % 2 == 0
    )
    
    # 逐个排布节点
    for node in nodes_to_arrange:
        arrange_single_node(node)

func arrange_single_node(node: Control) -> void:
    # 遍历找到第一个可容纳当前节点的可用区域
    for i in range(available_areas.size()):
        var target_area = available_areas[i]
        if target_area.size.x >= node.size.x and target_area.size.y >= node.size.y:
            # 放置节点到区域左上角
            node.position = target_area.position
            # 移除已被占用的旧区域
            available_areas.remove_at(i)
            # 切割添加右侧剩余区域
            if target_area.size.x - node.size.x > 0:
                available_areas.append(Rect2(
                    target_area.position + Vector2(node.size.x, 0),
                    Vector2(target_area.size.x - node.size.x, node.size.y)
                ))
            # 切割添加下方剩余区域
            if target_area.size.y - node.size.y > 0:
                available_areas.append(Rect2(
                    target_area.position + Vector2(0, node.size.y),
                    Vector2(target_area.size.x, target_area.size.y - node.size.y)
                ))
            return
    # 无可用区域时的异常处理,可按需调整
    push_warning("节点尺寸过大,无可用区域放置: " + node.name)

特殊场景适配

  • 如果待排布的是不规则形状节点,可以给每个节点添加CollisionShape2D,放置前使用PhysicsDirectSpaceState2D的intersect_shape方法检测是否和已有节点重叠,调整位置直到无重叠即可。
  • 需要适配不同屏幕尺寸时,排布前将初始可用区域的尺寸修改为当前屏幕的实际尺寸即可。

内容的提问来源于stack exchange,提问作者user3618687

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 01:12:01