对于游戏开发者来说,UI(用户界面)是玩家与游戏交互的第一扇门。而Godot的Control节点作为UI系统的核心,能轻松实现按钮、菜单、对话框等交互组件。本文将以​​鸿蒙折叠屏适配​​为目标,带你用Control节点制作一个基础游戏菜单,并解决折叠屏下的布局难题。


一、为什么选择Control节点做UI?

在Godot中,Control节点是所有UI元素的基类(如按钮Button、标签Label、面板Panel),它天生支持:

  • ​布局系统​​:通过锚点(Anchor)、边距(Margin)自动对齐父节点;
  • ​输入响应​​:内置点击、悬停等事件,无需手动检测触摸位置;
  • ​样式自定义​​:支持主题(Theme)全局配置字体、颜色、圆角等;
  • ​折叠屏适配​​:通过动态调整尺寸和位置,适配不同屏幕形态。

对于新手来说,Control节点的可视化编辑(在Godot编辑器中拖拽调整)和简洁的API(如positionsizeanchor_left)能大幅降低UI开发门槛。


二、实战准备:创建菜单场景

1. 新建鸿蒙适配项目

  • 打开Godot 4.2+版本,创建新项目(选择2D模板);
  • 配置鸿蒙SDK路径(参考前文《鸿蒙适配:Godot项目初始化》);
  • 导出设置中勾选“鸿蒙(HarmonyOS)”导出模板。

2. 构建菜单场景结构

我们需要一个主菜单,包含“开始游戏”“设置”“退出”三个按钮,以及顶部标题。场景结构如下:

MainMenu (Control)  # 主菜单面板
├── Title (Label)    # 游戏标题
├── ButtonContainer (VBoxContainer)  # 按钮容器(垂直排列)
│   ├── StartBtn (Button)  # 开始按钮
│   ├── SettingsBtn (Button)  # 设置按钮
│   └── ExitBtn (Button)   # 退出按钮
└── Version (Label)  # 版本号(底部)

​操作步骤​​:

  1. 在根节点(默认Node2D)下添加MainMenuControl类型),命名为MainMenu
  2. 调整MainMenu的锚点(anchor_leftanchor_rightanchor_topanchor_bottom)为0,1,0,1(占满整个屏幕);
  3. 添加TitleLabel)作为子节点,设置文本为“我的游戏”,字体大小48,锚点center_x=0.5, top=0.1(水平居中,顶部距离屏幕10%);
  4. 添加ButtonContainerVBoxContainer,垂直布局容器),锚点center_x=0.5, center_y=0.5(水平居中,垂直居中);
  5. ButtonContainer中添加三个Button节点(StartBtnSettingsBtnExitBtn),设置文本分别为“开始游戏”“设置”“退出”,调整custom_minimum_size200x60(最小尺寸);
  6. 添加VersionLabel),文本为“v1.0.0”,锚点center_x=0.5, bottom=0.1(水平居中,底部距离屏幕10%)。

三、基础菜单功能:按钮交互与事件

Control节点的核心优势是​​内置事件系统​​。我们可以通过_on_Button_pressed()等回调函数,快速实现按钮点击逻辑。

1. 编写菜单脚本

MainMenu节点添加脚本(main_menu.gd):

extends Control

# 按钮点击事件(自动绑定同名信号)
func _on_StartBtn_pressed():
    print("开始游戏!")
    # 这里可以跳转到游戏场景:get_tree().change_scene("res://game.tscn")

func _on_SettingsBtn_pressed():
    print("打开设置!")
    # 打开设置弹窗(后续扩展)

func _on_ExitBtn_pressed():
    print("退出游戏!")
    get_tree().quit()  # 退出游戏

2. 绑定按钮信号

在Godot编辑器中:

  1. 选中StartBtn,点击右侧“节点”面板的“信号”按钮;
  2. 搜索pressed信号(按钮按下时触发),点击“连接”;
  3. 选择目标节点为MainMenu,方法名为_on_StartBtn_pressed
  4. 重复步骤为SettingsBtnExitBtn绑定对应事件。

​新手提示​​:Godot支持自动重命名信号处理函数(如按钮命名为StartBtn,自动生成_on_StartBtn_pressed函数),无需手动输入。


四、鸿蒙折叠屏适配:动态调整布局

