UID 1595448 性别 保密 经验 EP 铁粒 粒 回帖 0 主题 精华 在线时间 小时 注册时间 2024-2-16 最后登录 1970-1-1
本帖最后由 星空晶体 于 2024-11-30 22:06 编辑 由于本人对Script API不是非常了解,所以本教程可能会出现遗漏或出错,欢迎进行反馈。授权协议请查看帖子最后
Server UI 教程 做一个由 SAPI 制作的游戏内UI!
前言
Server UI 是 Script API 中的一个库,可以在游戏里创建菜单、表单等 UI。它的出现使 Script API 变得更加有创造性,你可以将此功能用到 Script API 的各种地方,例如雪球(时钟)菜单、触发事件的自定义组件或其他。本教程将告诉大家什么是 ActionFormData、MessageFormData 与 ModalFormData 以及它们的使用方法。本人对 Script API 并不过于全知,所以可能会有遗漏,欢迎进行提醒。如何使用 Server UI
第一个问题来了,我们怎么来使用 Script API 以及 Server UI库呢?
打开行为包文件夹,打开附加包清单文件 manifest.json ,在 modules 数组以下,添加 dependencies 数组,dependencies 这样写:"dependencies": [ { "module_name": "@minecraft/server", "version": "xxx" }, { "module_name": "@minecraft/server-ui", "version": "xxx" } ] 复制代码
module_name 是库的名字,version 是库的版本,@minecraft/server-ui 就是 Server UI 的库名。截止到目前,@minecraft/server 的最新版本是1.15.0,@minecraft/server-ui 的最新版本是 1.3.0。若想要查看这两个库名的最新版本,可以去https://www.npmjs.com/package/@minecraft/server https://www.npmjs.com/package/@minecraft/server-ui
查看
完整的清单文件是这样的:{ "format_version": 2, "header": { "name": "名称", "description": "介绍", "uuid": "自行填写", "version": [ 0, 0, 1 ], "min_engine_version": [ x, x, x ] }, "modules": [ { "type": "script", "language": "javascript", "uuid": "自行填写", "entry": "scripts/xxx.js",//自行选择xxx部分 "version": [ 0, 0, 1 ] } ], "dependencies": [ { "module_name": "@minecraft/server", "version": "1.15.0" }, { "module_name": "@minecraft/server-ui", "version": "1.3.0" } ] } 复制代码
在行为包的 script 文件夹,在JS文件中写入import { ActionFormData, MessageFormData, ModalFormData } from "@minecraft/server-ui" 复制代码
接下来将讲解三个 UI 是什么,不再赘述 Script API 其他内容。ActionFormData
此 UI 相当于一个菜单,在游戏里显示为以下:BBCode 表格无法完全清楚显示 ActionFormData UI ,请参考游戏内
写法:function Functionname(player) { const Test = new ActionFormData() .title(``) .body(``) .button(``) .button(``) .button(``) .show(player) .then((Test) => { }) } 复制代码 代码讲解
▪const Test = new ActionFormData() 此代码是创建 ActionFormData UI 的语句,Test 是这个 ActionFormData 对象的名字,可替换为其他名字。
▪.title(``) 菜单最上面的标题,可见上方图例。
▪.body(``) 菜单中靠上的简介部分,可见上方图例。
▪.button(``) 菜单的按钮部分,可见上方图例。还可以写为 .button(``, `textures/...`) ,后者资源包的 textures 图片路径指定按钮左旁的图片。可多个添加。
▪
.show(player)
.then((Test) => {
}
展现给玩家的语句,在里面括号里写入当点击按钮时会发生什么。这里使用IF语句if (Test.selection == 0) { ... } 复制代码 里面的其他函数以及其他的这是当点击按钮1时会执行的 ,如果 Test.selection 为1,就是第2个按钮点击后发生的。以此类推。
可以执行另一个 UI 函数,也可以执行命令。使用 player.runCommand ,比如:player.runCommand(`effect ${player.nameTag} instant_health 99999 255 true`) 复制代码 ModalFormData
此 UI 相当于一个表单,里面内含输入框、下拉栏、滑动栏、拉杆。
在游戏里显示如下:BBCode 表格无法完全清楚显示 ModalFormData UI ,请参考游戏内
写法:function Functionname(player) { const Test = new ModalFormData() .title(``) .textField(``,``) .toggle(``,true) .dropdown(``,[``,``,``,``],0) .slider(``,0,64,1,32)//不要在意这些数字 .show(player) .then((Test) => { if (xxx.formValues[0] == xxx) { ... } else { ... } }) } 复制代码 代码讲解
▪.textField(``,``) 输入框,前者反引号为输入框上面的输入文字,后者为输入框里面的提醒文字。
▪.toggle(``,true) 前者反引号是拉杆选项是文字,后者布尔值是默认为开还是关。true 是默认为打开,false 是默认不打开。
▪.dropdown(``,[``,``,``,``],0) 下拉栏,前者反引号是下拉栏说明,中间的数组下拉栏内容,也是用反引号为一个,内容直接用英文逗号隔开。最后的数字是下拉栏默认的内容,0 是 第一个,1 是 第二个,以此类推。
▪.slider(``,,,,) 滑动条,这样写:.slider(`滑动条名字`,最小值,最大值,分度值,默认值) 复制代码 分度值是每次滑动一次时会滑动多少。比如最大值为10,分度值为2,每次滑动数值都会滑动±2,从开头/结尾滑动5次就会拉到头。默认值是设置滑动条的默认数值。如何获取表单内容进行判断: 如果有的表单内容需要判断,要获取一个部分的值并判断,写为以下代码if (Test.formValues[0] == xxx) { ... } else { ... } 复制代码 Test.formValues[0] == xxx 是索引值为某一数值、字符串或布尔值的判断部分。当点击提交,就会安装IF语句里执行其他内容。MessageFormData
此 UI 相当于一个弹窗,在游戏里显示如下:BBCode 表格无法完全清楚显示 MessageFormData UI ,请参考游戏内
写法function Functionname(player) { const Test = new MessageFormData() .title(`标题`) .body(``) .button(``) .button(``) .show(player) .then((Test) => { if (Test.selection == 0) { ... } if (Test.selection == 1) { ... } }) } 复制代码
弹窗有两个按钮,当点击第一个按钮后执行第一个IF语句内容,第二个同理。
▪.body(``) 弹窗内容实例 下面内容 来自我的资源帖子 [原创][1.21.2+][Script API][测试插件]雪球游戏菜单-2 import { world, system } from "@minecraft/server" import { ActionFormData, MessageFormData, ModalFormData } from "@minecraft/server-ui" world.beforeEvents.itemUseOn.subscribe((event) => { const huchu = event.itemStack const player = event.source if (huchu.typeId == `minecraft:snowball`) system.run(() => Action(player)) }) function Action(player) { const Action = new ActionFormData() .title(`SAPI测试2|作者KLPBBS星空晶体`) .body(`下方测试`) .button(`时间设置`) .button(`效果设置`) .button(`清除设置`) .button(`矿物给予`) .button(`当前位置设置重生点`) .button(`游戏模式`) .show(player) .then((Action) => { if (Action.selection == 0) { timeshzh(player) } if (Action.selection == 1) { effectshzh(player) } if (Action.selection == 2) { killshzh(player) } if (Action.selection == 3) { oregiving(player) } if (Action.selection == 4) { player.runCommand(`setworldspawn`) player.onScreenDisplay.setActionBar({"rawtext":[{"text":`已设置重生点`}]}) } if (Action.selection == 5) { mode(player) } }) } function timeshzh(player) { const timeshzh = new ActionFormData() .title(`时间设置`) .body(`下方设置`) .button(`日出`) .button(`白天`) .button(`正午`) .button(`傍晚`) .button(`夜晚`) .button(`午夜`) .show(player) .then((timeshzh) => { if (timeshzh.selection == 0) { player.runCommand(`time set sunrise`) player.onScreenDisplay.setActionBar({"rawtext":[{"text":`时间: 日出`}]}) } if (timeshzh.selection == 1) { player.runCommand(`time set day`) player.onScreenDisplay.setActionBar({"rawtext":[{"text":`时间:白日`}]}) } if (timeshzh.selection == 2) { player.runCommand(`time set noon`) player.onScreenDisplay.setActionBar({"rawtext":[{"text":`时间:中午`}]}) } if (timeshzh.selection == 3) { player.runCommand(`time set sunset`) player.onScreenDisplay.setActionBar({"rawtext":[{"text":`时间: 傍晚`}]}) } if (timeshzh.selection == 4) { player.runCommand(`time set night`) player.onScreenDisplay.setActionBar({"rawtext":[{"text":`时间: 夜晚`}]}) } if (timeshzh.selection == 5) { player.runCommand(`time set midnight`) player.onScreenDisplay.setActionBar({"rawtext":[{"text":`时间: 正夜`}]}) } }) } function effectshzh(player) { const effectshzh = new ModalFormData() .title(`药水效果`) .toggle(`瞬间治疗`,false) .toggle(`夜视`,false) .toggle(`饱和`,false) .toggle(`抗性`,false) .toggle(`生命恢复`,false) .toggle(`速度`,false) .toggle(`水下呼吸`,false) .toggle(`力量`,false) .toggle(`隐身`,false) .toggle(`跳跃增强`,false) .toggle(`急迫`,false) .toggle(`抗火`,false) .show(player) .then((effectshzh) => { if (effectshzh.formValues[0] == true) { player.runCommand(`effect ${player.nameTag} instant_health 99999 255 true`) } if (effectshzh.formValues[1] == true) { player.runCommand(`effect ${player.nameTag} night_vision 99999 255 true`) } if (effectshzh.formValues[2] == true) { player.runCommand(`effect ${player.nameTag} saturation 99999 255 true`) } if (effectshzh.formValues[3] == true) { player.runCommand(`effect ${player.nameTag} resistance 99999 255 true`) } if (effectshzh.formValues[4] == true) { player.runCommand(`effect ${player.nameTag} regeneration 99999 255 true`) } if (effectshzh.formValues[5] == true) { player.runCommand(`effect ${player.nameTag} speed 99999 10 true`) } if (effectshzh.formValues[6] == true) { player.runCommand(`effect ${player.nameTag} water_breathing 99999 255 true`) } if (effectshzh.formValues[7] == true) { player.runCommand(`effect ${player.nameTag} strength 99999 255 true`) } if (effectshzh.formValues[8] == true) { player.runCommand(`effect ${player.nameTag} invisibility 99999 255 true`) } if (effectshzh.formValues[9] == true) { player.runCommand(`effect ${player.nameTag} fire_resistance 99999 255 true`) } if (effectshzh.formValues[10] == true) { player.runCommand(`effect ${player.nameTag} jump_boost 99999 10 true`) } if (effectshzh.formValues[11] == true) { player.runCommand(`effect ${player.nameTag} haste 99999 10 true`) } }) } function killshzh(player) { const killshzh = new ActionFormData() .title(`清除目标选择`) .button(`清除随机玩家(需多人)`) .button(`清除所有玩家`) .button(`清除所有实体`) .button(`清除命令执行者`) .button(`清除所有掉落物`) .button(`清除X半径范围中的所有实体`) .button(`清除特定实体`) .button(`自定义清除(需有选择器基础)`) .show(player) .then((killshzh) => { if (killshzh.selection == 0) { player.runCommand(`kill @r`) } if (killshzh.selection == 1) { player.runCommand(`kill @a`) } if (killshzh.selection == 2) { player.runCommand(`kill @e`) } if (killshzh.selection == 3) { reallykill(player) } if (killshzh.selection == 4) { player.runCommand(`kill @e[type=item]`) } if (killshzh.selection == 5) { mkill1(player) } if (killshzh.selection == 6) { mkill2(player) } if (killshzh.selection == 7) { mkill3(player) } }) } function reallykill(player) { const reallykill = new MessageFormData() .title(`确认操作`) .body(`[谨慎选择]是否清除命令执行者本身\n如果您是玩家,请确保开了保留物品栏以不会丢失雪球`) .button(`是的`) .button(`不是[我误点/我反悔]`) .show(player) .then((reallykill) => { if (reallykill.selection == 0) { player.runCommand(`kill @e`) } if (reallykill.selection == 1) { killshzh(player) } }) } function mkill1(player) { const mkill1 = new ModalFormData() .title(`清除特定半径范围中的实体`) .textField(`请输入半径范围`,`输入一个整数`) .toggle(`不包括玩家`,true) .show(player) .then((mkill1) => { if (mkill1.formValues[1] == true) { player.runCommand(`kill @e[type=!player,r=${mkill1.formValues[0]}]`) } else { player.runCommand(`kill @e[r=${mkill1.formValues[0]}]`) } }) } function mkill2(player) { const mkill2 = new ModalFormData() .title(`清除特定实体`) .textField(`请输入半径范围`,`若不想设置范围,请填0`) .textField(`请输入实体ID`,`可省略minecraft前缀`) .show(player) .then((mkill2) => { if (mkill2.formValues[0] == 0) { player.runCommand(`kill @e[type=${mkill2.formValues[1]}]`) } else { player.runCommand(`kill @e[type=${mkill2.formValues[1]},r=${mkill2.formValues[0]}]`) } }) } function mkill3(player) { const mkill3 = new ModalFormData() .title(`自定义清除实体`) .textField(`请输入`,`注:开头必须有那个斜杠`) .toggle(`这个是没有用的`,false) .show(player) .then((mkill3) => { if (mkill3.formValues[1] == false) { player.runCommand(`${mkill3.formValues[0]}`) } else { player.runCommand(`${mkill3.formValues[0]}`) } }) } function oregiving(player) { const oregiving = new ModalFormData() .title(`矿物给予`) .slider(`铁矿石`,0,64,1,32)// .slider(`滑动条`,最小值,最大值,分度值,默认值) .slider(`金矿石`,0,64,1,32) .slider(`煤矿石`,0,64,1,32) .slider(`青金石矿石`,0,64,1,32) .slider(`绿宝石矿石`,0,64,1,32) .slider(`钻石矿石`,0,64,1,32) .slider(`红石矿石`,0,64,1,32) .slider(`铜矿石`,0,64,1,32) .show(player) .then((oregiving) => { player.runCommand(`give ${player.nameTag} iron_ore ${oregiving.formValues[0]}`) player.runCommand(`give ${player.nameTag} gold_ore ${oregiving.formValues[1]}`) player.runCommand(`give ${player.nameTag} coal_ore ${oregiving.formValues[2]}`) player.runCommand(`give ${player.nameTag} lapis_ore ${oregiving.formValues[3]}`) player.runCommand(`give ${player.nameTag} emerald_ore ${oregiving.formValues[4]}`) player.runCommand(`give ${player.nameTag} diamond_ore ${oregiving.formValues[5]}`) player.runCommand(`give ${player.nameTag} redstone_ore ${oregiving.formValues[6]}`) player.runCommand(`give ${player.nameTag} copper_ore ${oregiving.formValues[7]}`) }) } function mode(player) { const mode = new ModalFormData() .title(`游戏模式`) .dropdown(`模式选择`,[`生存`,`创造`,`冒险`,`旁观`],0) .show(player) .then((mode) => { if (mode.formValues[0] == `生存`) { player.runCommand(`gamemode survival`) } else if (mode.formValues[0] == `创造`){ player.runCommand(`gamemode creative`) } else if (mode.formValues[0] == `冒险`) { player.runCommand(`gamemode adventure`) } else { player.runCommand(`gamemode spectator`) } }) } 复制代码
以上内容包括本教程帖的所有内容,可进行参考。
可去
原帖找到资源进行改编 。本人表示欢迎。
结语
感谢您观看本教程,本教程共花费了本人几个小时的编写。包括查阅资料、文字编写已经BBCode排版。这也是本人第一次写这样体量的教程,若有遗失欢迎补充。感谢支持,愿大家制作自己的作品,让Minecraft论坛社区变得更好!
帖子信息
星 空 抚 吾 梦 , 晶 体 映 吾 心 。 青 年 应 有 梦 , 破 浪 乘 舟 行 !
评分
查看全部评分