游戏 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;。
把文档放到屏幕上
- 创建
Assets/UI/menu.ui和Assets/UI/theme.uss(见下文)。 - 添加一个节点,然后 Add Component → UI → UI Document。
- 把
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 的行和列。