开启辅助访问     
收藏本站

站内搜索

搜索

Minecraft(我的世界)苦力怕论坛

[BE教程] Concepts of SAPI: Form & FormResponse

 发表于 2025-9-4 21:38:16|显示全部楼层|阅读模式 IP:北京
前言
表单(Form)是一种可供玩家操作的用户界面(UI),在SAPI中,表单则是一种承诺(Promise)对象。表单回执(FormResponse)则是表单兑现(fullfill)后的打包形式,玩家在表单上的操作最终会打包进表单回执当中。
讲述
《借由附加包开发可获得成就的地图!》中,我介绍了SAPI 1.0中的表单、表单属性和表单方法,以及SAPI 2.0中的部分表单方法。这里来详细讲讲SAPI 2.0中的表单和表单回执,毕竟还是要与时俱进。首先,表单和资源包内的JSONUI不同,JSONUI用的是游戏内接口,通常不方便开发者自定义参数,但是可以在资源包内设计JSONUI的元素,使其看起来更美观;而表单虽然只有几个固定的控件,但是它可以与SAPI脚本内的其他参数交互,这让玩家可以在游戏内对SAPI参数实时交互。接下来介绍,目前拥有的三种表单分对应其表单数据:消息表单数据(MessageFormData),行动表单数据(ActionFormData)和模拟表单数据(ModalFormData)。表单数据有一个共通的构造方法,就是new <Action|Message|Modal>FormData()。其中,消息表单数据的结构非常简单:
屏幕截图 2025-09-02 133547.png屏幕截图 2025-09-02 221758.png
只有四个设计方法(builder method),都是用来显示文字的。我们使用以下代码:
  1. import { world, system } from "@minecraft/server"
  2. import { MessageFormData } from "@minecraft/server-ui"
  3. world.afterEvents.playerJoin.subscribe(event => {
  4.   const player = world.getEntity(event.playerId)
  5.   var demo = new MessageFormData()
  6.   demo = demo.title("标题")
  7.     .body("整体注释")
  8.     .button1("第一个按钮")
  9.     .button2({translate: "第二个按钮"})//实际上,如果没有在语言文件定义替换的文本,就还会显示“第二个按钮”
  10.   system.runTimeout(() => {
  11.     demo.show(player)
  12.   }, 80)
  13. })
复制代码
这里方法后换行再接方法的方式其实是一种简写,完整的代码应该是这样的:
  1.   var demo = new MessageFormData()
  2.   demo.title("标题")
  3.   demo.body("整体注释")
  4.   demo.button1("第一个按钮")
  5.   demo.button2({translate: "第二个按钮"})
复制代码
只不过由于设计方法返回的还是消息表单数据类,所以可以一直在后面接设计方法。这样在玩家进入游戏4秒后就会弹出该表单,效果是这样的: 屏幕截图 2025-09-03 132522.png
看起来像是用的服务器消息的接口,在主界面退出游戏也会弹出类似的窗口。表单有一个共同的.show()方法,将返回各种表单回执,本质是兑现后的承诺对象,存在以下共通属性:
屏幕截图 2025-09-03 182008.png
这个canceled属性可以用来避免报错,因为如果表单被取消,表单回执就不会包括表单上的操作,所以有些表单回执的属性就不能读取,进而报错。我们来看消息表单回执(MessageFormResponse)的属性:
屏幕截图 2025-09-03 184207.png
一个属性就足够,消息表单是最简单的表单。我们继续使用以下代码:
  1. import { world, system } from "@minecraft/server"
  2. import { MessageFormData } from "@minecraft/server-ui"
  3. world.afterEvents.playerJoin.subscribe(event => {
  4.   const player = world.getEntity(event.playerId)
  5.   var demo = new MessageFormData()
  6.   demo = demo.title("标题")
  7.     .body("整体注释")
  8.     .button1("第一个按钮")
  9.     .button2({translate: "第二个按钮"})//实际上,如果没有在语言文件定义替换的文本,就还会显示“第二个按钮”
  10.   system.runTimeout(() => {
  11.     demo.show(player)
  12.       .then(response => {
  13.         if (response.canceled) {
  14.           player.sendMessage("你取消了表单")
  15.         } else {
  16.           player.sendMessage(response.selection === 0? "你选择了第一个按钮" : "你选择了第二个按钮")
  17.         }
  18.       })
  19.   }, 80)
  20. })
复制代码
就可以在聊天栏显示你对表单进行的操作了。接下来介绍行动表单数据。相比于消息表单数据,行动表单数据不局限于两个按钮,而是有不定的按钮可以选择,并且SAPI 2.0给它也加入了表头、标签和分隔线,它的设计方法如下: 屏幕截图 2025-09-03 222250.png屏幕截图 2025-09-04 110623.png屏幕截图 2025-09-04 111617.png
其中图标路径是表示图片在资源包内相对文件地址的字符串。而行动表单回执(ActionFormResponse)和消息表单回执一样,只有一个selection属性,于是我们可以这样设计表单:
  1. import { world, system } from "@minecraft/server"
  2. import { ActionFormData } from "@minecraft/server-ui"
  3. world.afterEvents.playerJoin.subscribe(event => {
  4.   const player = world.getEntity(event.playerId)
  5.   var demo = new ActionFormData()
  6.   demo = demo.title("标题")
  7.     .body("整体注释")
  8.     .header("表头")
  9.     .button("第一个按钮")
  10.     .button({translate: "第二个按钮"})
  11.     .divider()
  12.     .label("标签")
  13.     .button("第三个按钮", "textures/blocks/torchflower")
  14.     .button("第四个按钮", "pack_icon")
  15.   system.runTimeout(() => {
  16.     demo.show(player)
  17.       .then(response => {
  18.         if (response.canceled) {
  19.           player.sendMessage("你取消了表单")
  20.         } else {
  21.           player.sendMessage(`你选择了第${response.selection+1}个按钮`)
  22.         }
  23.       })
  24.   }, 80)
  25. })
