00. 从零开始的 SUS 集成
目标: 在不查阅其他文档的情况下,把一个空的 Unity 项目搭建到第一个
.sharq屏幕。
关键:SusApp + 生成的文件
Sharq.Core.SusApp 是文档化的应用程序入口点。 优先使用它,而不是只调用 styleSheets.Add / Mount 的手写 Start()。它会应用 TSS、令牌级联、主题, 确保存在 OverlayHost(屏幕根节点的最后一个 child),并创建 SusWorldSpacePanel,使 world UI(BindToWorld、health bar)有一个已知的挂载目标。
bootstrap 之后各部分的位置
SusApp 是一个 fluent bootstrap,不是带有三个子槽位的 VisualElement。实际的树结构如下:
Camera
└── __SusWorldSpacePanel__ (SusWorldSpacePanel + UIDocument) ← UNDER all screen UI
└── healthbars / nameplates / floating damage
(WorldSpaceService.Default → BindToWorld)
Screen UIDocument ← SusApp.Create(uiDocument) targets this root
└── rootVisualElement
├── screen content (Mount<T> or SusRouteView) ← screens
└── OverlayHost ← last child: modals, tooltips,
dropdowns, toasts, consoleWorld-space 没有接入 OverlayHost。在 Mount / Run 之后,使用:
WorldSpaceService.BindToWorld(healthBar, unit.transform, offset: new Vector3(0, 2f, 0));
// or: app.WorldPanel / WorldSpaceService.Default.WorldSpacePanel退出方式:对纯 2D 应用使用 .UseWorldSpace(false)。详情见 07-overlayhost。
先有鸡还是先有蛋:让生成的 .g.cs 保持同步
Sharq 源文件(.sharq)不是 C#。编译器会把 partial 类写入 GeneratedDirectory(例如 Assets/SusUI/Generated/*.g.cs)。你的入口 (MyApp / Setup 向导 starter)通常会调用 Mount<HomeScreen>()——而这个类型 只有在生成之后才存在。
Setup Project 会从 sus-core git 复制预先烘焙好的 starter(Editor/Setup/Starter~/):
| 复制的文件 | 作用 |
|---|---|
HomeScreen.sharq | 源 SFC |
Generated/HomeScreen.g.cs | 已经生成——项目立即可编译 |
{AppName}.cs | 调用 Sharq.Core.SusApp.Create(...).Mount<HomeScreen>() |
默认 starter 不需要先执行一次 RegenerateAll——向导会复制已提交的 .g.cs,因此项目在文件落地的瞬间即可编译。只有当你同时启用了自定义脚手架 和下游组件包(AppButton.sharq)、而该组件需要生成时,才会运行 RegenerateAll。 维护者通过 Tools~/refresh-starter-generated.ps1 或 Window → SUS → Setup → Refresh Starter Generated 刷新已提交的 starter .g.cs, 然后在 sus-core 中提交。
| 不良状态 | 后果 |
|---|---|
.sharq 存在,Generated/ 缺失或为空 | 项目无法编译 → Unity AssetPostprocessor / Sharq 可能不会运行 → 编译器无法自我修复 |
| Starter 引用了从未生成过的屏幕 | CS0246 / domain 卡在损坏状态 |
为了"清理"而删除 Generated/ 却不重新生成 | 同样的先有鸡还是先有蛋问题 |
如何避免损坏:
- 运行一次
Window → SUS → Setup Project——复制配置、SusApp starter、HomeScreen.sharq+ 预先生成的HomeScreen.g.cs。这是推荐路径(见步骤 2)。 - 或者,对于手工搭建的屏幕:创建
sus.config.json+.sharq,然后保存该.sharq(或运行Window → SUS → Sharq → Regenerate All Prototype Components),使.g.cs在引用这些类型的代码之前(或同时)出现。 - 在 Unity 之外(CI / 消费方应用的全新克隆):CLI
sus-core/Tools~/SharqBootstrap可以在无需编译好的 Editor 的情况下生成.g.cs。 - 不要手动编辑
*.g.cs/*.g.uss——编辑.sharq并重新生成。 - 消费方项目的
Generated/通常在 gitignore 中;带可选组件库的包仓库和 core 的 Starter~ 会随附已生成的源码,使 UPM / Setup 开箱即用。
Window → SUS → Validate Setup 会在 .sharq 存在而 Generated/ 不存在时发出警告。
步骤 1. 安装包
添加到 Packages/manifest.json:
{
"dependencies": {
"com.sharq-it.sus.core": "https://github.com/antaresdk/sus-core.git#v1.0.29"
}
}当编辑器获得焦点时,Unity 会自动拉取该包。它会在 Package Manager 中显示为 "SusCore"。
本地开发时可以在项目旁边使用
"file:../sus-core"。生产环境——使用 git URL 或 npm registry。
步骤 2. 推荐路径 —— Setup Project
Window → SUS → Setup Project 一键完成以下所有工作:
- 检查环境(Unity 版本、UI Toolkit、包),
- 写入
sus.config.json, - 创建带有
UIDocument+PanelSettings的场景, - 复制预先烘焙好的 starter(
HomeScreen.sharq+Generated/HomeScreen.g.cs+{AppName}.cs), - 可选地搭建
Customization/文件夹脚手架。
由于 starter 自带已生成的 .g.cs,项目会立即编译—— 不需要第一次生成步骤。向导完成、Unity 重新编译之后,直接跳到 步骤 7(Play)。
优先选择这条路径。下面的步骤 3–6 描述的是不使用向导、手工搭建屏幕的手动流程—— 有助于理解整个流水线,或用于手动添加屏幕。
步骤 3. 第一个 .sharq 组件(手动)
创建 Assets/SusUI/HelloScreen.sharq:
<template>
<ui:VisualElement $MainElement style="flex-grow: 1; align-items: center; justify-content: center;">
<ui:Label text="Hello SUS!" style="font-size: 28px; color: white; -unity-text-align: middle-center;" />
</ui:VisualElement>
</template>
<script>
$using Sharq.Core;
</script>在
<script>中使用$using(Sharq 指令),而不是普通的using。Sharq.Core会 自动导入,所以空的<script>(或完全没有)同样可以工作——上面的$using只是一个示例。
步骤 4. sus.config.json
创建 Assets/sus.config.json:
{
"SharqDirectory": "Assets/SusUI",
"GeneratedDirectory": "Assets/SusUI/Generated",
"ResourcesDirectory": "Assets/SusUI/Generated/Resources/SusRuntime",
"LogGeneratedFiles": true
}| 字段 | 说明 |
|---|---|
SharqDirectory | 你的 .sharq 文件所在位置 |
GeneratedDirectory | .g.cs 和 .g.uss 的写入位置 |
ResourcesDirectory | .uss 的 Resources/ 镜像写入位置 |
LogGeneratedFiles | true(默认)——记录每个生成的文件;设为 false 可关闭 |
如果没有该文件,Sharq 编译器会使用默认路径(
Assets/SusUI)。
步骤 5. 生成 Sharq(手动路径)
保存 .sharq 后,Sharq 编译器会自动生成:
Assets/SusUI/Generated/HelloScreen.g.cs—— C# partial 类Assets/SusUI/Generated/HelloScreen_static.g.uss—— 从 inlinestyle="…"提取出的 USS (全局的HelloScreen.g.uss/ 作用域内的HelloScreen_scoped.g.uss仅在组件带有<style>块时才会出现)
顺序很重要: 在依赖 Mount<HelloScreen>() 的入口代码编译之前,先生成(或等待导入完成)。 如果 domain 已经损坏,使用 Setup Project / Regenerate All Prototype Components / CLI bootstrap ——见上文的关键部分。
检查 Unity 控制台:Window → SUS → Validate Setup——诊断会告诉你一切是否正常。
步骤 6. 入口点 —— SusApp(手动路径)
创建 MyApp.cs,并将其挂到带有 UIDocument 的 GameObject 上:
using Sharq.Core;
using UnityEngine;
using UnityEngine.UIElements;
[RequireComponent(typeof(UIDocument))]
public class MyApp : MonoBehaviour
{
// OnEnable mirrors the Setup Project starter; Start() also works.
private void OnEnable()
{
// Prefer Sharq.Core.SusApp — avoids clash with a legacy global SusApp type.
Sharq.Core.SusApp.Create(GetComponent<UIDocument>())
.UseTheme(SusTheme.Dark)
.Mount<HelloScreen>();
}
}SusApp.Create(UIDocument),然后 Mount / Run——完整的 Finalize 顺序:
- Create —— 把
SusDefault.tss应用到 PanelSettings(面板级别的_palette+_font+_global) - Icons —— 注册
UseIcons提供者(最高优先级) - Token cascade ——
_palette→_font→_theme→design-tokens→_icon→ L4/L5 附加项 +OverlayHost(最后一个 child) - World ——
EnsureWorldSpacePanel+WorldSpaceService.Default(除非设置了UseWorldSpace(false)) - Fonts —— 在 root + OverlayHost 上执行
UseFonts - Custom styles —— 在 root + OverlayHost 上执行
UseCustomStyles(最上层的 override 层) - Configure —— 回调(router 注册、手动 UI)
- Mount —— 根组件(如果调用了
Mount<T>) - Theme last ——
SusThemeService.Instance.SetTheme(root, theme),使 OverlayHost 继承主题相关的类
这是启动 SUS 应用的受支持方式。优先使用 Setup Project,让 starter + 第一份 .g.cs 一起创建。
步骤 7. Play
点击 Play → 深色背景上出现白色文字 "Hello SUS!"。
备用 bootstrap —— SusBootstrap.Mount<T>()
如果 SusApp 不合适(例如没有主题的手动 UI):
void Start()
{
// Apply the default TSS + create OverlayHost.
// NOTE: Mount<T> does NOT call ApplyDefaultTSS for you — do it explicitly here.
SusBootstrap.ApplyDefaultTSS(_uiDocument);
var root = _uiDocument.rootVisualElement;
// Load the token cascade manually (_palette → _font → _theme → design-tokens → _icon).
SusBootstrap.LoadTokenCascade(root);
// Mount the component
SusBootstrap.Mount<HelloScreen>(root);
}你仍然需要为 HelloScreen 生成好的 .g.cs。跳过 SusApp 并不会取消 先有鸡还是先有蛋的规则。这条路径应用了级联,但不会应用主题—— 如果需要,请自行调用 SusThemeService.Instance.SetTheme(root, SusTheme.Dark)。
连接 sus-router
来自公共 GitHub 的 open-core(免费)包:
{
"dependencies": {
"com.sharq-it.sus.core": "https://github.com/antaresdk/sus-core.git#v1.0.29",
"com.sharq-it.sus.router": "https://github.com/antaresdk/sus-router.git#v1.0.16"
}
}可选的 UI 组件库是独立的产品——见 https://sus-ui.dev。
搭配 router(using Sharq.Router;)。请注册每个你会导航到的屏幕——示例中 使用了 HomeScreen 和 SettingsScreen,因此两者都必须有 .sharq 源文件(以及生成的 .g.cs):
SusApp.Create(_uiDocument)
.UseTheme(SusTheme.Dark)
.UseRouter(
new SusRouter(),
r =>
{
r.Register("/", typeof(HomeScreen));
r.Register("/settings", typeof(SettingsScreen));
},
initialPath: "/")
.Run();Setup 向导与 Customization/ 文件夹
上面的一切都可以通过一个按钮获得:Window → SUS → Setup Project——向导 检查环境,写入 sus.config.json,创建带有 UIDocument + PanelSettings 的场景, 并复制预先烘焙好的 starter(HomeScreen.sharq + 已生成的 HomeScreen.g.cs + {AppName}.cs)。默认 starter 不会触发首次生成,因此它开箱即可编译 (解决了先有鸡还是先有蛋的问题)。
启用 Create customization scaffold 选项(默认启用)后,向导还会创建 {UI-root}/Customization/——为项目定制预留的位置,每个维度都带有一个可运行的 示例;一切都已经通过 starter 中的一行 Use* 连接好了:
| 维度 | 文件 | starter 中对应的行 |
|---|---|---|
| 颜色/尺寸(令牌) | Customization/Theme/Resources/branding.uss | .UseCustomStyles("branding") |
| 字体 | Customization/Fonts/AppFonts.asset | .UseFonts(_fonts) |
| 图标 | Customization/Icons/Resources/SusRuntime/Icons/app/… | .UseIcons(new ResourcesFolderIconProvider(<yourPackageOrCollection>, "app")) |
| 你的组件 | Customization/Components/AppButton.sharq(可选的下游包) | HomeScreen.sharq 中的 <sus:AppButton> |
图标——第一个参数的注意事项。
ResourcesFolderIconProvider(editorPackagePath, collection)会将编辑器扫描指向Packages/{editorPackagePath}/Runtime/Resources/SusRuntime/Icons/{collection}(回退到Assets/Resources/SusRuntime/Icons/{collection})。对于随附自己包的 消费方应用,请传入你自己的包 id(例如"com.my.game");对于位于Assets/.../Resources下的图标,请传入一个不存在的路径对应的 id,以便触发Assets/Resources的回退。不要原样照抄"com.sharq-it.sus.core"——那会把扫描 指向 core 包,而不是你的图标。见 Design tokens §4。
"我想改 X → 编辑文件 Y" 的对照卡片——在生成的 Customization/README.md 中。 再次运行向导不会抹掉已编辑的文件(只会创建缺失的文件)。
诊断
Window → SUS → Validate Setup 检查:
- Unity 版本(≥6000.0)
- UI Toolkit
sus.config.json及其路径.sharq和.g.cs是否存在PanelSettings- 包的可用性
编辑器设置 — .sharq 语法高亮
.sharq 本身不是 C# / XML / CSS。没有编辑器扩展时,文件看起来像 纯文本。SusCore 在包内提供 VS Code / Cursor 扩展: Tools~/vscode-sharq/(Unity 不会把 Tools~ 当作资源导入)。
高亮内容:
| 区块 | 语言 | Sharq 扩展 |
|---|---|---|
<template> | XML | v-if / v-else / v-for / v-show, :prop, @event, $MainElement |
<script> | C# | $using Namespace; |
<style> | CSS | USS -unity-*, design tokens --sus-* |
安装到 VS Code 或 Cursor
A. 复制文件夹(无需 Node / Marketplace):
- 在磁盘上找到包 — Package Manager → SusCore → path,或
sus-core的 git checkout。 打开Tools~/vscode-sharq/。 - 将该文件夹复制到:
- Windows VS Code:
%USERPROFILE%\.vscode\extensions\sharq-it.sharq-language-0.1.0 - macOS / Linux VS Code:
~/.vscode/extensions/sharq-it.sharq-language-0.1.0 - Cursor:
%USERPROFILE%\.cursor\extensions\sharq-it.sharq-language-0.1.0(或~/.cursor/extensions/…)
- Windows VS Code:
- 重启编辑器并打开
.sharq— 状态栏语言应显示 Sharq。
B. 从 VSIX 安装:
同一文件夹包含 sharq-language-0.1.0.vsix。在编辑器中: Extensions → … → Install from VSIX… → 选择该文件 → reload。
之后若要重新打包 VSIX:
npm i -g @vscode/vsce
cd <path-to-sus-core>/Tools~/vscode-sharq
vsce package --allow-missing-repository安装后可打开的起步示例: Editor/Setup/Starter~/HomeScreen.sharq(Setup Project 也会复制进你的项目)。
Rider / JetBrains
尚无一等公民的 JetBrains 插件。将 Rider 的 TextMate / TextMate Bundles 指向 Tools~/vscode-sharq/syntaxes/sharq.tmLanguage.json(与 VS Code 相同的 scopes)。这是 受支持的过渡路径。
Marketplace(可选)
publisher sharq-it 下的 VS Code Marketplace 上架是可选的,且独立于本包交付。 上面的本地复制 / VSIX 已足够日常编辑。
延伸阅读
- Quick start —— 更多关于
.sharq、组合、props 的内容 - OverlayHost —— 屏幕 overlay 层 vs world-space
- Design tokens —— 主题化:颜色、字体、图标
- 主题扩展说明 —— 包仓库中的
Documentation~/theme-extension.md