事前説明
こんにちは、さば2号です。
今回はScriptAPIのUIについて解説していきます。
事前準備、アドオンフォルダの作成、manifestの書き方は前回の解説をご覧ください。
【統合版】ScriptAPIでアドオンを作ってみよう #1 ダメージメッセージ
注意事項
・この記事は2024/03/26時点のものです。
・投稿者は素人です。間違えることがあります。
解説
ScriptAPIでは3つのフォームのUIを作成できます。
今回はボタンの選択肢を設定できる、ActionFormの解説をしていきます。
公式リファレンス ActionFormData Class
さっそくサンプルのフォームを作っていきましょう。
今回は次のようなフォームを作ります。
フォームを開く方法
・「フォームを開く」という棒のアイテムを使う
閉じられた(キャンセルされた)とき
・「キャンセルしました」とメッセージを送る
ボタンが押されたとき
・「〇番目のボタンを押しました」とメッセージを送る
import { world } from "@minecraft/server";
// フォームのインポート
import { ActionFormData, MessageFormData, ModalFormData } from "@minecraft/server-ui";
// アイテムを使用すると起動
world.afterEvents.itemUse.subscribe(ev => {
// 定数「player」にアイテム使用者(ev.source)を代入
const player = ev.source;
const itemStack = ev.itemStack;
// アイテムの種類が棒(minecraft:stick) かつ アイテムの名前が「フォームを開く」の場合
if (itemStack.typeId === "minecraft:stick" && itemStack.nameTag === "フォームを開く") {
// アクションフォームのを生成
const form = new ActionFormData();
// フォームの設定
form.title("タイトル");
form.body("ボディ");
// ボタンの追加
form.button("0番目のボタン");
form.button("1番目のボタン");
form.button("2番目のボタン", "textures/items/apple");
form.button("3番目のボタン", "textures/blocks/stone");
// フォームをプレイヤーに表示
form.show(player).then(response => {
// ここから下はフォームが送信される または フォームが閉じられると処理が始まる
// response - フォームの結果のデータ
// response.canceled - フォームをキャンセルした(閉じた)かどうか
// response.selection - 押したボタンの番号 (0から始まる)
if (response.canceled) { // キャンセルした場合
player.runCommand("say キャンセルしました");
} else { // フォームをキャンセルしてない場合
// 押したボタン番号を送る
player.runCommand("say 押したボタン番号: " + response.selection);
}
});
}
});
サンプルコード:コマンドフォーム
今度は実用的なフォームを作ってみましょう。
フォームを開く方法
・「OP」タグを持っているプレイヤーが「コマンドフォーム」という棒のアイテムを使う
閉じられた(キャンセルされた)とき
・なにもしない
ボタンが押されたとき
・ボタンに応じてコマンドを実行する
import { world } from "@minecraft/server";
import { ActionFormData, MessageFormData, ModalFormData } from "@minecraft/server-ui";
world.afterEvents.itemUse.subscribe(ev => {
const player = ev.source;
const itemStack = ev.itemStack;
// アイテムの種類が棒(minecraft:stick) かつ アイテムの名前が「コマンドフォーム」の場合
if (itemStack.typeId === "minecraft:stick" && itemStack.nameTag === "コマンドフォーム") {
// プレイヤーがopタグを持っていたら
if (player.hasTag("op")) {
// フォームの生成と設定
const form = new ActionFormData();
form.title("コマンドフォーム");
form.button("アドベンチャーに変更");
form.button("クリエイティブに変更");
form.button("ロビーにTP (0,0,0)");
form.button("アイテムクリア");
// フォームをプレイヤーに表示
form.show(player).then(response => {
// response.canceled - フォームをキャンセルした(閉じた)かどうか
// response.selection - 押したボタンの番号 (0から始まる)
// フォームをキャンセルしていない場合
if (!response.canceled) {
// 選んだボタンによってコマンドを実行する
// <Player>.runCommand("command") - プレイヤーがコマンドを実行する
if (response.selection === 0) { // 0のとき
player.runCommand("gamemode a @s");
} else if (response.selection === 1) { // 1のとき
player.runCommand("gamemode c @s");
} else if (response.selection === 2) { // 2のとき
player.runCommand("tp @s 0 0 0");
} else { // 3のとき
player.runCommand("clear @s");
}
}
});
// タグを持っていない場合
} else {
// <Player>.sendMessage("message") - プレイヤーにメッセージを送る
player.sendMessage("opタグを持っていません。");
}
}
});
サンプルコード:コマンドフォーム(async/await,メソッドチェーン,switchを使用する場合)
これは上で作ったコマンドフォームを、さらに簡略化したプログラムです。
import { world, system } from "@minecraft/server";
import { ActionFormData, MessageFormData, ModalFormData } from "@minecraft/server-ui";
world.afterEvents.itemUse.subscribe(ev => {
const player = ev.source; const itemStack = ev.itemStack;
if (itemStack.typeId === "minecraft:stick" && itemStack.nameTag === "コマンドフォーム") {
if (player.hasTag("op")) {
showCommandForm(player);
} else {
player.sendMessage("opタグを持っていません");
}
}
});
// コマンドフォームを表示する関数
async function showCommandForm(player) {
// メソッドチェーンでまとめて定義
const form = new ActionFormData()
.title("コマンドフォーム")
.button("アドベンチャーに変更")
.button("クリエイティブに変更")
.button("ロビーにTP (0,0,0)")
.button("アイテムをクリア");
// フォームの表示と結果の代入
const res = await form.show(player);
// もしキャンセルされていたら、return;で処理を終了する
if (res.canceled) return;
// 押されたボタンに応じてコマンドを実行
switch (res.selection) {
case 0:
player.runCommand("gamemode a @s");
break;
case 1:
player.runCommand("gamemode c @s");
break;
case 2:
player.runCommand("tp @s 0 0 0");
break;
case 3:
player.runCommand("clear @s");
break;
}
}
参考URL
公式リファレンス
minecraft/server Module | Microsoft Learn
ディスコードサーバー
Script API 開発初心者コミュニティ
参考にしたサイト
マイクラの泉
コメント
質問失礼します。こちらの記事を参考に、作ってみたのですが、フォームが表示されなくて、原因分かりますか?
import { world } from “@minecraft/server”;
import { ActionFormData, MessageFormData, ModalFormData } from “@minecraft/server-ui”;
world.afterEvents.itemUse.subscribe(ev => {
const player = ev.source;
const itemStack = ev.itemStack;
// アイテムの種類がコンパス(minecraft:compass) の場合
if (itemStack.typeId === “minecraft:compass”) {
const form = new ActionFormData();
form.title(“§l§bServer menu”);
form.button(“§l§aback to lobby”);
// フォームの表示
form.show(player).then(response => {
if (response.canceled === false) {
// 選んだボタンによってコマンドを実行する
if (response.selection === 0) {
player.runCommand(“tp @s 0 1 0 0 0”);
}
}
});
コンテンツ ログに[main.js] run with error: [SyntaxError: unexpected token in expression: “ at main.js:23 とエラーが出ています。
返信お願いします。
返信してください。お願いします。
次の括弧がないためエラーとなっているようです。
4行目のsubscribe(ev => { の終わりの括弧 });
9行目のif (itemStack.typeId === … の終わりの括弧 }
一部コードを変更し、説明を加えました。
質問です。
entity(tag付きまたは名前)を殴ると発火(フォームが開く)はできますか?
entityは任意
tagまたは名前も任意
でできますか?
entityhitがなんちゃらコンチャら(?)をするのかな(?)
もしかして”
// エンティティがダメージを与えたときに起動するイベント
world.afterEvents.entityHurt.subscribe(ev => {
// ダメージを与えたエンティティを定数「entity」に代入
const entity = ev.damageSource.damagingEntity
// もし「entity」の種族がプレイヤーなら
if (entity.typeId === “minecraft:player”) {
ここにフォーム開く処理コード?}
});”??
でもentity指定方法が分からない…
可能です。
もし詳しいプログラムを知りたい場合は、次のディスコードサーバーにて質問することをお勧めします。
https://discord.gg/88AduKQ9j4
私はdiscord使用年齢にたっしていません…
おっと 忘れてました。
僕のアカウントの説明(?)のところにあるdiscord招待リンクは兄のです。
import { world } from “@minecraft/server”;
はなんの処理に使いますか?
import { world } from “@minecraft/server”;
// フォームのインポート
import { ActionFormData, MessageFormData, } from “@minecraft/server-ui”;
// アイテムを使用すると起動
world.afterEvents.itemUse.subscribe(ev => {
// 定数「player」にアイテム使用者(ev.source)を代入
const player = ev.source;
const itemStack = ev.itemStack;
// アイテムの種類が棒(minecraft:stick) かつ アイテムの名前が「フォームを開く」の場合
if (itemStack.typeId === “minecraft:stick” && itemStack.nameTag === “フォームを開く”) {
const form = new ActionFormData();
// フォームの設定
form.title(“ショップ”);
form.body(“ボディ”);
// ボタンの追加
form.button(“ガラス”,”textures/bloks/glass”);
form.button(“1番目のボタン”);
form.button(“2番目のボタン”);
form.button(“3番目のボタン”);
// アクションフォームを表示する
actionForm.show(player).then(response => {
else {
let target = “minecraft:glass”;
if (response.selection === 0) {
target = “minecraft:glassa”;
} else if (response.selection === 1) {
target = “minecraft:cow”;
} else if (response.selection === 2) {
target = “minecraft:chicken”;
}
player.runCommandAsync(`give @p ${target} 16`);
}
}
}
ボタン1以外キニシナイキニシナイ
さて私は答えが来るまでお昼寝します。
このコードは間違ってますか?
友達がこれでフォームが開けないと行っているんです。
manifestは
{
“format_version”: 2,
“header”: {
“name”: ” 秘密 “,
“description”: “秘密”,
“uuid”: “fa4fbacb-fbb2-4123-b2d1-c3d834cd30c9”,
“version”: [1, 28, 0],
“min_engine_version”: [1, 21, 20]
},
“modules”: [
{
“type”: “data”,
“uuid”: “1fa5ac6d-43b2-4f61-b4f3-b417f9438037”,
“version”: [1, 28, 0]
},
{
“type”: “script”,
“language”: “javascript”,
“uuid”: “4587bdeb-ce4f-444f-b934-76e1eea4eb20”,
“entry”: “scripts/main.js”,
“version”: [1, 28, 0]
}
],
“dependencies”: [
{
“module_name”: “@minecraft/server”,
“version”: “1.14.0-beta”
},
{
“module_name”: “@minecraft/server-ui”,
“version”: “1.3.0-beta”
}
]
}
です。
答えが来るまでコーヒーでも飲んでのんびり待ちます。
・いくつか終わりの ) がありません
・不要な else { があります
・targetに代入されるアイテムIDにミスがあります、minecraft:glassa(おそらくglass)、minecraft:cow(おそらくbeef)
ーーーーーーーーーーーーーーーーーーーーーーーーーーーー
// アイテムを使用すると起動
world.afterEvents.itemUse.subscribe(ev => {
// 定数「player」にアイテム使用者(ev.source)を代入
const player = ev.source;
const itemStack = ev.itemStack;
// アイテムの種類が棒(minecraft:stick) かつ アイテムの名前が「フォームを開く」の場合
if (itemStack.typeId === “minecraft:stick” && itemStack.nameTag === “フォームを開く”) {
const form = new ActionFormData();
// フォームの設定
form.title(“ショップ”);
form.body(“ボディ”);
// ボタンの追加
form.button(“ガラス”, “textures/bloks/glass”);
form.button(“1番目のボタン”);
form.button(“2番目のボタン”);
form.button(“3番目のボタン”);
// アクションフォームを表示する
actionForm.show(player).then(response => {
let target = “minecraft:glass”;
if (response.selection === 0) {
target = “minecraft:glass”;
} else if (response.selection === 1) {
target = “minecraft:beef”;
} else if (response.selection === 2) {
target = “minecraft:chicken”;
}
player.runCommandAsync(`give @p ${target} 16`);
});
}
});
フォームの選択肢のうちの一つを押すとさらにフォームが開くようにするにはどうしたらいいですか。
名前などは特に指定しません