复制代码

这是实机的效果:
屏幕截图 2025-09-04 162606.png屏幕截图 2025-09-04 162620.png
接下来就是最复杂的模拟表单数据,它的设计方法特别多: 屏幕截图 2025-09-04 163007.png屏幕截图 2025-09-04 164342.png屏幕截图 2025-09-04 164908.png屏幕截图 2025-09-04 165942.png屏幕截图 2025-09-04 191550.png
里面还提到了各种设置项,其实就是几个固定属性的对象,它们的属性都是可选的: 屏幕截图 2025-09-04 194840.png屏幕截图 2025-09-04 201515.png屏幕截图 2025-09-04 204112.png屏幕截图 2025-09-04 204739.png
另外还有模拟表单回执(ModalFormResponse)的属性: 屏幕截图 2025-09-04 205348.png
这里面说的控件(control)其实就对应相应的设计方法,另外要注意,即使文本框的默认值是原始文本类型,它在表单回执中读取时返回的是替换后的字符串,而不是原始文本;而且像分隔线、表头这样的控件,在formValues中读取的值是空(null)。然后我们可以设计以下表单:
  1. import { world, system } from "@minecraft/server"
  2. import { ModalFormData } from "@minecraft/server-ui"
  3. world.afterEvents.playerJoin.subscribe(event => {
  4.   const player = world.getEntity(event.playerId)
  5.   const draw = ["选项1", {translate: "选项2"}]
  6.   var demo = new ModalFormData()
  7.   demo = demo.title("标题")
  8.     .header("表头")
  9.     .label({translate: "标签"})
  10.     .toggle("开关", {defaultValue: false, tooltip: "开关小贴士"})
  11.     .slider("滑块", 0, 255, {defaultValue: 0, tooltip: {translate: "滑块小贴士"}, valueStep: 5})
  12.     .divider()
  13.     .dropdown("下拉列表", draw, {defaultValueIndex: 0, tooltip: "下拉列表小贴士"})
  14.     .textField("文本框", {translate: "文本框悬挂文字"}, {defaultValue: "默认文本", tooltip: "文本框小贴士"})
  15.     .submitButton("提交按钮显示文字")
  16.   system.runTimeout(() => {
  17.     demo.show(player)
  18.       .then(response => {
  19.         if (response.canceled) {
  20.           player.sendMessage("你取消了表单")
  21.         } else {
  22.           const list = response.formValues
  23.           player.sendMessage((list[2]?"你扳开了开关":"开关仍然关闭")+`,你将滑块滑至数值${list[3]},`+`你选择了下拉列表中的${draw[list[5]]},`+"这是你填写的文本:"+list[6])
  24.         }
  25.       })
  26.   }, 80)
  27. })
复制代码

然后是实机画面:
屏幕截图 2025-09-04 212951.png屏幕截图 2025-09-04 213001.png
总结
表单是许多SAPI附加包的必要组件,表单回执是玩家实时操纵脚本的通道。在这里我给借助附加包那个帖打一个小补丁,表单看起来是不会读取.json定义的文件地址缩写,本来想着行为包文件里都可以用,结果试验之后还是不能用。所以代码一定要到游戏里试验才可以啊!

评分

参与人数 3铁粒 +145收起理由
 采矿*** + 100很给力!
 小*** + 40推荐奖励
 幻溯*** + 5挺好的。

查看全部评分

苦力怕论坛,感谢有您~
 发表于 2025-9-8 02:07:23 来自手机|显示全部楼层 IP:湖北省
那个「Modal」应该翻译成「模态」而非「模拟」。
2#2025-9-8 02:07:23回复收起回复
苦力怕论坛,感谢有您~
回复支持

使用道具举报

 楼主|  发表于 2025-9-8 09:44:35|显示全部楼层 IP:北京
幻溯验劣 发表于 2025-9-8 02:07
那个「Modal」应该翻译成「模态」而非「模拟」。

“模态”指的是模式+状态的对应关系;“模拟”这个词算是我最早做翻译留下来的习惯译法吧,那个时候管这一类表单都叫“模拟表单”,模拟表单就是这么来的。我是觉得模态这个词不太好理解,跟那个行动表单一样,我觉得应该叫选择表单更符合这个表单的特性。还是按英文的原文标注来看吧,翻译是什么能对应上就好
3#2025-9-8 09:44:35回复收起回复
苦力怕论坛,感谢有您~

本版积分规则

本站
关于我们
联系我们
坛史纲要
官方
哔哩哔哩
技术博客
下载
网易版
安卓版
JAVA
反馈
意见建议
教程中心
更多
捐助本站
QQ群
QQ群

QQ群

访问手机版

访问手机版

手机版|小黑屋|系统状态|klpbbs.com

| 由 木韩网络 提供支持 | GMT+8, 2026-2-3 04:51

声明:本站与Mojang以及微软公司没有从属关系

Powered by Discuz! X3.4