KubeJS 可操作 UI(ScreenJS:能点能放物品的交互式界面)¶
原文:原创教程(ぴよまる),API 依据官方 Wiki「ScreenJS」篇
⚠️ 版本警告(重要):ScreenJS 只支持 Minecraft 1.19.2(CurseForge 上全部版本均为 1.19.2,最后更新 1.1.6 也是 1.19.2),不支持 1.20.1!如果你用的是 1.20.1(KubeJS 6.1),请直接使用 KubeJS 官方内置的可操作 UI——见下一篇「可操作 UI(KubeJS 内置)」:
player.openChestGUI()等,无需任何第三方插件。本页内容仅适用于 1.19.2。
上一篇的 Painter API 画出来的东西只能看、不能点(没有按钮、没有输入)。想要真正可操作的 UI——有按钮、能放物品、有进度条的交互式界面——在 1.19.2 需要 ScreenJS:KubeJS 的自定义容器菜单(ContainerMenu)系统,注册后右键方块/实体就能打开,跟箱子、熔炉一样的 GUI。
⚠️ 前置说明:ScreenJS 是第三方附加组件(作者 screret),需要单独安装(CurseForge 搜
screenjs,Forge 1.19.2)且需要 beJS(描述中明确标注「this mod now requires beJS」)。装上后在kubejs/里正常写脚本。
1. 整体思路¶
ScreenJS 用 StartupEvents.registry('menu', ...) 注册一个"菜单类型",然后把它绑到某个方块/方块实体/实体上——玩家右键那个东西就自动打开 GUI。菜单里可以加:
- 物品槽(能放/取物品,像箱子格子)
- 输出槽(只能取不能放,可绑定熔炉配方)
- 进度条(进度/燃料/能量条,从方块实体的数据读取)
- 按钮(点了触发回调)
四种菜单类型(type):
| 类型 | 用途 | 绑定方法 |
|---|---|---|
basic |
独立 GUI,不绑定任何东西(默认) | 无,用命令/按键打开 |
block_entity |
绑定方块实体(带数据的方块) | .setBlockEntity('modid:方块id') |
block |
绑定普通方块 | .setBlock('modid:方块id') |
entity |
绑定实体(右键实体打开) | .setEntity('modid:实体id') |
2. 最小示例:给普通方块加一个"带物品格子的 GUI"¶
// startup_scripts/menu.js
// startup 脚本:游戏启动时注册菜单
StartupEvents.registry('menu', event => { // 监听"注册菜单"事件;event 提供注册方法
event.create('my_box' /*菜单名字,自己起*/, 'block') // 创建一个"绑定普通方块"的菜单,名字叫 my_box
.addItemHandler(9) // 给菜单添加一个 9 格子的物品处理器(相当于 9 个槽位)
.inputSlotIndices(0) // 把 0 号处理器当作"输入槽"(放进物品会触发 slotChanged 回调)
.setBlock('minecraft:grass_block') // 绑定草方块:玩家右键草方块就会打开这个 GUI
})
进游戏右键一块草方块,就会弹出一个带 9 个物品格子的界面!
3. 完整案例:绑定方块实体的"机器菜单"¶
方块实体(带数据/逻辑的方块)能做进度条 + 输出槽。假设已经有一个 KubeJS 方块实体(见「进阶实战」第 3 节):
// startup_scripts/machine_menu.js
StartupEvents.registry('menu', event => { // 注册菜单
event.create('example_machine_menu' /*菜单名*/, 'block_entity') // 类型:绑定方块实体
.addSlot(10, 20) // 在 (10, 20) 位置加一个物品槽(坐标为界面纹理上的像素位置)
.addSlot(28, 20) // 第二个输入槽
.addOutputSlot(118, 20, 0, 0, 1, 'minecraft:smelting') // 输出槽:只进不出,绑定熔炉配方(参数:位置、输入容器、输出容器、配方类型)
.inputSlotIndices(0) // 0 号处理器作为"放入物品就触发回调"的输入
.playerInventoryY(100) // 玩家背包栏在界面纹理上的起始 Y 坐标(100 像素处)
.tintColor(0xFF00FF00) // 给整个界面纹理染色:绿色(0xAARRGGBB)
.progressDrawable(80, 50, new Rectangle(0, 0, 10, 30), 'forge:textures/white.png', 'up', 'energy')
// 画一个进度条:位置 (80,50)、从白色纹理裁 10×30 的区域、方向向上('up')、类型 'energy'(能量条)
.slotChanged((menu, level, player, itemHandlers) => { // 物品槽内容变化时触发
console.info('槽位变了!' + player) // 打印到日志(logs/server.log)
})
.setBlockEntity('kubejs:example_machine') // 绑定方块实体:右键这个方块打开 GUI
})
💡
addSlot(x, y)的坐标是界面纹理上的像素位置;物品槽间隔通常是 18 像素(对齐原版格子)。
批量加槽位(loop)¶
StartupEvents.registry('menu', event => { // 注册菜单
event.create('big_box' /*菜单名*/, 'basic') // 独立 GUI(不绑定东西)
.loop(builder => { // loop:循环调用,批量加槽位;builder 就是菜单构建器本身
for (let x = 0; x < 9; x++) { // 横向 9 个
for (let y = 0; y < 4; y++) { // 纵向 4 排
// 每格间隔 18 像素;第 3、4 个参数是槽位序号和容器序号(0 就是默认容器)
builder.addSlot(x * 18, y * 18, x + y * 4, 0)
}
}
})
})
4. 进度条与特殊绘制¶
progressDrawable 可以画三类条,方向支持四种:
类型(type): PROGRESS 进度 / FUEL 燃料 / ENERGY 能量
方向(direction): 'up' 向上 / 'down' 向下 / 'left' 向左 / 'right' 向右
// 给方块实体菜单加各种条
StartupEvents.registry('menu', event => {
event.create('machine' /*菜单名*/, 'block_entity')
// 燃料条:从白色纹理裁 (0,0,10,30),向上生长,类型 FUEL
.progressDrawable(50, 50, new Rectangle(0, 0, 10, 30), 'forge:textures/white.png', 'up', 'fuel')
// 能量条:向左生长,类型 ENERGY(读方块实体的 FE 能量)
.progressDrawable(70, 50, new Rectangle(0, 0, 10, 30), 'forge:textures/white.png', 'left', 'energy')
.setBlockEntity('kubejs:machine_block')
})
其他绘制方法:
| 方法 | 作用 |
|---|---|
drawable(x, y, rect, 纹理) |
画一个静态贴图 |
progressDrawable(...) |
画进度/燃料/能量条 |
fluidDrawable(x, y, rect, 纹理, 方向, tankIndex) |
画流体储量条(读方块实体流体罐) |
customDrawable(x, y, rect, 纹理, 方向, 回调) |
完全自定义绘制(回调里自己画) |
backroundTexture(纹理, rect) |
自定义界面背景贴图 |
5. 按钮(可点击!)¶
button() 可以加真正的可点击按钮:
StartupEvents.registry('menu', event => {
event.create('menu_with_button' /*菜单名*/, 'basic')
// 加一个按钮:位置矩形 (10, 10, 宽60, 高20),文字"点我";第三个参数是点击回调
.button(new Rectangle(10, 10, 60, 20), Text.string('点我'), button => {
// 按钮被点击时执行这里
console.info('按钮被点了!') // 打印到日志
})
})
6. 怎么打开菜单(三种方式)¶
6.1 右键绑定的方块/实体(最常用)¶
绑定好 setBlock / setBlockEntity / setEntity 后,玩家右键对应目标自动打开。
6.2 自定义按键打开(KeybindEvents)¶
// client_scripts/keybind.js
// 注册一个按键:按 G 打开上面注册的 basic 菜单
KeybindEvents.register(event => { // 监听"注册按键"事件(客户端事件)
event.register(
// new KeyBind(名字, 按键编号, 分类名):按键编号是 OpenGL 键码,G 是 71(GLFW_KEY_G)
new KeyBind('open_menu', 71, 'screenjs'),
(action, modifiers) => { // 按键回调;action 1=按下 0=松开 2=长按重复
if (action == 1) { // 按下时
// MenuScreens.create(菜单ID, 客户端实例, 窗口ID, 标题文本):打开指定菜单
MenuScreens.create('kubejs:menu_with_button', Minecraft.instance, 1000, Text.string('我的菜单'))
}
}
)
})
6.3 其他回调方法¶
| 方法 | 作用 |
|---|---|
quickMoveFunc((player, slotIndex, menu) => ...) |
自定义 Shift 点击快速移动逻辑,返回物品 |
slotChanged((menu, level, player, itemHandlers) => ...) |
槽位内容变化回调 |
validityFunc((player, pos) => ...) |
判断玩家能否打开这个菜单(返回 boolean) |
disablePlayerInventory() |
隐藏玩家背包栏 |
playerInventoryY(数字) |
玩家背包栏的起始 Y 坐标 |
7. 速查表¶
| 想做什么 | 写法 |
|---|---|
| 注册菜单 | StartupEvents.registry('menu', event => event.create('名字', 类型)) |
| 菜单类型 | 'basic' / 'block_entity' / 'block' / 'entity' |
| 绑定方块实体 | .setBlockEntity('modid:id') |
| 绑定普通方块 | .setBlock('modid:id') |
| 绑定实体 | .setEntity('modid:id') |
| 加物品槽 | .addSlot(x, y) |
| 批量加槽 | .loop(builder => { ... builder.addSlot(...) }) |
| 加输出槽 | .addOutputSlot(x, y, 槽序号, 输入容器, 输出容器, 配方类型) |
| 输入槽序号 | .inputSlotIndices(0) |
| 画进度条 | .progressDrawable(x, y, rect, 纹理, 方向, 'energy') |
| 进度条类型 | 'progress' / 'fuel' / 'energy' |
| 进度条方向 | 'up' / 'down' / 'left' / 'right' |
| 加按钮 | .button(new Rectangle(x, y, w, h), 文字, 回调) |
| 槽位变化回调 | .slotChanged((menu, level, player, handlers) => ...) |
| 自定义 Shift 移动 | .quickMoveFunc((player, slotIndex, menu) => ...) |
| 能否打开校验 | .validityFunc((player, pos) => true) |
| 隐藏玩家背包 | .disablePlayerInventory() |
| 自定义按键 | KeybindEvents.register(...) + new KeyBind(名, 键码, 分类) |
| 按键打开菜单 | MenuScreens.create('kubejs:菜单名', Minecraft.instance, 1000, Text.string('标题')) |
💡 记忆口诀:
registry('menu')造菜单 →addSlot放格子、addOutputSlot放输出、progressDrawable放条、button放按钮 →setBlock/setBlockEntity/setEntity绑定打开方式 → 右键目标就能用;要按键触发就用KeybindEvents+MenuScreens.create。
本文为 KubeJS 1.20.1 中文文档原创篇目。ScreenJS 为第三方附加组件,需单独安装(CurseForge 搜 screenjs)。