mcpField
M
monarch-screen-setup

monarch-screen-setup

github.com/indiesoftby开发10445 次安装27 周前更新
代码仓库

关于 monarch-screen-setup

monarch-screen-setup 是面向使用 Monarch 的 Defold 项目的技能,指导开发者组织屏幕与弹窗、完成注册及导航,并要求先确认项目包含 Monarch。

主要功能

  1. 01验证 Monarch 依赖
  2. 02屏幕与弹窗命名规范
  3. 03使用 collectionproxy 设置屏幕
  4. 04使用 collectionfactory 设置弹窗
  5. 05屏幕与弹窗导航模式

适用场景

  1. 01应用 Monarch 指引前检查 Defold 项目
  2. 02设置屏幕之间的导航
  3. 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),并添加:

  1. 一个引用 /monarch/screen_proxy.script 的组件 screen_proxy,其属性如下:
    • screen_id = gameplay(hash,必须与 monarch.show() 中使用的 ID 相匹配)
    • popup = false
    • popup_on_popup = false
  2. 一个类型为 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),并添加:

  1. 一个 组件 screen_factory,引用 /monarch/screen_factory.script,并设置以下属性:
    • screen_id = settings_popup(哈希值)
    • popup = true
    • popup_on_popup = true(如果此弹窗可以显示在另一个弹窗上方,则设为 true)
    • screen_factory = 指向 collectionfactory 组件的 URL(见第 2 步)
  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()

评论

支持 Markdown