在Minecraft BE中使用Scripting API!第二部分:显示自定义用户界面
首先/先生/起初我想解释一下关于用棒子敲击方块后会出现3个按钮,然后按下第三个按钮就会消失的脚本。由于文件结构稍微复杂,所以建议您下载页面底部的示例包。
准备本次添加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_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先生)
在手机上可能会有一部分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);
}
};
系统初始化
首先,在这个例子中,我们将使用一个名为minecraft:ui_event的事件来在client.js中使用。这个事件将在从html文件(这次是button.html)广播时被调用。
监听事件我在上次已经使用了这种方法来处理minecraft:ui_event并在this.onUIMessage中进行处理了,但这次我会使用另一种方法。
实际上,我们可以在第一个参数eventIdentifier中传入我们自定义的事件(例如本次是stick:loadui)。通过这种方式,我们可以注册一个JavaScript对象(例如本次是this.loadui),每当自定义事件被广播时就会被调用。
这是注册事件数据。通过使用这个,可以注册自定义事件(mcjixif:test的形式)。这次我们将注册stick:clientA, stick:clientB, stick:clientC。
系统加载用户界面这是之前在this.listenForEvent中注册的内容。当stick:loadui被广播时,将调用此内容。在这里,主要进行UI的设置。
加载活动数据的路径。这行代码指定了要读取的HTML文件。
加载EventData数据中的选项。通过这个进行UI的详细设置。总共有七个设置选项。(这次我们省略了说明。)
系统.onUIMessage在这里,我们将写下按钮被按下时的处理代码。我们将比较eventData与先前注册的事件(例如:stick:clickA),如果它们匹配,就会执行相应的处理步骤。
这个广播事件通过使用这个,将它广播到服务器端,使其正常运作。
Minecraft:卸载我想要将Button C按下时的UI隐藏的机制设置在这里,所以只需使用这个选项。
使用这个事件将先前显示的UI隐藏起来。通过指定路径进行广播来实现。
服务器.js编我想写一个使用相同的block_Interacted_with函数的处理过程,当使用棒子敲击方块时,它会产生动作。
实际上,我们可以在第一个参数eventIdentifier中传入我们自定义的事件(例如本次是stick:loadui)。通过这种方式,我们可以注册一个JavaScript对象(例如本次是this.loadui),每当自定义事件被广播时就会被调用。
这是注册事件数据。通过使用这个,可以注册自定义事件(mcjixif:test的形式)。这次我们将注册stick:clientA, stick:clientB, stick:clientC。
系统加载用户界面这是之前在this.listenForEvent中注册的内容。当stick:loadui被广播时,将调用此内容。在这里,主要进行UI的设置。
加载活动数据的路径。这行代码指定了要读取的HTML文件。
加载EventData数据中的选项。通过这个进行UI的详细设置。总共有七个设置选项。(这次我们省略了说明。)
系统.onUIMessage在这里,我们将写下按钮被按下时的处理代码。我们将比较eventData与先前注册的事件(例如:stick:clickA),如果它们匹配,就会执行相应的处理步骤。
这个广播事件通过使用这个,将它广播到服务器端,使其正常运作。
Minecraft:卸载我想要将Button C按下时的UI隐藏的机制设置在这里,所以只需使用这个选项。
使用这个事件将先前显示的UI隐藏起来。通过指定路径进行广播来实现。
服务器.js编我想写一个使用相同的block_Interacted_with函数的处理过程,当使用棒子敲击方块时,它会产生动作。
加载活动数据的路径。这行代码指定了要读取的HTML文件。
加载EventData数据中的选项。通过这个进行UI的详细设置。总共有七个设置选项。(这次我们省略了说明。)
系统.onUIMessage在这里,我们将写下按钮被按下时的处理代码。我们将比较eventData与先前注册的事件(例如:stick:clickA),如果它们匹配,就会执行相应的处理步骤。
这个广播事件通过使用这个,将它广播到服务器端,使其正常运作。
Minecraft:卸载我想要将Button C按下时的UI隐藏的机制设置在这里,所以只需使用这个选项。
使用这个事件将先前显示的UI隐藏起来。通过指定路径进行广播来实现。
服务器.js编我想写一个使用相同的block_Interacted_with函数的处理过程,当使用棒子敲击方块时,它会产生动作。
系统.onUIMessage在这里,我们将写下按钮被按下时的处理代码。我们将比较eventData与先前注册的事件(例如:stick:clickA),如果它们匹配,就会执行相应的处理步骤。
这个广播事件通过使用这个,将它广播到服务器端,使其正常运作。
Minecraft:卸载我想要将Button C按下时的UI隐藏的机制设置在这里,所以只需使用这个选项。
使用这个事件将先前显示的UI隐藏起来。通过指定路径进行广播来实现。
服务器.js编我想写一个使用相同的block_Interacted_with函数的处理过程,当使用棒子敲击方块时,它会产生动作。
Minecraft:卸载我想要将Button C按下时的UI隐藏的机制设置在这里,所以只需使用这个选项。
使用这个事件将先前显示的UI隐藏起来。通过指定路径进行广播来实现。
服务器.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;
};
旗帜
这个标记是为了让脚本判断UI是否显示所必需的。如果没有这个标记,可能会导致多个UI堆叠显示。如果显示了UI,就将其赋值为true,否则赋值为false。
系统初始化
监听此事件首先注册block_Interacted_with。这一部分不需要解释,因为和平常一样。
然后使用listenForEvent注册之前通过client的registerEventData注册的事件。在这里注册的javascript对象(例如this.onClickA)会在client接收到stick:clickA广播时被调用。
当系统与其交互在这里,我们将创建一个if语句,就像上一次一样,如果用minecraft:stick敲击,会变成〜。我们还要确保flag为false。
当物品是棍子并且flag为false时,我们将广播客户端注册的stick:loadui。这将调用client的system.loadui并显示ui。由于ui出现了,我们将flag设置为true。
系统.点击事件因为我已经在客户端上设置了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
}
}
可以参考的链接
脚本文档官方示例包
监听此事件首先注册block_Interacted_with。这一部分不需要解释,因为和平常一样。
然后使用listenForEvent注册之前通过client的registerEventData注册的事件。在这里注册的javascript对象(例如this.onClickA)会在client接收到stick:clickA广播时被调用。
当系统与其交互在这里,我们将创建一个if语句,就像上一次一样,如果用minecraft:stick敲击,会变成〜。我们还要确保flag为false。
当物品是棍子并且flag为false时,我们将广播客户端注册的stick:loadui。这将调用client的system.loadui并显示ui。由于ui出现了,我们将flag设置为true。
系统.点击事件因为我已经在客户端上设置了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
}
}
可以参考的链接
脚本文档官方示例包
当物品是棍子并且flag为false时,我们将广播客户端注册的stick:loadui。这将调用client的system.loadui并显示ui。由于ui出现了,我们将flag设置为true。
系统.点击事件因为我已经在客户端上设置了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
}
}
可以参考的链接
脚本文档官方示例包
<!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
}
}
可以参考的链接
脚本文档官方示例包
这次解说的内容是这个mcjixif样本包。