11、UI系统

第11章 UI 系统

11.1 Control 节点基础

Control 是所有 UI 节点的基类。

锚点系统示意图

复制代码
父容器(如屏幕 1280x720)
┌─────────────────────────────────────┐
│(0,0)                          (1,0)│
│  左上角                      右上角 │
│                                     │
│          (0.5, 0.5)                 │
│              中心                    │
│                                     │
│  左下角                      右下角 │
│(0,1)                          (1,1)│
└─────────────────────────────────────┘

常见锚点配置:

  左上角固定     居中固定      全屏拉伸
  ┌────┐         ┌────┐      ┌────────────┐
  │按钮│         │    │      │            │
  └────┘         │按钮│      │    按钮     │
                 │    │      │            │
                 └────┘      └────────────┘
  (0,0,0,0)    (.5,.5,.5,.5)  (0,0,1,1)
gdscript 复制代码
# 锚点(Anchor):决定 Control 相对于父容器的定位参考点
# 范围:0.0 ~ 1.0
# (0, 0) = 左上角, (1, 1) = 右下角, (0.5, 0.5) = 中心

# 常见锚点预设
# 左上角:anchor_left=0, anchor_top=0, anchor_right=0, anchor_bottom=0
# 右下角:anchor_left=1, anchor_top=1, anchor_right=1, anchor_bottom=1
# 全屏拉伸:anchor_left=0, anchor_top=0, anchor_right=1, anchor_bottom=1
# 居中:anchor_left=0.5, anchor_top=0.5, anchor_right=0.5, anchor_bottom=0.5

# 代码设置锚点
func set_anchor_fullscreen() -> void:
    anchor_left = 0.0
    anchor_top = 0.0
    anchor_right = 1.0
    anchor_bottom = 1.0
    offset_left = 0
    offset_top = 0
    offset_right = 0
    offset_bottom = 0

11.2 常用控件

Label 文本

gdscript 复制代码
extends Label

func _ready() -> void:
    text = "Hello, Godot!"
    horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
    vertical_alignment = VERTICAL_ALIGNMENT_CENTER
    
    # 设置字体大小(通过 Theme)
    add_theme_font_size_override("font_size", 24)
    
    # 自动换行
    autowrap_mode = TextServer.AUTOWRAP_WORD_SMART

Button 按钮

gdscript 复制代码
extends Button

func _ready() -> void:
    text = "开始游戏"
    
    # 连接信号
    pressed.connect(_on_pressed)
    button_down.connect(_on_button_down)  # 按下
    button_up.connect(_on_button_up)      # 松开
    toggled.connect(_on_toggled)          # 切换模式

func _on_pressed() -> void:
    print("按钮被点击!")

# 切换模式
func _on_toggled(is_pressed: bool) -> void:
    toggle_mode = true  # 在检查器中启用
    print("切换状态:", is_pressed)

ProgressBar 进度条

gdscript 复制代码
extends ProgressBar

# ⚠️ Godot 4.x 中 ProgressBar 没有 show_percentage 属性
# 如需显示百分比文字,用子节点 Label 实现

func _ready() -> void:
    min_value = 0
    max_value = 100
    value = 100

func update_health(current: int, maximum: int) -> void:
    max_value = maximum
    value = current
    
    # 颜色变化
    var ratio := float(current) / maximum
    if ratio < 0.3:
        modulate = Color.RED
    elif ratio < 0.6:
        modulate = Color.YELLOW
    else:
        modulate = Color.GREEN

TextureRect 图片

gdscript 复制代码
extends TextureRect

func _ready() -> void:
    texture = preload("res://assets/ui/frame.png")
    stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
    expand_mode = TextureRect.EXPAND_IGNORE_SIZE

11.3 CanvasLayer(UI 层分离)

gdscript 复制代码
# CanvasLayer 让 UI 独立于游戏世界
# UI 不受相机移动影响

# 场景结构:
# Player (CharacterBody2D)
#   Sprite2D
#   CollisionShape2D
#   Camera2D
#   UILayer (CanvasLayer)  ← 这里的 UI 跟随玩家但不受相机影响
#     HealthBar (ProgressBar)
#     AmmoLabel (Label)

# 设置
# CanvasLayer → Layer: 10(更高的层显示在上面)
# CanvasLayer → Follow Viewport Enabled: false(不跟随相机)

11.4 布局容器

gdscript 复制代码
# VBoxContainer:垂直排列
# HBoxContainer:水平排列
# GridContainer:网格排列
# MarginContainer:边距
# CenterContainer:居中

# 代码控制容器子节点的对齐
extends VBoxContainer

func _ready() -> void:
    alignment = BoxContainer.ALIGNMENT_CENTER  # 居中对齐
    # 属性面板中的 Separation 控制间距

11.5 UI 动画(Tween)

gdscript 复制代码
# 血条平滑变化
extends ProgressBar

var target_value: float = 100.0

func set_health(new_health: float) -> void:
    target_value = new_health
    var tween := create_tween()
    tween.tween_property(self, "value", target_value, 0.3).set_ease(Tween.EASE_OUT)

# 数字滚动效果
func animate_score(new_score: int) -> void:
    var tween := create_tween()
    tween.tween_method(_update_score_display, current_score, new_score, 0.5)

func _update_score_display(value: int) -> void:
    $ScoreLabel.text = "分数:%d" % value

