Godot 有 HVBoxContainer 吗?
Is there a `HVBoxContainer` for Godot?
想一想您可能需要显示按钮列表的角色扮演游戏。用户可能会进入一个房间,在那里他们必须通过一系列选项(按钮)select。是否有一种 container/panel 可以水平显示可点击按钮,但需要时换行?
我能想到的最好的比喻是,想象一下需要点击背包中的物品,但每个物品的宽度可能不同。 (我可以让它们高度相同,但宽度会有所不同)
.---[My Backpack]------.
| aaa bbb cccc ddd |
| ee fff g |
| |
| |
`----------------------'
(选项来自数据库,因此在编译时不知道房间中可能有多少个选项,因此我需要以编程方式添加选项。)
this godot document 的最底部介绍了自定义容器布局,但我不清楚这在实践中如何运作
Godot 3.5 或更新版本的流容器
Godot 3.5(目前处于测试阶段)引入了 HFlowContainer
和 VFlowContainer
,它们将为所描述的目的服务。
HFlowContainer
将填满一行,当它们溢出时,它将添加一个新行并在那里继续。 VFlowContainer
将以类似的方式工作,但有列。
Godot 3.5 之前的流容器
对于旧版本的 Godot,您可以使用 HFlowContainer
插件,您可以在资产库 (here) 中找到它。 请注意,没有 VFlowContainer
对应项。
由于资产库中的所有内容都是免费和开源的,因此请随意阅读和修改代码,如果您想进行自定义 Container
,可以作为起点。
制作你自己的定制Container
制作自定义 Container
的要点是它必须定位其子项。
为了达到这种效果,您需要在 _notification
方法中对 NOTIFICATION_SORT_CHILDREN
做出反应。 您可能还想对 NOTIFICATION_RESIZED
做出反应。
你可以有一个方法 - 我称之为 layout
- 当你收到通知时调用它:
func _notification(what):
if what == NOTIFICATION_SORT_CHILDREN:
layout()
并且还从定义 Container
必须如何组织其子项的属性的设置器 (setget
) 调用 layout
。 要从 _notification
以外的任何地方调用 layout
,您可能需要使用 call_deferred("layout")
来防止任何可能的 re-layout 循环挂起或使游戏崩溃。
layout
方法将遍历可见子项 Control
并使用 get_combined_minimum_size
计算出它们的大小。
像这样:
func layout() -> void:
# …
for child in get_children():
var control := child as Control
if not is_instance_valid(control) or not control.visible:
continue
var size := control.get_combined_minimum_size()
# …
然后使用该信息计算子 Control
的位置和大小。当 Control
有增长空间时,您可能希望根据他们的 size_flags_stretch_ratio
.
将其分配给他们
一旦你确定了 Control
的位置和大小,使用 fit_child_in_rect
来定位它们,这将考虑增长和大小标志。
因此 - 除了最简单的 Container
s - 你将需要迭代子 Control
s 两次。为此,您可能会发现使用辅助数据结构来临时存储它们很有用。
想一想您可能需要显示按钮列表的角色扮演游戏。用户可能会进入一个房间,在那里他们必须通过一系列选项(按钮)select。是否有一种 container/panel 可以水平显示可点击按钮,但需要时换行?
我能想到的最好的比喻是,想象一下需要点击背包中的物品,但每个物品的宽度可能不同。 (我可以让它们高度相同,但宽度会有所不同)
.---[My Backpack]------.
| aaa bbb cccc ddd |
| ee fff g |
| |
| |
`----------------------'
(选项来自数据库,因此在编译时不知道房间中可能有多少个选项,因此我需要以编程方式添加选项。)
this godot document 的最底部介绍了自定义容器布局,但我不清楚这在实践中如何运作
Godot 3.5 或更新版本的流容器
Godot 3.5(目前处于测试阶段)引入了 HFlowContainer
和 VFlowContainer
,它们将为所描述的目的服务。
HFlowContainer
将填满一行,当它们溢出时,它将添加一个新行并在那里继续。 VFlowContainer
将以类似的方式工作,但有列。
Godot 3.5 之前的流容器
对于旧版本的 Godot,您可以使用 HFlowContainer
插件,您可以在资产库 (here) 中找到它。 请注意,没有 VFlowContainer
对应项。
由于资产库中的所有内容都是免费和开源的,因此请随意阅读和修改代码,如果您想进行自定义 Container
,可以作为起点。
制作你自己的定制Container
制作自定义 Container
的要点是它必须定位其子项。
为了达到这种效果,您需要在 _notification
方法中对 NOTIFICATION_SORT_CHILDREN
做出反应。 您可能还想对 NOTIFICATION_RESIZED
做出反应。
你可以有一个方法 - 我称之为 layout
- 当你收到通知时调用它:
func _notification(what):
if what == NOTIFICATION_SORT_CHILDREN:
layout()
并且还从定义 Container
必须如何组织其子项的属性的设置器 (setget
) 调用 layout
。 要从 _notification
以外的任何地方调用 layout
,您可能需要使用 call_deferred("layout")
来防止任何可能的 re-layout 循环挂起或使游戏崩溃。
layout
方法将遍历可见子项 Control
并使用 get_combined_minimum_size
计算出它们的大小。
像这样:
func layout() -> void:
# …
for child in get_children():
var control := child as Control
if not is_instance_valid(control) or not control.visible:
continue
var size := control.get_combined_minimum_size()
# …
然后使用该信息计算子 Control
的位置和大小。当 Control
有增长空间时,您可能希望根据他们的 size_flags_stretch_ratio
.
一旦你确定了 Control
的位置和大小,使用 fit_child_in_rect
来定位它们,这将考虑增长和大小标志。
因此 - 除了最简单的 Container
s - 你将需要迭代子 Control
s 两次。为此,您可能会发现使用辅助数据结构来临时存储它们很有用。