8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

MinecraftBEでscriptingAPI!part2.自作uiを表示する

Last updated at Posted at 2019-11-03

#はじめに
今回は棒でブロックを叩くと3つのボタンが現れ、3つ目のボタンを押すと消える、というscriptを解説したいと思います。ファイル構成がやや複雑なのでページ下のサンプルパックをダウンロードすることをおすすめします。
#準備
今回はuiを追加するにあたって前回と違いいくつかのファイルを使用します。
client.js, server.jsに加えて button.html, button.css, hud_screen.jsonが必要になります。(今回はbuttonという名前をつけていますが、名前はなんでも大丈夫です)

リソースパック、ビヘイビアーパックのファイル構成は以下の通りになります。
your_resource
├ manifest.json
├ ui
│ └ hud_screen.json
└ experimental_ui
     └ button.html
     └ button.css

your_behavior
├ manifest.json
└ scripts
     ├ client
     │ └ client.js
     └ server
          └ server.js

今回はclient.js, server.js の2つの解説をしたいと思います。
###追記
win10だと中央の十字が表示されなくなるようです。原因と解決方法が分かり次第編集します。
uiオプションのloadEventData.data.options.is_showing_menu = true;にするとwin10でも正常に動作するようです。(情報提供buttonさん)
スマホだと1部uiが消えるので注意です。

#client.js編
前回扱ったserver.jsとは扱える内容が少し違います。前回使用したblock_Interacted_withはここでは使用できない、といったように使えるものと使えないものがあります。(逆にclient.jsでしか使えないものもあります。)

早速コードを見てみましょう。
↓のものがclient.jsのコード全体です

client.js
const system = client.registerSystem(0, 0);

system.initialize = function () {
   this.listenForEvent('minecraft:ui_event', (eventData) => this.onUIMessage(eventData));
   
   //指定イベントがブロードキャストされる毎に呼び出されるJavaScriptオブジェクトを登録
   this.listenForEvent('stick:loadui', (eventData) => this.loadui(eventData));
   
   //eventDataを登録
   
   this.registerEventData('stick:clickA', {});
   this.registerEventData('stick:clickB', {});
   this.registerEventData('stick:clickC', {});
};

system.loadui = function (eventData) {
   //uiのオプション
   var loadEventData = this.createEventData('minecraft:load_ui');
   loadEventData.data.path = 'button.html';
   loadEventData.data.options.always_accepts_input = false;
   loadEventData.data.options.is_showing_menu = false;
   loadEventData.data.options.absorbs_input = false;
   loadEventData.data.options.should_steal_mouse = true;
   loadEventData.data.options.force_render_below = true;
   loadEventData.data.options.render_only_when_topmost = true;
   loadEventData.data.options.render_game_behind = true;
   this.broadcastEvent('minecraft:load_ui', loadEventData);
};

//ボタンを押した時の処理
system.onUIMessage = function (eventData) {
   var BroadcastEventData = this.createEventData('minecraft:display_chat_event');
   
   if (!eventData.data) {
      return;
   }
   if (eventData.data === 'buttonAClicked') {
      //server側にブロードキャスト
      var clickEventDataA = this.createEventData('stick:clickA');
      this.broadcastEvent('stick:clickA', clickEventDataA);
      
      //チャットに'buttonA'と送る
      BroadcastEventData.data.message = 'buttonA';
      this.broadcastEvent('minecraft:display_chat_event', BroadcastEventData);
   }
   if (eventData.data === 'buttonBClicked') {
      //server側にブロードキャスト
      var clickEventDataB = this.createEventData('stick:clickB');
      this.broadcastEvent('stick:clickB', clickEventDataB);
      
      //チャットに'buttonB'と送る
      BroadcastEventData.data.message = 'buttonB';
      this.broadcastEvent('minecraft:display_chat_event', BroadcastEventData);
   }
   if (eventData.data === 'buttonCClicked') {
      //server側にブロードキャスト
      var clickEventDataC = this.createEventData('stick:clickC');
      this.broadcastEvent('stick:clickC', clickEventDataC);
      
      //ボタンを削除
      var unloadEventData = this.createEventData('minecraft:unload_ui');
      unloadEventData.data.path = 'button.html';
      this.broadcastEvent('minecraft:unload_ui', unloadEventData);
      
      //チャットに'buttonC'と送る
      BroadcastEventData.data.message = 'buttonC';
      this.broadcastEvent('minecraft:display_chat_event', BroadcastEventData);
   }
};

###system.initialize
まず、今回client.jsで使用するイベントはminecraft:ui_eventです。これはhtmlファイル(今回でいうbutton.html)からブロードキャストされたとき呼び出されるイベントです。
######this.listenForEvent
これを使用してminecraft:ui_eventthis.onUIMessageで扱えるようにするのと同様のことは前回やりましたが、今回はまた別の使い方もします。
実は第1引数であるeventIdentifierには自作のイベント(今回でいうstick:loadui)も入れることができます。これを利用し、自作イベントがブロードキャストされる毎に呼び出されるjsオブジェクト(今回でいうthis.loadui)が登録できます。
######this.registerEventData
これを使用する事で自作イベント(mcjixif:test の形)を登録する事が出来ます。今回はstick:clientA, stick:clientB, stick:clientCを登録します。

