> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/all-out-docs/docs-zh/ui/fundamentals.md).

# UI 基础

***

为你的游戏添加 UI 需要编写代码，但一旦你学会了几种模式，就能快速构建简洁、可扩展的界面。本指南将带你完成一个逐步教程，最终得到一个完整的对话框示例。

{% hint style="info" %}
玩家的所有 UI 都必须绘制在该玩家的 `ao_late_update` 调用栈中，并用 `is_local_or_server()`包裹起来。这可以防止 UI 出现在错误的客户端上。不要从全局或非玩家组件回调中绘制玩家 UI。
{% endhint %}

你可以随时跳转到 [UI 参考](/all-out-docs/docs-zh/ui/ui-reference.md) 查看更多模式和更深入的细节。

### 步骤 1：创建一个 UI 入口点

所有交互式 UI 都应该从本地玩家的 `ao_late_update`:

```go
Player :: class : Player_Base {
    ao_late_update :: method(dt: float) {
        if this.is_local_or_server() {
            draw_ui(this);
        }
    }
}
```

### 步骤 2：从屏幕矩形开始

屏幕 UI 应始终基于 `UI.get_safe_screen_rect()` 或 `UI.get_screen_rect()`。请记住：（0，0）在左下角，Y 轴向上增长。

传递给常规矩形辅助函数的屏幕空间尺寸是 **点** 基于一块高度为 1080 点的参考画布。引擎会将这些点缩放为设备的实际像素，因此相同的布局在不同分辨率下仍能保持一致的相对大小。

```go
draw_ui :: proc(player: Player) {
    screen := UI.get_safe_screen_rect();

    // 一个简单的居中面板
    panel := screen.center_rect().grow(120, 200, 120, 200);
    UI.quad(panel, core_globals.white_sprite, {0, 0, 0, 0.7});
}
```

### 步骤 3：使用 Cut 进行布局

在进行多个元素布局时，应从矩形中切出空间，而不是从同一个原点来定位所有元素。

```go
draw_panel_layout :: proc() {
    panel := UI.get_safe_screen_rect().center_rect().grow(140, 220, 140, 220);

    header := panel.cut_top(80);
    footer := panel.cut_bottom(70);
    body := panel;

    UI.quad(header, core_globals.white_sprite, {0.1, 0.1, 0.1, 0.8});
    UI.quad(body, core_globals.white_sprite, {0.05, 0.05, 0.05, 0.8});
    UI.quad(footer, core_globals.white_sprite, {0.1, 0.1, 0.1, 0.8});
}
```

### 步骤 4：添加文本

使用文本设置来控制大小、颜色和对齐方式。

```go
draw_header_text :: proc(rect: Rect) {
    ts := UI.default_text_settings();
    ts.size = 52;
    ts.color = {1, 1, 1, 1};
    ts.halign = .CENTER;
    ts.valign = .CENTER;

    UI.text(rect, ts, "新任务！");
}
```

### 步骤 5：添加按钮

按钮将布局和交互结合在一起。请使用引擎提供资源中的按钮精灵（参见 [UI 参考](/all-out-docs/docs-zh/ui/ui-reference.md) 了解更多）。

```go
draw_button :: proc(rect: Rect) {
    bs := UI.default_button_settings();
    ts := UI.default_text_settings();

    bs.sprite = get_asset(Texture_Asset, "$AO/new/modal/buttons_2/button_2.png");
    bs.press_scaling = 0.35;

    if UI.button(rect, bs, ts, "接受").clicked {
        log_info("已接受！");
    }
}
```

### 步骤 6：构建一个对话框

现在把所有步骤组合成一个可复用的对话框布局。

```go
draw_dialog :: proc(title: string, body: string) {
    screen := UI.get_safe_screen_rect();
    dialog := screen.center_rect().grow(200, 300, 200, 300);

    UI.quad(dialog, core_globals.white_sprite, {0, 0, 0, 0.85});

    content := dialog.inset(30);
    header := content.cut_top(80);
    buttons := content.cut_bottom(90);
    body_rect := content;

    ts := UI.default_text_settings();
    ts.halign = .CENTER;
    ts.valign = .CENTER;

    ts.size = 52;
    UI.text(header, ts, title);

    ts.size = 36;
    UI.text(body_rect, ts, body);

    bs := UI.default_button_settings();
    bs.sprite = get_asset(Texture_Asset, "$AO/new/modal/buttons_2/button_2.png");
    bs.press_scaling = 0.35;

    left := buttons.cut_left(210);
    buttons.cut_left(20);
    right := buttons.cut_left(210);

    if UI.button(left, bs, ts, "取消").clicked {
        log_info("已取消");
    }
    if UI.button(right, bs, ts, "确认").clicked {
        log_info("已确认");
    }
}
```
