【統合版】ScriptAPI #4 アクションフォーム

スポンサーリンク

事前説明

こんにちは、さば2号です。

今回はScriptAPIのUIについて解説していきます。

事前準備、アドオンフォルダの作成、manifestの書き方は前回の解説をご覧ください。
【統合版】ScriptAPIでアドオンを作ってみよう #1 ダメージメッセージ

注意事項

・この記事は2024/03/26時点のものです。
・投稿者は素人です。間違えることがあります。

解説

ScriptAPIでは3つのフォームのUIを作成できます。
今回はボタンの選択肢を設定できる、ActionFormの解説をしていきます。

公式リファレンス ActionFormData Class

%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2024-03-27-180910-3.png

さっそくサンプルのフォームを作っていきましょう。

今回は次のようなフォームを作ります。

フォームを開く方法
・「フォームを開く」という棒のアイテムを使う

閉じられた(キャンセルされた)とき
・「キャンセルしました」とメッセージを送る

ボタンが押されたとき
・「〇番目のボタンを押しました」とメッセージを送る

%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2024-03-27-183624.png
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 ${response.selection}番目のボタンを押しました`);

} else { // キャンセルした場合
player.runCommand("say キャンセルしました");
}
});
}
});

サンプルコード:コマンドフォーム

今度は実用的なフォームを作ってみましょう。

フォームを開く方法
・「OP」タグを持っているプレイヤーが「コマンドフォーム」という棒のアイテムを使う

閉じられた(キャンセルされた)とき
・なにもしない

ボタンが押されたとき
・ボタンに応じてコマンドを実行する

%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2024-03-27-204101.png
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 開発初心者コミュニティ

参考にしたサイト
マイクラの泉

備忘録ブログ
さば2号のgametest(scriptAPI)備忘録

※投稿記事に含まれるファイルやリンクにより発生した被害についてクラフターズコロニーは責任を取りません
投稿通報

コメント

  1. 質問失礼します。こちらの記事を参考に、作ってみたのですが、フォームが表示されなくて、原因分かりますか?

    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 === … の終わりの括弧 }

  2. 一部コードを変更し、説明を加えました。

コメント通報