# UI 元素弹出动画
func popup_animation() -> void:
    scale = Vector2.ZERO
    var tween := create_tween()
    tween.tween_property(self, "scale", Vector2.ONE, 0.3) \
        .set_ease(Tween.EASE_OUT) \
        .set_trans(Tween.TRANS_ELASTIC)

11.6 主菜单与暂停菜单

gdscript 复制代码
# 暂停菜单
extends Control

func _ready() -> void:
    process_mode = Node.PROCESS_MODE_ALWAYS  # 暂停时也能处理输入
    visible = false

func _unhandled_input(event: InputEvent) -> void:
    if event.is_action_pressed("pause"):
        toggle_pause()

func toggle_pause() -> void:
    get_tree().paused = not get_tree().paused
    visible = get_tree().paused

func _on_resume_pressed() -> void:
    toggle_pause()

func _on_quit_pressed() -> void:
    get_tree().paused = false
    get_tree().change_scene_to_file("res://scenes/ui/main_menu.tscn")

11.7 UI 焦点系统(手柄/键盘导航)

gdscript 复制代码
# 设置焦点邻居(控制导航方向)
func setup_focus_navigation() -> void:
    $Button1.focus_neighbor_right = $Button2.get_path()
    $Button2.focus_neighbor_left = $Button1.get_path()
    $Button2.focus_neighbor_right = $Button3.get_path()
    $Button3.focus_neighbor_left = $Button2.get_path()
    
    # 设置初始焦点
    $Button1.grab_focus()

# focus_mode 设置
# FOCUS_NONE = 0      不能获取焦点
# FOCUS_CLICK = 1     只能通过点击获取
# FOCUS_ALL = 2       可以通过键盘/手柄获取

11.8 多分辨率适配

gdscript 复制代码
# 项目设置 → 窗口 → 拉伸
# Mode: canvas_items  # 推荐:缩放画布内容
# Aspect: keep        # 保持宽高比,可能有黑边
# Aspect: expand      # 扩展,显示更多内容

# 代码中获取实际显示信息
func _ready() -> void:
    var viewport_size := get_viewport().get_visible_rect().size
    var window_size := DisplayServer.window_get_size()
    var scale_factor := viewport_size.x / 1280.0  # 基于设计分辨率

11.9 Theme 主题

gdscript 复制代码
# 创建全局主题
var theme := Theme.new()

# 设置字体
var font := load("res://assets/fonts/main_font.tres")
theme.set_default_font(font)
theme.set_default_font_size(16)

# 设置按钮样式
var normal_style := StyleBoxFlat.new()
normal_style.bg_color = Color(0.2, 0.2, 0.3)
normal_style.corner_radius_top_left = 8
theme.set_stylebox("normal", "Button", normal_style)

var hover_style := StyleBoxFlat.new()
hover_style.bg_color = Color(0.3, 0.3, 0.5)
theme.set_stylebox("hover", "Button", hover_style)

# 应用主题
get_tree().root.theme = theme

实操练习

练习:完整 HUD

gdscript 复制代码
extends CanvasLayer

@onready var health_bar: ProgressBar = %HealthBar
@onready var score_label: Label = %ScoreLabel
@onready var combo_label: Label = %ComboLabel

func _ready() -> void:
    GameManager.score_changed.connect(_on_score_changed)
    GameManager.combo_changed.connect(_on_combo_changed)

func update_health(current: int, maximum: int) -> void:
    var tween := create_tween()
    tween.tween_property(health_bar, "value", float(current) / maximum * 100, 0.3)

func _on_score_changed(new_score: int) -> void:
    var tween := create_tween()
    tween.tween_method(
        func(v): score_label.text = "分数:%d" % v,
        int(score_label.text.replace("分数:", "")),
        new_score,
        0.5
    )

func _on_combo_changed(combo: int) -> void:
    combo_label.text = "%d 连击!" % combo
    combo_label.visible = combo > 1
    # 弹出动画
    combo_label.scale = Vector2(1.5, 1.5)
    var tween := create_tween()
    tween.tween_property(combo_label, "scale", Vector2.ONE, 0.2).set_trans(Tween.TRANS_ELASTIC)
相关推荐
郝学胜-神的一滴4 小时前
C++ Templates 01:拨开迷雾,读懂C++模板经典著作
开发语言·c++·程序人生·游戏·游戏引擎·软件构建
淡海水6 小时前
02-01-原理篇-Mark-Sweep与变种算法
算法·unity·c#·游戏引擎·.net·gc
babywang01 天前
Unity笔记--AssetBundle详解
unity·游戏引擎
魔士于安1 天前
经典Game
游戏·游戏引擎·贴图·技术美术·模型
淡海水1 天前
01-04-认知篇-Unity内存全景
unity·c#·游戏引擎·.net·gc
598866753@qq.com2 天前
Codex与Unity
unity·游戏引擎
淡海水2 天前
01-03-认知篇-C#内存模型深度解析
unity·c#·游戏引擎·.net·gc
警醒与鞭策2 天前
Direct3D 12 中的内存管理
3d·游戏引擎·direct3d
淡海水2 天前
16-02-C#常用数据结构源码-附录B-源码索引速查
unity·c#·游戏引擎·il2cpp
速易达网络2 天前
无人机远程操控仿真
游戏引擎·cocos2d