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)
相关推荐
真鬼1231 小时前
【Unity AI】Untiy链接cursor与MCP
unity·游戏引擎
郝学胜-神的一滴4 小时前
C++11 工程级应用 10:减少拷贝,让容器跑得更快
服务器·开发语言·c++·游戏引擎·opengl
玖玥拾4 小时前
Lua 基础语法(八) Unity Huatuo (HybridCLR)
开发语言·unity·游戏引擎·lua
狂人开飞机5 小时前
10、相机系统
游戏引擎·godot
不吃凉粉1 天前
Unity与AS通信
unity·游戏引擎
两水先木示2 天前
【Unity】探索小地图迷雾散开Shader效果(基础版)
unity·游戏引擎
WarrenMondeville2 天前
AI复刻街头霸王到 Unity
unity·游戏引擎
烛阴3 天前
Godot 4 入门(03):用第一份 GDScript 驱动节点
godot
xcLeigh3 天前
Unity基础:MonoBehaviour的生命周期——Awake、OnEnable、Start、Update执行顺序
unity·游戏引擎