#はじめに
今回は棒でブロックを叩くと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のコード全体です
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_event
をthis.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
を使用してブロックを棒で叩いたら動作する処理を書きたいと思います。
↓が全体のコードになります
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
にします。
#その他ファイル
コメントで解説があるので省略します。手抜きですみません🙇🙏
<!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>
@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@common.base_screen": {
"always_accepts_input": true
}
}
#参考リンク
scriptingDocumentation
official samplePack
今回解説したものはこちらです。
mcjixif samplePack