跳转至

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)。