【統合版】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 キャンセルしました");

            } else { // フォームをキャンセルしてない場合
                // 押したボタン番号を送る
                player.runCommand("say 押したボタン番号: " + response.selection);
            }
        });
    }
});

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

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

フォームを開く方法
・「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. 一部コードを変更し、説明を加えました。

  3. 質問です。
    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招待リンクは兄のです。

  4. import { world } from “@minecraft/server”;
    はなんの処理に使いますか?

  5. 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`);

      });
      }
      });

  6. フォームの選択肢のうちの一つを押すとさらにフォームが開くようにするにはどうしたらいいですか。
    名前などは特に指定しません

コメント通報