鸿蒙折叠屏的核心特性是​​屏幕形态可变​​(折叠时为小屏,展开时为大屏)。为了让菜单在不同形态下都能良好显示,需要实现​​响应式布局​​。

1. 检测屏幕形态

通过get_viewport_rect()获取当前可用屏幕区域(排除系统导航栏等),判断是否为折叠状态:

# 在MainMenu.gd中添加以下代码
var is_folded = false  # 折叠状态标志

func _ready():
    # 初始检测屏幕尺寸(假设折叠屏展开宽度≥1200vp,折叠宽度≤800vp)
    check_screen_size()
    # 监听窗口尺寸变化(折叠屏切换时触发)
    get_window().connect("size_changed", self, "_on_window_size_changed")

func check_screen_size():
    var screen_size = get_viewport_rect().size  # 获取当前可用屏幕尺寸(Vector2)
    is_folded = screen_size.x < 1200  # 假设宽度<1200为折叠状态
    adjust_layout(is_folded)

func _on_window_size_changed(new_size):
    # 窗口尺寸变化时重新检测
    check_screen_size()

2. 动态调整布局

根据折叠状态,调整菜单的间距、字体大小和按钮尺寸:

func adjust_layout(is_folded: bool):
    # 调整标题字体大小
    var title = $Title
    title.font_size = 36 if is_folded else 48
    
    # 调整按钮容器间距
    var button_container = $ButtonContainer
    button_container.spacing = 20 if is_folded else 30  # 折叠时按钮间距更小
    
    # 调整按钮最小尺寸
    for btn in button_container.get_children():
        if btn is Button:
            btn.custom_minimum_size = Vector2(150, 50) if is_folded else Vector2(200, 60)
    
    # 调整版本号字体大小
    var version = $Version
    version.font_size = 24 if is_folded else 32

3. 锚点与百分比布局(进阶)

为了进一步适配不同屏幕比例,可使用@export声明变量,结合百分比设置位置:

@export var title_top_margin: float = 0.1  # 标题顶部边距(屏幕高度的10%)
@export var button_width_percent: float = 0.4  # 按钮宽度占屏幕的40%

func _ready():
    # 使用百分比设置标题位置
    $Title.position.y = -get_viewport_rect().size.y * title_top_margin
    # 使用百分比设置按钮宽度
    for btn in $ButtonContainer.get_children():
        if btn is Button:
            btn.custom_minimum_size.x = get_viewport_rect().size.x * button_width_percent

五、常见问题与解决方案

问题1:折叠屏切换时,菜单元素错位

​解决方案​​:

  • 确保所有Control节点的锚点设置为百分比(如anchor_left=0.5表示水平居中);
  • 使用get_viewport_rect().size动态计算位置,而非固定数值;
  • _ready()size_changed信号中调用布局调整函数。

问题2:按钮点击区域过小(折叠屏上难以点击)

​解决方案​​:

  • 增大按钮的custom_minimum_size(最小尺寸);
  • 启用按钮的“扩大点击区域”属性(在编辑器中勾选Buttonexpand_click_area);
  • 为按钮添加Area2D子节点,扩大碰撞检测范围:
    # 在Button节点下添加Area2D(命名为ButtonArea)
    # 设置Area2D的size比按钮大20vp
    func _ready():
        var area = $ButtonArea
        area.size = Vector2(240, 80)  # 比按钮大40vp(20vp*2)

问题3:鸿蒙设备字体显示异常

​解决方案​​:

  • 使用鸿蒙系统默认字体(避免自定义字体兼容性问题);
  • Project Settings > General > Text Editor中设置Font Antialiasing2x(提升小字体清晰度);
  • LabelButton启用clip_text属性(超出部分裁剪,避免文字溢出)。

总结:从基础到适配的UI开发流程

本文通过“创建菜单场景→绑定按钮事件→适配折叠屏”三个步骤,带你掌握了用Control节点制作游戏菜单的核心技能。关键是要理解:

  • Control节点的布局系统(锚点、容器)是UI自适应的基础;
  • 鸿蒙折叠屏适配的核心是​​动态检测屏幕尺寸​​并​​调整布局参数​​;
  • 新手应多利用Godot的可视化编辑器(拖拽调整节点)和信号系统(简化事件处理)。
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