跳转到内容

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, console

World-space 没有接入 OverlayHost。在 Mount / Run 之后,使用:

csharp
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 复制预先烘焙好的 starterEditor/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.ps1Window → SUS → Setup → Refresh Starter Generated 刷新已提交的 starter .g.cs, 然后在 sus-core 中提交。

不良状态后果
.sharq 存在,Generated/ 缺失或为空项目无法编译 → Unity AssetPostprocessor / Sharq 可能不会运行 → 编译器无法自我修复
Starter 引用了从未生成过的屏幕CS0246 / domain 卡在损坏状态
为了"清理"而删除 Generated/ 却不重新生成同样的先有鸡还是先有蛋问题

如何避免损坏:

  1. 运行一次 Window → SUS → Setup Project——复制配置、SusApp starter、HomeScreen.sharq + 预先生成的 HomeScreen.g.cs。这是推荐路径(见步骤 2)。
  2. 或者,对于手工搭建的屏幕:创建 sus.config.json + .sharq,然后保存该 .sharq(或运行 Window → SUS → Sharq → Regenerate All Prototype Components),使 .g.cs 在引用这些类型的代码之前(或同时)出现。
  3. 在 Unity 之外(CI / 消费方应用的全新克隆):CLI sus-core/Tools~/SharqBootstrap 可以在无需编译好的 Editor 的情况下生成 .g.cs
  4. 不要手动编辑 *.g.cs / *.g.uss——编辑 .sharq 并重新生成。
  5. 消费方项目的 Generated/ 通常在 gitignore 中;带可选组件库的包仓库core 的 Starter~ 会随附已生成的源码,使 UPM / Setup 开箱即用。

Window → SUS → Validate Setup 会在 .sharq 存在而 Generated/ 不存在时发出警告。


步骤 1. 安装包

添加到 Packages/manifest.json

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 的场景,
  • 复制预先烘焙好的 starterHomeScreen.sharq + Generated/HomeScreen.g.cs + {AppName}.cs),
  • 可选地搭建 Customization/ 文件夹脚手架。

由于 starter 自带已生成的 .g.cs,项目会立即编译—— 不需要第一次生成步骤。向导完成、Unity 重新编译之后,直接跳到 步骤 7(Play)

优先选择这条路径。下面的步骤 3–6 描述的是不使用向导、手工搭建屏幕的手动流程—— 有助于理解整个流水线,或用于手动添加屏幕。


步骤 3. 第一个 .sharq 组件(手动)

创建 Assets/SusUI/HelloScreen.sharq

xml
<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 指令),而不是普通的 usingSharq.Core 会 自动导入,所以空的 <script>(或完全没有)同样可以工作——上面的 $using 只是一个示例。


步骤 4. sus.config.json

创建 Assets/sus.config.json

json
{
  "SharqDirectory": "Assets/SusUI",
  "GeneratedDirectory": "Assets/SusUI/Generated",
  "ResourcesDirectory": "Assets/SusUI/Generated/Resources/SusRuntime",
  "LogGeneratedFiles": true
}
字段说明
SharqDirectory你的 .sharq 文件所在位置
GeneratedDirectory.g.cs.g.uss 的写入位置
ResourcesDirectory.ussResources/ 镜像写入位置
LogGeneratedFilestrue(默认)——记录每个生成的文件;设为 false 可关闭

如果没有该文件,Sharq 编译器会使用默认路径(Assets/SusUI)。


步骤 5. 生成 Sharq(手动路径)

保存 .sharq 后,Sharq 编译器会自动生成:

  • Assets/SusUI/Generated/HelloScreen.g.cs —— C# partial 类
  • Assets/SusUI/Generated/HelloScreen_static.g.uss —— 从 inline style="…" 提取出的 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 上:

csharp
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 顺序:

  1. Create —— 把 SusDefault.tss 应用到 PanelSettings(面板级别的 _palette + _font + _global
  2. Icons —— 注册 UseIcons 提供者(最高优先级)
  3. Token cascade —— _palette_font_themedesign-tokens_icon → L4/L5 附加项 + OverlayHost(最后一个 child)
  4. World —— EnsureWorldSpacePanel + WorldSpaceService.Default(除非设置了 UseWorldSpace(false)
  5. Fonts —— 在 root + OverlayHost 上执行 UseFonts
  6. Custom styles —— 在 root + OverlayHost 上执行 UseCustomStyles(最上层的 override 层)
  7. Configure —— 回调(router 注册、手动 UI)
  8. Mount —— 根组件(如果调用了 Mount<T>
  9. 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):

csharp
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(免费)包:

json
{
  "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;)。请注册每个你会导航到的屏幕——示例中 使用了 HomeScreenSettingsScreen,因此两者都必须有 .sharq 源文件(以及生成的 .g.cs):

csharp
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 的场景, 并复制预先烘焙好的 starterHomeScreen.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>XMLv-if / v-else / v-for / v-show, :prop, @event, $MainElement
<script>C#$using Namespace;
<style>CSSUSS -unity-*, design tokens --sus-*

安装到 VS Code 或 Cursor

A. 复制文件夹(无需 Node / Marketplace):

  1. 在磁盘上找到包 — Package Manager → SusCore → path,或 sus-core 的 git checkout。 打开 Tools~/vscode-sharq/
  2. 将该文件夹复制到:
    • 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/…
  3. 重启编辑器并打开 .sharq — 状态栏语言应显示 Sharq

B. 从 VSIX 安装:

同一文件夹包含 sharq-language-0.1.0.vsix。在编辑器中: Extensions → … → Install from VSIX… → 选择该文件 → reload。

之后若要重新打包 VSIX:

bash
npm i -g @vscode/vsce
cd <path-to-sus-core>/Tools~/vscode-sharq
vsce package --allow-missing-repository

安装后可打开的起步示例: Editor/Setup/Starter~/HomeScreen.sharqSetup 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