アクションフォームの使い方 / ActionFormData [Script API]

マイクラのアドオンを作成していると、プレイヤーに選択肢を選んでもらって処理を変えたくなる時があります(ありませんか?)。プレイヤーの選択によって処理を変えるために、Script APIには「フォーム」というものを表示させる機能があります。

その中でもアクションフォームは複数のボタンから1つを選択してもらうようなシンプルなフォームです。

アクションフォームを利用すれば、コマンドや特定の処理をボタンを押すだけで実行できるようになるため、アドオンの操作性が格段に上がります。

サンプルコードについて

サンプルコードはマインクラフト統合版1.19.70で動作確認をしております。(2023/03/21現在)

アクションフォームの使い方

アクションフォームは@minecraft/server-uiモジュールのActionFormDataクラスを利用することで作成および表示することができます。

基本的なフォームの作り方と表示方法は以下の通りです。

// ActionFormDataクラスをインポートする
import { ActionFormData } from "@minecraft/server-ui";

// ActionFormDataクラスをインスタンス化する
const actionForm = new ActionFormData();
// フォームに部品(タイトルやボタン)を追加する
actionForm.button("ボタン1");
// 
actionForm.show(/* プレイヤー */).then(res => {
  // フォームが選択された後の処理を記述する
});

アクションフォームには最低1個のボタンを追加しておく必要があります。

関連クラス

関連クラスは次の通りです。

クラス名概要リファレンス
ActionFormDataアクションフォームを組み立てるためのフォームビルダーを作成する。公式リファレンス
ActionFormResponseプレイヤーがアクションフォームの操作した結果のデータ。公式リファレンス

サンプルコード

特定のアイテムを使ったらアクションフォームを表示する

まずは何も機能を持たないアクションフォームを表示してみます。アクションフォームを含む各フォーム(メッセージフォーム、アクションフォーム、モーダルフォーム)は何かしらのイベントが発火したときに表示させることになりますので、ここではBeforeItemUseイベントを利用して棒(minecraft:stick)が使われた時にメッセージフォームを表示してみましょう。

import { world } from "@minecraft/server";
import { ActionFormData } from "@minecraft/server-ui";

world.events.beforeItemUse.subscribe(beforeItemUseEvent => {
  // アイテムを使ったエンティティがプレイヤー(minecraft:player)でなければ処理を抜ける
  if (beforeItemUseEvent.source.typeId !== "minecraft:player") {
    return;
  }

  // アクションフォームを表示するプレイヤーを変数に保存
  const player = beforeItemUseEvent.source;

  // アクションフォームを組み立てる
  const actionForm = new ActionFormData();
  actionForm.title("ここはタイトルです。");
  actionForm.body("ここはボディメッセージ部分です。");
  actionForm.button("0番目のボタン");
  actionForm.button("1番目のボタン", "textures/items/apple");
  actionForm.button("2番目のボタン", "textures/blocks/compost");
  actionForm.button("3番目のボタン", "textures/entity/steve");

  // アクションフォームを表示する
  actionForm.show(player).then(response => {
    if (response.canceled) {
      player.runCommandAsync("say キャンセルされました。");
    } else {
      player.runCommandAsync(`say ${response.selection} 番目のボタンが押されました!`);
    }
  });
});

これを実行すると次のようなフォームが表示されます。

ActionForm_1.jsの実行結果

アクションフォームのポイントは、次の3点かと思います。

  • アイコンを利用することができる
  • 押されたボタンの位置はActionFormResponse クラスのselectionプロパティでわかる
  • ボタンは0番目から開始する

なお、アイコンに指定できるのはリソースパックに含まれるものであればなんでもOKです。上記の例ではエンティティのテクスチャも使ってみました。(が、そのままの画像が表示されるのでスティーブが分解されています)

指定するアイコンのパスに関してですが、マイクラ標準のリソースパック(バニラリソースパック)を展開してtexturesフォルダを見てみるとたくさんのテクスチャが登録されていますので、それを参考にしてみてください。→ バニラリソースパック
もちろん自作のリソースパックのアイコンも使えます。

ボタンを押したらコマンドを実行する

先ほどはアクションフォームを表示しただけだったので、次はちゃんとした動作を入れてみます。ここではボタンに対応したコマンドとしてsummonコマンドを使ってモブを召喚してみたいと思います。

import { world } from "@minecraft/server";
import { ActionFormData } from "@minecraft/server-ui";

world.events.beforeItemUse.subscribe(beforeItemUseEvent => {
  // アイテムを使ったエンティティがプレイヤー(minecraft:player)でなければ処理を抜ける
  if (beforeItemUseEvent.source.typeId !== "minecraft:player") {
    return;
  }

  // アクションフォームを表示するプレイヤーを変数に保存
  const player = beforeItemUseEvent.source;

  // アクションフォームを組み立てる
  const actionForm = new ActionFormData();
  actionForm.title("モブ召喚");
  actionForm.body("召喚するモブを選んでください。");
  actionForm.button("羊を召喚", "textures/items/egg_sheep");
  actionForm.button("牛を召喚", "textures/items/egg_cow");
  actionForm.button("ニワトリを召喚", "textures/items/egg_chicken");

  // アクションフォームを表示する
  actionForm.show(player).then(response => {
    if (response.canceled) {
      player.runCommandAsync("say キャンセルされました。");
    } else {
      let target = "minecraft:sheep";
      if (response.selection === 0) {
        target = "minecraft:sheep";
      } else if (response.selection === 1) {
        target = "minecraft:cow";
      } else if (response.selection === 2) {
        target = "minecraft:chicken";
      }
      player.runCommandAsync(`summon ${target} ^ ^2 ^5`);
    }
  });
});

実行すると次のようなフォームが表示され、ボタンを押すとモブたちが召喚されます。

ActionForm_2.jsの実行例

まとめ

アクションフォーム(ActionFormDataクラス)の説明と、簡単な使用例について紹介してきました。プレイヤーに選択肢を与えてアクションを起こさせるアクションフォームを使えるようになると、お買い物システムやRPGの選択肢みたいな仕組みを作ることができますのでマルチでマイクラを楽しむときなんかに使ってみるといいかもしれません。メッセージフォーム(MessageFormDataクラス)の時と同様にshowメソッドがPromiseを返すので少々分かりにくいところもあるかもしれませんが、使っていくうちに少しずつ慣れると思いますので是非チャレンジしてみてください!きっとマイクラの幅が広がるはずです。