###system.loadui
これは先程this.listenForEventで登録したものになります。stick:loaduiがブロードキャストされた時に呼び出されます。
この中では主にuiの設定を行います。
######loadEventData.data.path
この1行により読み込まれるhtmlファイルを指定します。
######loadEventData.data.options
これでuiの細かい設定をします。設定は7つあります。(今回は説明を省きます。)

###system.onUIMessage
ここではボタンが押された時の処理を書きます。eventDataと先程登録したイベント(stick:clickAなど)を比較し、一致したら処理するという流れになります。
######this.broadcastEvent
これを使うことでserver側にブロードキャストし、動作するようにします。
######minecraft:unload
今回buttonCを押した時、uiを消すという仕組みにしたいのでここだけこれを使います。
このイベントを使用して先程出したuiを消します。pathを指定しブロードキャストする事で消えます。

#server.js編
今回も前回と同じくblock_Interacted_withを使用してブロックを棒で叩いたら動作する処理を書きたいと思います。

↓が全体のコードになります

server.js
const system = server.registerSystem(0, 0);

var flag = false;

system.initialize = function () {
   this.listenForEvent('minecraft:block_interacted_with', (eventData) => this.onInteractedWith(eventData));
   
   //clientでregisterしたイベントを登録
   this.listenForEvent('stick:clickA', eventData => this.onClickA(eventData));
   this.listenForEvent('stick:clickB', eventData => this.onClickB(eventData));
   this.listenForEvent('stick:clickC', eventData => this.onClickC(eventData));
};

system.onInteractedWith = function (eventData) {
   var handContainer = this.getComponent(eventData.data.player, 'minecraft:hand_container');
   var carriedItem = handContainer.data[0].item;

   if (carriedItem == 'minecraft:stick' && !flag) {
      //clientのstick:loaduiをブロードキャスト
      this.broadcastEvent('stick:loadui', eventData);
      flag = true;
   }
};

system.onClickA = function (eventData) { 
   //処理
};

system.onClickB = function (eventData) { 
   //処理
};

system.onClickC = function (eventData) { 
   flag = false;
};

###flag
これはuiが表示されているかどうかをscriptが判断する為に必要なフラグです。これが無ければ複数重ねて表示されてしまうこともあります。表示されていればtrue、されていなければfalseになるように代入します。

###system.initialize
######this.listenForEvent
まずblock_Interacted_withを登録します。これはいつも通りなので説明は省きます。
次に先程clientのregisterEventDataで登録したイベントをlistenForEventで登録します。ここで登録したjavascriptオブジェクト(今回でいうthis.onClickA)はclientでstick:clickAがブロードキャストされた時に呼び出されます。

###system.onInteractedWith
ここでは前回行ったようにminecraft:stickで叩いたら〜 となるようにif文を作ります。ここでflagがfalseになっていることも確認します。
持ち物が棒かつflagがfalseだった時、clientで登録したstick:loaduiをブロードキャストします。これによりclientのsystem.loaduiが呼び起こされuiが現れます。uiが現れたのでflagはtrueにします。

###system.onClickC
clientでuiが消えるようにしているのでflagはfalseにします。

#その他ファイル
コメントで解説があるので省略します。手抜きですみません🙇🙏

button.html
<!DOCTYPE html>
<html>

<head>
	<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
	<script src="../UIEngine.js"></script>
	<link rel="stylesheet" href="button.css" />
</head>

<body>
  <div class="parent">
    <button id="buttonA" class="child"></button>
    <button id="buttonB" class="child"></button>
    <button id="buttonC" class="child"></button>
  </div>
</body>
<script type="text/javascript">
let scriptInterface = null;
engine.on("facet:updated:core.scripting", function (interface) {
    scriptInterface = interface;
});

engine.trigger("facet:request", ["core.scripting"]);

//ボタンのidからエレメントオブジェクトを取得
let buttonA = document.getElementById("buttonA");
let buttonB = document.getElementById("buttonB");
let buttonC = document.getElementById("buttonC");

//clickを感知してclient側にブロードキャスト
let broadcastEvent = function (event) {
    scriptInterface.triggerEvent(event);
}
buttonA.addEventListener("click", function () {
    broadcastEvent("buttonAClicked");
});
buttonB.addEventListener("click", function () {
    broadcastEvent("buttonBClicked");
});
buttonC.addEventListener("click", function () {
    broadcastEvent("buttonCClicked");
});
</script>

</html>
button.css
@font-face {
  font-family: 'MinecraftTen';
  src: url(fonts/MinecraftTen.otf);
}
body {
  font-family: "MinecraftTen";
}
.parent {
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
  height: 100%;
  width: 100%;
  opacity: 0.7;
}
.child {
  height: 6%;
  width: 6%;
}
hud_screen.json
{
  "hud_screen@common.base_screen": {
    "always_accepts_input": true
  }
}

#参考リンク

scriptingDocumentation
official samplePack

今回解説したものはこちらです。
mcjixif samplePack

8
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?