游戏 UI

本页面为自动翻译,可能包含错误。如果发现问题,请通过“编辑此页面”链接帮助修正。

在 Play Mode 中运行的 .ui 文档

Turian 中的游戏 UI 像 Web 或 Unity 的 UI Toolkit 一样编写:.ui XML 文档描述元素,.uss 样式表描述外观,C# 的 UiController 或数据绑定让它们动起来。它由 Guinevere 绘制,这也是绘制 Turian Studio 的同一个工具包。

游戏 UI 是内置的 brick org.mass4.turian.ui。新项目已包含它;没有它的游戏不会附带任何 UI 栈。要在旧项目中使用它,请在 Packages/manifest.json 中添加 "org.mass4.turian.ui": "builtin:org.mass4.turian.ui",并在使用 UI 类型的脚本中添加 using Turian.Engine.UI;。

把文档放到屏幕上

  1. 创建 Assets/UI/menu.ui 和 Assets/UI/theme.uss(见下文)。
  2. 添加一个节点,然后 Add Component → UI → UI Document。
  3. 把 menu.ui 拖到它的 Document 字段上。
属性 含义
Document 要渲染的 .ui 文档。
StyleSheets 在文档自带样式表之上额外应用的 .uss。
Mode ScreenSpaceOverlay(绘制在场景之上)或 WorldSpace(绘制在场景中的四边形上)。
SortOrder 屏幕空间文档之间的绘制顺序。
ScaleMode、ReferenceResolution 固定像素大小,或从设计分辨率出发随屏幕缩放。
PanelSize 世界空间面板的像素大小。

世界空间文档会在 Studio 的视图和 CLI 渲染中显示;导出的游戏尚不绘制它们。添加 UI Raycaster 组件可使其可点击。

文档

<?xml version="1.0" encoding="utf-8"?>
<UI xmlns="https://turian.dev/ui" controller="Usercode.MainMenu">
  <Style src="Assets/UI/theme.uss" />

  <VisualElement name="root" class="screen">
    <Label class="title" text="{Title}" />
    <Button name="play" text="Play" click="OnPlay" />
    <Toggle name="music" label="Music" value="{Music, mode=TwoWay}" />
    <Button name="quit" text="Quit" click="OnQuit" />
  </VisualElement>
</UI>
  • 根元素始终是 <UI>;它包含 <Style> 样式表、可选的 <Template>,以及一个可视元素。
  • 常用属性:name(唯一 id)、class(样式类)、style(内联声明)、tooltip、enabled。
  • 叶子元素的内部文本会成为它的 text:<Label>主菜单</Label>。

元素

元素 说明
VisualElement 通用容器;用 flex-direction、gap、尺寸和对齐来布局。
Label 文本。
Button text;触发 click。
Image src、width、height。
ImageButton image-normal、image-hover、image-pressed、nine-slice="l,t,r,b";触发 click。
TextField value、placeholder;触发 value-changed。
Toggle value、label;触发 value-changed。
ScrollView 垂直滚动其子元素。
Tabs / Tab 每页一个 <Tab header="…">;触发 changed。

给有状态的控件(TextField、Toggle、Tabs)设置一个 name,以便在帧与帧之间保留其状态。

模板和列表

<Template name="StatRow">
  <VisualElement class="row">
    <Label text="{label}" />
    <Label binding-text="{path}" />
  </VisualElement>
</Template>

<Instance template="StatRow" label="Gold" path="Player.Gold" />

<ScrollView>
  <Repeat items="{Inventory}" as="item">
    <Label binding-text="{item.Name}" />
  </Repeat>
</ScrollView>

用 .uss 设置样式

--accent: #4a90e2;

.screen  { flex-direction: column; gap: 12; padding: 24; align-items: center; }
.title   { font-size: 32; color: #ffffff; text-shadow: #000000 2 2; }
Button   { width: 220; height: 44; border-radius: 8; background-color: #2a2f3a; }
Button:hover { background-color: var(--accent); }
#quit    { background-color: #6b2b2b; }
  • 选择器:Type、.class、#name、*、Button.primary 这样的复合选择器,以及分组 a, b。不支持后代和子代组合器。
  • 状态::hover、:active、:focus、:disabled。
  • 变量:在顶层声明 --name: value;,并用 var(--name) 使用。
  • 布局:flex-direction、flex-wrap、flex-grow、gap、width/height(像素或 %)、最小/最大尺寸、padding、margin、align-items、justify-content、align-self。
  • 盒子:background-color、border-color、border-width、border-radius。
  • 文本:color、font-size、font-family(项目中的 .ttf/.otf 或系统字体)、text-outline、text-shadow、text-inner-shadow、text-gradient。

Code-behind 和数据绑定

namespace Usercode;

public sealed class MainMenu : UiController
{
    public string Title => "My Game";
    public bool Music { get; set; } = true;

    public void OnPlay() => Log.Logger.LogInformation("按下了 Play");
    public void OnQuit() => Log.Logger.LogInformation("按下了 Quit");
}
  • 每个无参数的 public void 方法都是事件处理器,可在 click、value-changed、changed、submit、activated 或 selection-changed 中按名称引用。
  • 属性中的 {Path} 把它绑定到控制器(或单独的数据上下文)的某个属性,每帧重新读取——无需变更通知。binding-text="{…}" 是显式形式,也可以用 <Bindings> 块把它们分组。
  • 模式:OneWay(默认)、TwoWay(文本框和开关会写回)、OneTime。
  • 转换器:{Health | percent}——内置的有 not、percent、thousands、upper 和 lower;用 ValueConverters.Register("name", converter) 注册你自己的。
  • 重写 OnBind、OnUpdate(float deltaTime) 和 OnUnbind 来做初始化、每帧逻辑和清理。

本地化文本

Label 的文本会自动从项目的字符串表中查找;text-key 指定显式的键。参见本地化。

不运行游戏的预览

CLI 无需 GPU 即可把文档渲染为 PNG,并把 JSON 作为数据绑定:

turian-cli ui --file Assets/UI/menu.ui --out menu.png --data '{"Title":"Preview","Music":true}'

解析错误会报告出错 XML 的行和列。


← 所有文档 编辑此页面