关于 monarch-screen-setup
monarch-screen-setup 是面向使用 Monarch 的 Defold 项目的技能,指导开发者组织屏幕与弹窗、完成注册及导航,并要求先确认项目包含 Monarch。
主要功能
- 01验证 Monarch 依赖
- 02屏幕与弹窗命名规范
- 03使用 collectionproxy 设置屏幕
- 04使用 collectionfactory 设置弹窗
- 05屏幕与弹窗导航模式
适用场景
- 01应用 Monarch 指引前检查 Defold 项目
- 02设置屏幕之间的导航
- 03添加可堆叠并可关闭的弹窗
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ indiesoftby/ defold-agent-config --skill monarch-screen-setup安装后在 Claude Code 中输入/monarch-screen-setup确认已加载。
详细介绍
使用 Monarch 组织屏幕和弹窗
前置条件:验证 Monarch 依赖
应用本技能中的任何指导之前,必须确认项目确实使用了 Monarch。检查项目根目录中的 game.project 文件,确认是否包含指向 britzl/monarch 的依赖 URL(例如 dependencies#N = https://github.com/britzl/monarch/archive/...)。或者,检查项目目录中是否存在 monarch/monarch.lua 文件。
如果 game.project 中没有 Monarch 依赖,也没有找到本地 monarch/monarch.lua 模块,请勿应用本技能。告知用户项目似乎没有使用 Monarch;如果他们希望使用 Monarch,建议将依赖添加到 game.project:
[project]
dependencies#N = https://github.com/britzl/monarch/archive/refs/tags/5.2.0.zip
本技能介绍了在使用 Monarch 库的 Defold 项目中,通过 collectionproxy 创建和管理屏幕,以及通过 collectionfactory 创建和管理弹窗的约定。
命名规则
- 所有屏幕和弹窗名称均使用
snake_case。 - 屏幕和弹窗名称在整个项目中必须唯一,因为 Monarch 会将它们注册到一个共享注册表(
monarch.lua中的screens表)。ID 重复会导致断言错误。 - 建议为弹窗名称添加明确的前缀(例如
settings_popup、reward_popup),避免与屏幕名称(例如main_menu、gameplay)冲突。
目录结构
project/
├── main/
│ ├── main.collection -- bootstrap collection (set in game.project [bootstrap])
│ └── main.script -- main controller script: waits for registration, shows first screen
├── screens/
│ └── <screen_name>/
│ ├── <screen_name>.collection -- IMPORTANT: collection name MUST be unique (see below)
│ ├── <screen_name>.gui
│ └── <screen_name>.gui_script
├── popups/
│ └── <popup_name>/
│ ├── <popup_name>.collection
│ ├── <popup_name>.gui
│ └── <popup_name>.gui_script
创建屏幕(collectionproxy)
屏幕是通过 collectionproxy 加载的全屏视图。一次只能有一个屏幕处于活动状态。切换屏幕时,始终使用 { clear = true },以避免堆叠多个屏幕。
屏幕所需文件(例如 gameplay)
1. screens/gameplay/gameplay.collection
-
集合的
name属性在整个项目中必须唯一(Defold 使用该属性在已加载的世界中进行 URL 寻址)。 -
包含一个带有摄像机组件的游戏对象。
name: "gameplay"
scale_along_z: 0
embedded_instances {
id: "camera"
data: "embedded_components {\n"
" id: \"camera\"\n"
" type: \"camera\"\n"
" data: \"aspect_ratio: 1.0\\n"
"fov: 0.7854\\n"
"near_z: -1.0\\n"
"far_z: 1.0\\n"
"orthographic_projection: 1\\n"
"orthographic_mode: ORTHO_MODE_AUTO_COVER\\n"
"\"\n"
"}\n"
""
}
在 main.collection 中注册屏幕
在 main.collection 中,为每个屏幕创建一个游戏对象(例如 ID 为 gameplay),并添加:
- 一个引用
/monarch/screen_proxy.script的组件screen_proxy,其属性如下:screen_id=gameplay(hash,必须与monarch.show()中使用的 ID 相匹配)popup=falsepopup_on_popup=false
- 一个类型为
collectionproxy的嵌入式组件collectionproxy,指向/screens/gameplay/gameplay.collection。
screen_proxy.script 会在其 init() 中调用 monarch.register_proxy(),自动注册屏幕。
显示屏幕(单屏幕栈模式)
显示屏幕时,始终使用 { clear = true },这样会清除栈中的现有实例,再替换为当前屏幕。这能确保栈中始终只有一个屏幕:
monarch.show("gameplay", { clear = true })
屏幕不要在调用 monarch.show("gameplay") 时省略 clear = true,否则会将屏幕推入栈中,造成令人困惑的多屏幕栈。
在屏幕之间导航:
-- from main_menu to gameplay:
monarch.show("gameplay", { clear = true })
-- from gameplay to main_menu:
monarch.show("main_menu", { clear = true })
屏幕之间导航时不要使用 monarch.back()。back() 用于关闭弹窗。
创建弹窗(collectionfactory)
弹窗是覆盖在屏幕上的视图,可暂停并调暗下方的屏幕。弹窗通过 collectionfactory 创建,因此可以同时存在多个弹窗(弹窗上叠加弹窗)。
弹窗所需文件(例如 settings_popup)
1. popups/settings_popup/settings_popup.collection
- 包含一个带有引用 GUI 组件的游戏对象。
name: "settings_popup"
scale_along_z: 0
embedded_instances {
id: "go"
data: "components {\n"
" id: \"gui\"\n"
" component: \"/popups/settings_popup/settings_popup.gui\"\n"
"}\n"
""
}
2. popups/settings_popup/settings_popup.gui
- 标准 Defold GUI 文件,包含弹窗的 UI 节点。
3. popups/settings_popup/settings_popup.gui_script
- 要关闭自身,请调用
monarch.back()。
local monarch = require("monarch.monarch")
function init(self)
end
function final(self)
end
function on_message(self, message_id, message, sender)
end
function on_input(self, action_id, action)
if action_id == hash("touch") and action.pressed then
-- example: close popup on a button press
-- (check node picking for your close button here)
monarch.back()
end
end
在 main.collection 中注册弹窗
在 main.collection 中,为每个弹窗创建一个游戏对象(例如,ID 为 settings_popup),并添加:
- 一个 组件
screen_factory,引用/monarch/screen_factory.script,并设置以下属性:screen_id=settings_popup(哈希值)popup=truepopup_on_popup=true(如果此弹窗可以显示在另一个弹窗上方,则设为true)screen_factory= 指向collectionfactory组件的 URL(见第 2 步)
- 一个类型为
collectionfactory的嵌入式组件collectionfactory,指向/popups/settings_popup/settings_popup.collection。
screen_factory.script 会在其 init() 中调用 monarch.register_factory(),自动注册弹窗。
显示和关闭弹窗
-- Open a popup (it stacks on top of the current screen):
monarch.show("settings_popup")
-- Open a popup on top of another popup (requires popup_on_popup = true):
monarch.show("confirm_popup")
-- Close the topmost popup:
monarch.back()
弹窗时间步行为
在屏幕上方显示弹窗时,Monarch 会自动在底层屏幕的代理上设置 timestep_below_popup。默认值为 1(正常速度)。若要暂停弹窗下方的屏幕,请在该屏幕的 screen_proxy.script 属性中将其设为 0:
timestep_below_popup=0
等待所有屏幕注册后再启动
不要直接在 main.script 的 init() 中调用 monarch.show()——此时其他脚本的 init() 尚未运行,屏幕也尚未注册。这会导致断言错误。
解决方法:在 init() 中向自身发送一条消息。处理该消息时,集合中的所有 init() 函数都已执行完毕,所有屏幕和弹窗也都已注册。
示例:main/main.script
local monarch = require("monarch.monarch")
function init(self)
msg.post(".", "acquire_input_focus")
msg.post("#", "start")
end
function on_message(self, message_id, message, sender)
if message_id == hash("start") then
monarch.show("main_menu", { clear = true })
end
end
快速参考
| 操作 | 代码 |
|---|---|
| 显示屏幕(清空堆栈) | monarch.show("screen_name", { clear = true }) |
| 显示弹窗 | monarch.show("popup_name") |
| 关闭最上层弹窗 | monarch.back() |
| 检查屏幕是否已注册 | monarch.screen_exists("screen_name") |
| 检查是否忙碌(正在转换) | monarch.is_busy() |
| 获取屏幕数据 | monarch.data("screen_name") |
| 向屏幕传递数据 | monarch.show("screen_name", { clear = true }, { key = "value" }) |
| 向弹窗传递数据 | monarch.show("popup_name", nil, { key = "value" }) |
| 检查是否为弹窗 | monarch.is_popup("popup_name") |
| 获取当前最上层屏幕 | monarch.top() |