【免费下载链接】stride
Stride (formerly Xenko), a free and open-source cross-platform C# game engine.
Stride(原 Xenko)在仓库中把游戏模板、类型化起步器、功能演示样例与资源包统一封装为 NuGet 包,并接入 dotnet new 模板引擎,使 GameStudio 的"New Project"对话框与命令行 CLI 共用同一条模板流水线。本文以 sources/templates/README.md 为核心脉络,结合模板预处理器的源码实现,系统讲解终端用户如何用 dotnet new 创建游戏、开发者在仓库内如何打包与迭代模板、以及如何为 Stride 新增一个模板样例或资源包。
一、四个模板包:一份生态,两条消费入口
Stride 的 dotnet new 模板由四个 NuGet 包共同组成,每个包对应不同的模板类型与分发渠道:
| 包 | 包含模板 | 分发方式 |
|---|---|---|
Stride.Templates.Games | stride-game(空白新游戏起步器)、stride-library(共享代码库) | 随 GameStudio 安装包内置 |
Stride.Templates.Games.Starters | stride-fps、stride-platformer2d、stride-topdownrpg、stride-thirdpersonplatformer、stride-vrsandbox | nuget.org(CLI 安装 / 未来模板商店) |
Stride.Templates.Samples | 18 个功能演示(教程、游戏、图形、物理、UI、粒子、输入、音频) | nuget.org(CLI 安装 / 未来模板商店) |
Stride.Templates.AssetPacks | 4 个资源包条目模板:stride-pack-buildingblocks、stride-pack-animatedmodels、stride-pack-materials、stride-pack-particles | nuget.org(由 GameStudio 新建游戏对话框 / stride CLI 按需下载) |
关键设计是:GameStudio 的"New Project"对话框与 CLI dotnet new 消费的是同一批包,只有一条模板流水线,而不是两套。这得益于引擎侧与 CLI 侧共享的解析逻辑——GameStudio 端由 DotNetNewTemplateBridge.cs 负责,它通过 ContentTemplateResolver.cs 解析四个包(Games 包跟随引擎版本,内容类包跟随内容版本),安装到编辑器隔离的 TemplateEngine profile,并把每个模板注册为 TemplateDotNetNewDescription 交给 TemplateManager。
二、终端用户视角:用 dotnet new 创建 Stride 项目
1. 创建空白游戏
最基础的用法是安装 Games 包并实例化 stride-game:
dotnet new install Stride.Templates.Games
dotnet new stride-game -n MyGame
cd MyGame
dotnet run --project MyGame.Windows
2. 类型化游戏起步器与功能演示
类型化起步器和功能演示需要先安装各自的包:
# 有明确游戏类型的起步器(FPS、平台跳跃、俯视角 RPG、第三人称、VR)
dotnet new install Stride.Templates.Games.Starters
dotnet new stride-fps -n MyShooter
cd MyShooter && dotnet run --project MyShooter.Windows
# 功能演示 / 教程(18 个模板:stride-csharp-beginner / -intermediate、
# stride-jumpyjet、stride-spaceescape、stride-animatedmodel、stride-particles、
# stride-bepuphysics、stride-physics、stride-ui-menu 等)
dotnet new install Stride.Templates.Samples
dotnet new stride-jumpyjet -n MyJumpyJet
cd MyJumpyJet && dotnet run --project MyJumpyJet.Windows
3. 资源包:向已有游戏追加内容
资源包是 item 模板,作用是把现成的资源"投递"到已有的游戏库目录中(与 New Game 对话框中以复选框形式展示的内容一致):
dotnet new install Stride.Templates.AssetPacks
cd MyGame/MyGame.Game
dotnet new stride-pack-buildingblocks # 将包的 Assets/ + Resources/ 合并进项目
stride CLI 则无需手动安装:它会解析目标 Stride 版本对应的模板包,并在首次需要时自动下载资源包,因此在游戏库目录内执行 stride new stride-pack-buildingblocks 效果相同。
安装完成后,dotnet new -l 可以列出所有可用的 stride-* 短名称;dotnet new <template> --help 则显示每个模板接受的具体参数。
4. 通用参数
模板参数随模板而异,以下是常见参数:
| 参数 | 取值 | 含义 |
|---|---|---|
-n / --name | 字符串 | 项目名;实例化时会替换内容中所有的 MyTemplate 字面量 |
--platforms | host / windows / linux / macos / ios / android(多平台用 \| 连接) | 要包含的各平台执行项目;host 自动检测当前操作系统 |
--HDR | true / false | HDR 渲染管线(要求 graphicsProfile >= 10.0) |
--graphicsProfile | 9.0 / 10.0 / 11.0 | 着色器功能级别 |
--orientation | Default / LandscapeLeft / LandscapeRight / Portrait | 移动端显示方向 |
这些参数在模板生成器中均有对应的 template.json 符号实现,详见后文源码剖析。
三、本地开发:打包、部署与端到端验证
1. 构建 Games 包并自动部署到本地源
构建 Stride.Templates.Games 会在 bin/packages/ 产出 .nupkg,并自动部署到 %LocalAppData%\stride\nugetdev,这样 GameStudio bridge 在下次启动编辑器时就能直接取用:
dotnet build sources/templates/Stride.Templates.Games/Stride.Templates.Games.csproj
2. 内容类包的"默认不打包"策略
三个内容类包(Starters、Samples、AssetPacks)不会被普通构建打包:GameStudio 与 CLI 使用的是引擎所声明的已发布内容版本(见"示例版本管理"一节)。当你在编辑样例时,可以显式将其打开;打开后包会带上工作树后缀(如 4.4.0-beta7-dev2),从而在本 checkout 中覆盖已发布内容。关闭该标志重新构建即可移除它:
dotnet build sources/templates/Stride.Templates.Samples -p:StridePackContentTemplates=true # 或在 build/Stride.Local.props 中设置 StridePackContentTemplates
dotnet msbuild build/Stride.Samples.build -t:CleanContentTemplates # 不重新构建直接移除开发包
从 Stride.Templates.Common.targets 的实现可以看到,StridePackContentTemplates 默认值在 CI 环境(CI / GITHUB_ACTIONS / TF_BUILD 任一为真)下自动为 true,本地为 false;关闭状态下包仍可被构建(NoTargets 项目本就无内容可编译),并且仍会以精确的已提交版本响应 GameStudio 的 nuspec 依赖查询。这样设计的原因是:内容包体积大、内容极少变化,按自己的节奏发布(release-samples.yml)。
3. 注册到全局 dotnet new 注册表(可选)
希望在每次构建后自动把新构建的 .nupkg 注册到全局 dotnet new 注册表(便于用 CLI 迭代模板内容),可以打开 StrideInstallTemplate:
dotnet build sources/templates/Stride.Templates.Games/Stride.Templates.Games.csproj -p:StrideInstallTemplate=true
该开关默认关闭,因为模板注册表是全局按用户生效的——每次构建都自动安装会覆盖其他 Stride checkout/worktree 的模板并打扰用户的 CLI 工作流。若希望跨构建持久生效,可以在 checkout 根目录放置一个被 gitignore 的 Directory.Build.user.props:
<Project>
<PropertyGroup>
<StrideInstallTemplate>true</StrideInstallTemplate>
</PropertyGroup>
</Project>
4. 端到端冒烟测试
打包 → dotnet new install → 实例化 → dotnet restore 的完整链路由测试项目覆盖:
dotnet test sources/tools/Stride.Templates.Tests
5. CI 发布打包
正式发布版会生成带版本号、经过完整预处理的 .nupkg(含资源裁剪与最终 schema 迁移):
dotnet pack sources/templates/Stride.Templates.Games -p:StridePackageBuild=true
这里 StridePackageBuild=true 会把模板打包模式切换为 preprocessed(完整预处理);本地默认的 minimal 模式会跳过 M6 资源裁剪步骤(--skip-prune)。Common.targets 中还内置了 CI 保护:StridePackageBuild=true 时若打包模式不是 preprocessed 会直接报错,确保绝不发布未经预处理的 nupkg。
四、示例版本管理:devN 与内容版本
仓库内的样例以干净的发布版本提交,但本地通常只有 -devN 开发包存在,因此需要在编辑前后切换引用版本:
SamplesToDevEngine:把样例 csproj 中所有Stride.*引用改写为本 checkout 开发构建的版本(真实编辑);SamplesToReleaseEngine:改回干净的发布版本,供提交前使用;PrepareSamplesForRelease:将样例升级到当前引擎并打包。
dotnet msbuild build/Stride.Samples.build -t:SamplesToDevEngine # 编辑/构建前(例如在 GameStudio 中)
dotnet msbuild build/Stride.Samples.build -t:SamplesToReleaseEngine # 提交前
dotnet msbuild build/Stride.Samples.build -t:PrepareSamplesForRelease # 升级样例到当前引擎并打包
Stride.Templates.Games 跟随引擎版本;而 Stride.Templates.Samples、.Games.Starters、.AssetPacks 是内容版本:StrideSamplesVersion(定义于 StrideSamplesVersion.props,当前提交值为 4.4.1)是引擎实际引用的已发布内容版本。该文件被 Stride.Templates.Common.targets(打包侧)与 build/Stride.Samples.build(样例发布侧)共同导入,并被 Stride.Assets 以资源形式嵌入——这样一次样例发布只需要重新构建 Stride.Assets,而不必重建所有程序集。样例的修改按普通变更合并,随后由 release-samples.yml 以新的内容版本发布并提交该版本。更完整的版本机制(引擎版本、-devN、样例发布顺序、解析器)见 docs/build/versioning.md。
五、添加一个新的模板样例
1. 编写样例
在 samples/<Category>/<SampleName>/<SampleName>/ 编写样例,遵循标准 Stride 样例布局:.Game/<SampleName>.Game.csproj + .Game/<SampleName>.Game.sdpkg,可选的 .Windows/<SampleName>.Windows.csproj(及其他平台执行目录)、Assets/、Resources/。样例必须能在自身目录下(先执行 SamplesToDevEngine)干净地 dotnet build——预处理器只负责暂存和转换,不修复损坏的输入。
2. 放置 .sdtpl 元数据文件
在 samples/<Category>/<SampleName>/<SampleName>/<SampleName>.sdtpl 放置模板元数据:
!TemplateSample
Id: <new-guid>
Name: "Sample game: MyCoolSample"
Scope: Session
Description: A short blurb for the dialog row.
FullDescription: Multi-line elaboration shown in the dialog detail pane.
Group: Samples/Games
Icon: .sdtpl/icon.png
DefaultOutputName: MyCoolSample
Screenshots:
- .sdtpl/screenshot_small.jpg
Parameters:
- HDR
- graphicsProfile
- orientation
其中 Parameters 声明该模板选择启用的可选参数(由预处理器发射到 template.json 中);Icon 与 Screenshots 相对于 .sdtpl 文件解析,指向样例目录之外的路径(如 ../../.sdtpl/shared.png)会在打包时被自动复制到每个模板的内容中。
3. 挂接到包中
在对应的 Stride.Templates.*.csproj 中添加 <StrideSampleTemplate> 项:
<StrideSampleTemplate Include="stride-mycoolsample">
<SamplePath>$(StrideRoot)samples/Category/MyCoolSample/MyCoolSample</SamplePath>
</StrideSampleTemplate>
Include 值即 dotnet new 短名称。按内容类型选包:类型化游戏起步器进 Stride.Templates.Games.Starters,功能演示进 Stride.Templates.Samples。仓库中的实际例子可见 Stride.Templates.Samples.csproj(18 个样例)与 Stride.Templates.Games.Starters.csproj(5 个起步器)。此外,每个包的 csproj 都要为对应的样例目录补充 UpToDateCheckInput 字面通配符,否则 VS 的快速最新检查(CPS 只读取静态展开的输入)会跳过 Build → 不触发 Pack → nupkg 过期。
4. 构建包并检查转换结果
预处理器会完成以下转换(详见下一节源码剖析):GUID 重写(样例内部 GUID → template.json 占位符,引擎原型 Id 保留)、ProjectReference 依赖折叠(共享资源包内联为 Assets//Resources/)、sourceName 重命名(MyCoolSample → MyTemplate → 实例化时的 -n 值)、.sln 合成(带平台条件项目段)、template.json 发射。打包前可检查 obj/template-content/stride-mycoolsample/ 目录确认转换结果。
六、添加一个新的资源包
资源包走的是精简流水线:只暂存 Assets/ + Resources/,打包为 dotnet new item 模板(无 sourceName 重命名、无 GUID 占位、无资源裁剪)。在包根目录放置一个 !TemplateAssetPack 类型的 .sdtpl(可参考 samples/Templates/Packs/PrototypingBlocks):
!TemplateAssetPack
Id: <new-guid>
Name: "My pack"
Description: A short blurb shown next to the checkbox.
Group: AssetPacks
然后在 Stride.Templates.AssetPacks.csproj 中添加 <StrideSampleTemplate> 条目。GameStudio 的 New Game 对话框会把 AssetPacks 包的每个 item 模板都列为一个复选框(.sdtpl 的 Parameters 中包含 assetPacks 的模板会进入该区域;目前是 stride-game),并把用户选中的每个资源包实例化到新生成的游戏库中。现有四个资源包的定义见 Stride.Templates.AssetPacks.csproj。
七、模板生成器源码剖析
1. 两个子命令
Program.cs 是发布流水线工具,提供两个子命令:
preprocess-template:把原始模板输入(一个样例目录)转换为 dotnet new 模板引擎可消费的目录。命令行选项包括--input-path、--output-path、--template-name(dotnet new 短名称)、--source-name(要重命名为MyTemplate的原始字面名,缺省时从首个.sdpkg的Name字段自动检测)、--engine-version(把引擎版本戳进产出的 csproj:$EngineVersion$字面量 + 引擎族Stride.*PackageReference 的具体版本)、--skip-prune(跳过资源裁剪)、--platform-template-path(参考模板,通常是 NewGame,其MyTemplate.{Linux,macOS,iOS,Android,Windows}目录会被复制进缺少对应平台执行项目的输出中)。aggregate-sdtpls:把每个被包裹模板的.sdtpl拼接为一个多文档 YAML 文件,输出到包根目录的templates.sdtpls。GameStudio bridge 读取这一个文件即可填充 New-Project 对话框,无需加载每个模板的预处理内容。
2. 预处理流水线
TemplatePreprocessor.cs 的 Run 方法内联记录了完整步骤,核心环节如下:
- 解析
.sdtpl:驱动 template.json 元数据(Name、Description、identity 等)与参数选择;若为!TemplateAssetPack则走精简的RunAssetPack路径。 - 暂存(Stage):递归镜像输入 → 输出,并剔除
.sdtpl元数据文件;bin/obj/.vs目录不进入模板(避免膨胀与 Windows MAX_PATH 问题)。 - 依赖折叠(Dep collapse):把指向暂存目录之外的
ProjectReference(如共享资源包)的Assets/、Resources/内联进暂存树并删除该引用;模板内部引用(如MyTemplate.Windows → MyTemplate)保留。 - 资源裁剪(Prune):以
.sdpkg的RootAssets与固定根类型(GameSettingsAsset、EffectShader、EffectLibrary、EffectCompositorAsset、ScriptSourceFileAsset)为根,对*.sd*文件中<guid>:<location>形式的资产引用做 BFS 可达性分析,删除不可达资产。对依赖折叠后的样例模板,通常能裁剪掉 80% 以上的内联包资源。该扫描是纯文本的(不加载PackageSession),因此毫秒级完成且不依赖引擎程序集。 - sourceName 重命名:把样例字面名(如
CSharpBeginner)按词边界替换为MyTemplate,覆盖文件内容、文件名与目录名;App/AppDelegate/Activity后缀通过前瞻保留(如CSharpBeginnerApp.cs → MyTemplateApp.cs)。 - 平台注入:从
--platform-template-path复制样例缺失的平台执行项目目录;仅对含有MyTemplate.Game/的"可运行游戏"类模板生效,纯库模板(stride-library)不会获得平台项目。 - 合成
.slnx:样例通常不包含解决方案文件,生成器为暂存树内每个 csproj 生成<Project>条目,平台执行项目用#if (XActive)条件包裹,供 template.json 的SpecialCustomOperations在实例化时剥离未选平台;优先级最高的保留平台(Windows > Linux > macOS > Android > iOS)获得DefaultStartup="true"——因为.slnx不像传统.sln按文件顺序确定启动项目。 - 相机脚本注入:把
BasicCameraController组件以!MyTemplate.BasicCameraController,MyTemplate.Game占位形式注入MainScene*.sdscene的 Camera 实体(HDR/LDR 双变体都会处理),组件 Id 使用固定 GUID 以便后续占位符化,保证每次实例化都生成全新 GUID。 - 方向占位符注入(仅当模板选择
orientation参数):把 GameSettings 的DisplayOrientation、Android 活动的ScreenOrientation.Landscape、iOS Info.plist 的UIInterfaceOrientationLandscapeRight分别改写为STRIDE_ORIENTATION、STRIDE_ANDROID_ORIENTATION、STRIDE_IOS_ORIENTATION占位符。源脚手架保留真实可构建的值,只有暂存副本被令牌化。 - GUID 扫描与占位:先建立"本地声明的 Id 集合"(
.sd*文件中所有Id:行,含子资产 Id),只对集合内的 GUID 做占位(00000000-0000-0000-0000-xxxxxxxxxxxx);引擎原型 Id、相机槽 Id 等外部引用保持原样,避免实例化后引用悬空。三个 Microsoft 预定义项目类型 GUID 也在保留集中。 template.json发射:为每个 GUID 占位符生成一个generated/guid符号;发射platforms多选(host通过env:OS/env:OSTYPE/env:HOME绑定与 computed 布尔链解析为各平台*Active)、HDR/LDR 选择、graphicsProfile选择、orientation选择(Android/iOS 用 switch 生成器映射到平台原生枚举),以及sources/modifiers按*Active条件排除平台目录、按EffectiveHDR选择 HDR/LDR 场景变体(LDR 变体通过rename恢复为标准文件名)。同时发射dotnetcli.host.json,把 GameStudio 程序化设置的updateOnly、skipSolution参数标记为 UI 不可见。值得注意的还有compactName名称形式(去空白、数字前加点转下划线、再走引擎的safe_namespace),解决带空格项目名导致.slnx/ProjectReference/sdpkg 路径不一致的问题。- 引擎版本戳印:替换
$EngineVersion$字面量,并把引擎族Stride.*PackageReference 的具体版本改写为打包时的引擎版本(社区前缀如Stride.Community、Stride.Mono.等除外),保证打包内容无需任何 Stride 侧改写钩子即可被包括纯dotnet new在内的所有消费者直接实例化。 - 换行符归一化:
.sln/.slnx→ CRLF(与 VS/dotnet 编辑行为一致,避免首次保存时的"行尾不一致"提示),其余文本 → LF;二进制文件(.dds/.png/.fbx/.wav等)不受影响,确保 nupkg 与构建主机无关地字节一致。
3. 共享 MSBuild 逻辑
Stride.Templates.Common.targets 被四个包的 csproj 共同导入,承担版本推导(Games 跟随 StrideNuGetVersion,内容类包跟随 StrideSamplesVersion,-p:PackageVersion= 显式覆盖)、工作树 -devN 后缀追加、preprocess-template 与 aggregate-sdtpls 的 Exec 调用、自动打包部署(Stride.AutoPackDeploy.targets)、CI 保护、以及 StrideInstallTemplate 可选目标。它还会通过一个 Private=false 的 Stride.Core ProjectReference 在 nuspec 中打入"最低引擎版本"标记依赖——CLI 正是读取该元数据来选择兼容模板的。GameStudio 会话侧由 DotNetNewTemplateGenerator.cs 完成实例化分发与各平台执行项目的会话注册。
八、未来工作方向
README 末尾列出了几项明确的演进方向,均围绕当前单条模板流水线的短板:
- Windows 一键 CLI 注册:在 Linux/macOS 上手动
dotnet new install是标准路径(没有编辑器可集成);Windows 上 GameStudio 已内置Stride.Templates.Games.<version>.nupkg,未来可提供一个设置开关替用户执行安装。采用 opt-in 是为了尊重用户意图、避免 4.4 与 4.5 GameStudio 并存时的多版本冲突。GameStudio 自身的 New-Project 对话框不受影响——它安装到隔离的 TemplateEngine profile,而非全局dotnet new注册表。 - 资源包改为引用包:目前资源包是用户持有的拷贝(复制进项目);未来可借助资产 URL 命名空间把资源包变成真正的 NuGet 资产包并作为
PackageReference引用,资产随版本更新、第三方可发布自己的包。对话框 UX 不变,复选框动作从"复制"改为"引用",item 模板在无需迁移的情况下逐步退出(已创建的游戏保留其复制的资产)。 - 模板商店 UI:在 New-Project 对话框内浏览 nuget.org 上的
Stride.Templates.Games.Starters/Stride.Templates.Samples,按需安装而无需手动 CLI。 templates.sdtpls的 HTTP Range 拉取:仅加载聚合元数据(Name/Description/Icon/Screenshots),再决定是否下载数 MB 的 nupkg,让商店 UI 无需全量下载即可展示丰富的预览卡片。
【免费下载链接】stride
Stride (formerly Xenko), a free and open-source cross-platform C# game engine.
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



