|
Deki 0.19.0
面向嵌入式显示屏和桌面的模块化 C++ 2D 引擎
|
平台是项目构建的一个目标:一块开发板、桌面模拟器或一台游戏机。本页介绍平台由什么组成、平台从哪里来、包如何附带开发板,以及项目开始使用某块开发板之后会发生什么。
项目 platforms/ 下的一个目录,以平台的 id 命名:
JSON 描述编辑器需要知道的内容,而不涉及如何构建:
| 键 | 含义 |
|---|---|
| id, displayName | id 同时也是目录名。 |
| framework | 由哪个构建后端来构建它(espidf、native、...)。没有默认值:未指定的平台就没有后端,构建时会提示这一点。 |
| frameworkOptions | 该后端自己的设置:芯片、闪存大小、sdkconfig 行、引脚。编辑器只负责携带而不读取它们;由后端在构建时进行校验。 |
| family | 仅用于描述。会成为能力 family:<x>。 |
| screenWidth, screenHeight, colorFormat | 该目标的屏幕。编辑器会预览它,桌面模拟器会打开该尺寸的窗口,设为“自动”的图像会以 colorFormat 为它存储。设备以其显示屏自身的尺寸和格式进行渲染;参见 screens.md。 |
| externalMemorySize | 内部堆之外的内存字节数(在微控制器上即 PSRAM)。为包提供 memory:external。 |
| provides | 该目标可以为包提供的东西:wifi、spi、desktop-os、... |
| requiresPackages | 无论场景使用什么,该目标始终需要的包。通常是它的硬件抽象层。 |
| defines, cFlags, cxxFlags, linkFlags | 游戏自身代码的编译器设置。 |
| bootScene | 引导场景的路径,相对于项目。 |
| assetStorage | 构建将游戏资源保存在哪里:internal(默认)或 external。见下文。 |
引导场景包含一个 Deki::PlatformSetupComponent,其 setupComponents 列表按顺序列出启动硬件的配置步骤:电源引脚、显示屏、I2C 总线、触摸。每个条目为 {id, typeId}:持有该步骤的子对象的 id,以及该步骤限定类名的哈希值(Deki::HashString)。typeId 错误不会导致失败;该步骤只是悄无声息地永远不会运行。编辑器测试中的 ShippedPlatformTemplates 会检查各个包附带的每个引导场景。
构建将游戏资源保存在以下两个位置之一:
只有 provides 中包含 external-storage 的平台才能选择外部存储;平台编辑器只对这些平台显示该选项(存储 > 资源存放位置)。只有游戏大到闪存放不下时才选择它:使用外部存储时如果卡槽中没有卡,游戏就没有任何资源。LilyGO T-Deck Plus 可以选择;除非另行指定,它会将资源保存在闪存中。
project_data.bin 会记录这一选择,以便引擎知道去哪里查找。
如果开发板的后端带有模拟器(ESP32 或 ESP32-S3 使用 QEMU),就可以将其构建为在模拟器中运行:在构建面板中勾选 在 QEMU 中模拟,然后点击“构建”和 运行。在命令行中:
模拟构建保留开发板引导场景的每一个步骤,并在其后加上模拟器自己的步骤(QEMU 屏幕),这些都保存在其构建目录下的一个副本中(generated/build/<platform>_qemu/simulation/boot.scene)。如果模拟器需要以其他方式运行某个步骤,副本中会注明:通过 SPI 连接的 SD 卡会改为接在 QEMU 的 SD 主机上。构建日志会列出每一处改动。平台的 boot.scene、它的常规构建以及烧录到开发板上的固件都不会被更改,模拟器需要的任何东西也都不会编译进去。
模拟的开发板带有一张 SD 卡,每次构建时在 simulation/sd_card 中重新生成:对于将资源保存在卡上的目标,卡中是 SD 卡部署面板会复制的那些资源;对于将资源保存在内部的目标,卡是空的。
后端通过 ITargetBuilder::SupportsSimulation、GetSimulatorName 和 MakeSimulationBootScene(配合 deki-editor/build/SimulationBootScene.h 中的 AddSimulationSteps)提供此功能,其余部分则读取 BuildOptions::simulate 来处理:它自己的构建目录、SD 卡以及部署时要做的事。
构建面板的目标列表有三个来源,后面的覆盖前面的:
安装或移除包会立即更新该列表。
在包中为每块开发板放一个目录:
这就是全部机制。包不需要任何代码:不需要 package.cmake,也不需要入口点。它的 package.json 应在 requires 下列出其开发板的引导场景所用的包,这样安装开发板时也会一并安装这些包;每个平台还应在 requiresPackages 中再次列出它的硬件抽象层。
会被检查的规则:
包的功能可以在该功能的 requires 中指定它单独需要的包:
这些包不会随该包一起安装。由使用该功能的开发板或项目引入它们:deki-lilygo-boards 需要 deki-i2c 和 deki-gpio,因为 T-Deck 有 I2C 总线和引脚,正是这一点让 deki-input 的键盘和轨迹球得以构建。安装了 deki-input 的桌面项目则两者都不会得到。
只有当某个目标使用了该功能时,构建才会引入该功能的包。正在使用但缺少所需包的功能,会被构建为一个在日志中记录需要安装什么的步骤,并且构建会发出警告。功能的代码用 __has_include 检查该包,因此无论哪种情况都能编译。
deki-lilygo-boards 是可供参照的示例。deki-desktop-integration 以同样的方式附带模拟器,deki-tactility-integration 则附带它的两个目标。
选择某个包的平台(在构建面板中、使用 set_active_platform,或为它进行构建)会将其目录复制到项目的 platforms/ 中。此后它就是项目的文件:在平台编辑器中编辑它,像打开任何场景一样打开它的引导场景,提交它。项目绝不会从包内部进行构建。
项目已经定义的平台绝不会被采用操作覆盖,该目录中已有的文件也会保留。
采用操作还会在平台旁边写入 origin.json。它记录包的名称,并保存采用时的模板:平台 JSON,以及其他每个文件的哈希值。请将它与其余文件一起提交。
当采用时的内容、项目当前的内容以及包当前提供的内容都已知时,构建面板会在目标列表下方显示:
以下情况不算作修改:编辑器以自己的格式重新保存 JSON(较旧的文件将后端设置放在顶层;保存时会将它们嵌套到 frameworkOptions 下),以及被 git 更改的换行符。
在开始记录来源之前就已采用的平台,会在下次使用时获得记录,前提是它仍与包提供的内容一致。如果不一致,就无从判断那是谁做的更改,因此不会凭空创建基准:它会显示为*与包中的版本不同*,可以恢复,但不能更新。
如果包被移除,平台会保留并且仍然可以构建。在包重新安装之前,该行会显示*(未安装)*。
删除一个已采用的平台会让它重新出现在可选列表中;再次选择它会复制包的当前版本。
| 工具 | 作用 |
|---|---|
| list_platforms(或 --list-platforms) | 列出每个目标,来自包的目标带有 origin:package、modified、updateAvailable、canUpdate、canRestore。 |
| set_active_platform | 选择项目的默认目标,必要时采用它。 |
| create_platform, set_platform_provides | 创建或更改项目自己的平台。set_platform_provides 接受 asset_storage 和 cxx_flags。 |
| update_platform | 从包更新。返回 taken 和 kept。 |
| restore_platform | 恢复包的版本。返回 taken。 |
deki-editor/build/PlatformConfig.h 是平台本身及其注册表。deki-editor/build/PlatformTemplates.h 包含本页中与包有关的所有内容:查找可选平台、采用、来源记录、更新和恢复。两者都在编辑器的 SDK 中,因此包的构建后端可以使用它们。