【Minecraft BE Addon講座#15】利用脚本的实例~尝试制作击杀计数器~

本页面是插件教程第15课,名为“脚本篇,脚本的应用示例”。
请查看目次或者关于这个教程的第1篇文章。

希望你能理解脚本编写时所要考虑的事情!

2022年4月19日のアップデート、Minecraft 1.18.30(Bedrock)(ベータ版では2022年1月27日のMinecraft Beta 1.18.20.21)をもって ScriptingAPIは削除されました。
本Addon講座#14、#15で解説されているScriptingAPIは、これ以降のバージョンで使用できません。
スクリプトの実行は、代わりにGameTestFrameworkが担っていくようです。

脚本API目前只能在Minecraft Bedrock Edition for Windows10(俗称“win10版”)上运行。(曾经)
如果不满足条件,不能在iOS版、Android版等上运行,请注意。
有关此限制以及应对此限制的详细信息,请参阅#14“服务器与客户端的区别”。

脚本编程与该插件教程中的其他应用编程有所不同,它不是使用.json文件,而是使用Javascript。 在应用编程中,它更偏向于高级发展程度。
然而,对于那些稍微接触过Javascript的人来说,脚本编程可能会感觉更容易。

脚本编写共有2页,前半部分#14涉及到脚本的写作方式(语法)和结构的理解,后半部分#15将演示如何实际制作插件。

このスクリプト編では、Javascriptを使うことで、.jsonなどの限られた機能だけではできなかった検知や、それを利用したシステムの製作ができるようになることを目的としています。

    • (前提#3~#4)基礎編

 

    • (前提#8)ファンクション編復習、コマンドの実行主の理解

 

    • (#14)ScriptingAPIとは?

 

    • (#14)サーバーとクライアントの違い

 

    (#15)[実践]キルカウントを作ってみよう

[実践]キルカウントを作ってみよう

Java版にはスコアボードの機能としてキルカウントがありますが、BEにはdummy型しかありません。
再現するには「武器を1確(一回当たったら倒れる)にしてスコアやらタグやらでmobやらを経由して@p」という誤検知しやすく制限の多い方法を使うしかないのです。

然而,在ScriptingAPI中,我们可以检测到攻击事件和实体被击败事件,同时获取到攻击者和受害者(玩家)的信息(组件),因此我们可以在脚本中创建一个没有误判的杀敌计数器。

由于这是一个针对插件的解释课程,所以我们将在制作过程中进行解释。

准备文件和文件夹

首先我们需要准备文件夹和文件。
文件夹的准备方法是像behavior/scripts/server那样。
这是一个在原始版本中已存在的文件夹,所以你应该能理解。
不使用behavior/scripts/client,所以如果你复制过来了,就应该删除它。

ファイルは**名前自由で拡張子.js**です。
今回はserver.jsとしましょう。

②餐前准备(每次复制粘贴的那个)

2-1. 注册脚本

让我们在编辑器中打开server.js文件。
一打开,首先在第一行添加。

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

我会写这个。这是在Minecraft中向脚本服务器文件注册的句子1。

顺便说一下,如果是客户端而不是服务器的情况下,

const clientSystem = client.registerSystem(0,0);

请问变量和常量在客户端和服务器之间是互相联动的吗?如果有专家的话,请告诉我!

2.内置函数

接下来,我们将编写主要的函数(内建函数)。

//ワールド始動時実行
system.initialize = function() {
  //イベントの登録、コンポーネントの登録、クエリの登録、イベントの検知登録
};

//更新されるたび(=tickごと?)実行
system.update = function() {
  //更新
};

//ワールド終了時?実行
system.shutdown = function() {
  //片付け
};

この3つのどれかを起点に実行は始まります。
updateとshutdownは使ったことがないので、どういう用途なのか、どういう挙動なのかよく分かりません。。。
updateはワールドに入った後で、エンティティを出したり動かしたりするなど、イベントの検知以外のタイミングで実行するときに使うようです。
shutdownに関しては例がありませんでした。

今回は「エンティティが倒された」というイベントの検知で実行をするので、initializeのみ使用します。

②-3. 注册事件的检测(listenForEvent)

system.initialize = function() {
  //エンティティが攻撃を受けたら関数「system.entity_hurt」を実行する
  this.listenForEvent ("minecraft:entity_hurt", (eventData) => this.entity_hurt(eventData));
  //エンティティが倒されたら関数「system.entity_death」を実行する
  this.listenForEvent("minecraft:entity_death", (eventData) => this.entity_death(eventData));
};

我监听了实体被击败时的事件”minecraft:entity_death”。

作为参考,我也写了一个listenForEvent的函数来处理受到攻击的情况。
您可以自由选择在检测到时执行的函数名称。
由于本次只会使用”minecraft:entity_death”,因此请将”minecraft:entity_hurt”移除。

进行处理

//ここまでのまとめ
const system = server.registerSystem(0,0);
system.initialize = function() {
  this.listenForEvent("minecraft:entity_death", (eventData) => this.entity_death(eventData));
};
system.entity_death = function(eventData) {
  //ここにエンティティが倒されたときに実行する処理を書いていくよ
}

获取组件数据

ScriptingAPIではエンティティのコンポネの値を取得することができます。
コンポーネントについて#5でプレイヤーの名前表示を出したり消したりしましたが、そのときに使った”minecraft:nameable”というコンポーネントを使います。

let hurter = this.getComponent(eventData.data.entity, "minecraft:nameable").data.name;

“minecraft:nameable”のnameには名前が入っています3。
これで変数hurterに「eventDataのentity」の名前が代入されました。

「eventDataのentity(eventData.data.entity)」はイベントを起こしたエンティティ、つまり今回は倒されたエンティティを指します。
じゃあ倒したエンティティの名前はどうやって取得するかというと、「eventDataの中のkiller(eventData.data.killer)」から取得します4。

let hurter = this.getComponent(eventData.data.entity, "minecraft:nameable").data.name;
let killer = this.getComponent(eventData.data.killer, "minecraft:nameable").data.name;

これで変数killerに「eventDataのkiller」の名前、つまり倒したエンティティの名前が代入されました。

执行命令

次はスクリプト内でのコマンドの実行です。
コマンドの実行は”minecraft:execute_command”というイベントで行われます5。
①イベントデータを作り、②イベントの内容を設定(=実行するコマンドを記述)し、③イベントを実行する、という3stepを踏みます。

let execute_command = this.createEventData("minecraft:execute_command");
execute_command.data.command = `/scoreboard players add @a[name="${hurter}"] deathcount 1`;
this.broadcastEvent("minecraft:execute_command", execute_command);

每一行对应3步操作。
如果执行多个命令,请重复步骤2和3。

let execute_command = this.createEventData("minecraft:execute_command");
execute_command.data.command = `/scoreboard players add @a[name="${hurter}"] deathcount 1`;
this.broadcastEvent("minecraft:execute_command", execute_command);
execute_command.data.command = `/scoreboard players add @a[name="${killer}"] killcount 1`;
this.broadcastEvent("minecraft:execute_command", execute_command);

只需要一种选项,以下是对原文的中文再述:
创建这种事件类型是为了能够将命令行赋值给事件,并且我认为这种感觉是通过创建的类型来实现,通过重新赋值给execute_command.data.command,就可以重复使用。

当然,用于存储创建的事件数据的变量名可以是execute_command,也可以是executeCommand或commandEvent,甚至可以是其他任何名称。但是需要注意的是,在使用该事件数据时,必须与最初分配的变量名相同。可以将其视为程序中的变量或Minecraft中的记分板。

<注意>
コマンドに使うセレクタの名前指定は@a[name=”名前”]という方法で行ってください。
/scoreboard players add 名前 deathcount 1や/scoreboard players add @p[name=”名前”] deathcount 1ではできません。
理由はよく分からないのですが、エンティティが倒された瞬間に実行するコマンドなので、名前や@p[name=”名前”]では、倒されたエンティティが見つからないようです(これに気付くのに2か月くらいかかりました)。

<追加情報>
ScriptingAPIは座標(x,y,z)=(0,0,0)を中心に実行されるようです。
@pや相対座標(チルダ~~~)を使う場合、この影響を受けることになります。

整理一下

//スクリプトの登録
const system = server.registerSystem(0,0);

//ワールドを開いたとき実行
system.initialize = function() {
  //イベント検知の登録
  this.listenForEvent("minecraft:entity_death", (eventData) => this.entity_death(eventData));
};

//エンティティが倒されたとき実行
system.entity_death = function(eventData) {
  //名前の取得
  let hurter = this.getComponent(eventData.data.entity, "minecraft:nameable").data.name;
  let killer = this.getComponent(eventData.data.killer, "minecraft:nameable").data.name;
  //コマンドの実行
  let execute_command = this.createEventData("minecraft:execute_command");
  execute_command.data.command = `/scoreboard players add @a[name="${hurter}"] deathcount 1`;
  this.broadcastEvent("minecraft:execute_command", execute_command);
  execute_command.data.command = `/scoreboard players add @a[name="${killer}"] killcount 1`;
  this.broadcastEvent("minecraft:execute_command", execute_command);
}

ワールドに入ったら、
/scoreboard objectives add killcount dummy
/scoreboard objectives add deathcount dummy
を実行します。
/scoreboard objectives setdisplay sidebar [表示したいobject名]
も実行して、倒したり、倒されたりしてみてください。
倒せばkillcountが増え、倒されればdeathcountが増えるのが分かると思います。

这样算是暂时完成了!

继续进一步探索

顺便尝试一下创建击杀通知吧。

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

system.initialize = function() {
  this.listenForEvent("minecraft:entity_death", (eventData) => this.entity_death(eventData));
};

system.entity_death = function(eventData) {
  let hurter = this.getComponent(eventData.data.entity, "minecraft:nameable").data.name;
  let execute_command = this.createEventData("minecraft:execute_command");
  execute_command.data.command = `/scoreboard players add @a[name="${hurter}"] deathcount 1`;
  this.broadcastEvent("minecraft:execute_command", execute_command);

  //倒したエンティティがいるなら
  if(eventData.data.killer){
    let killer = this.getComponent(eventData.data.killer, "minecraft:nameable").data.name;
    execute_command.data.command = `/scoreboard players add @a[name="${killer}"] killcount 1`;
    this.broadcastEvent("minecraft:execute_command", execute_command);
    
    execute_command.data.command = `/execute @a[name="${hurter}"] ~~~ playsound note.didgeridoo @s`;
    this.broadcastEvent("minecraft:execute_command", execute_command);
    execute_command.data.command = `/execute @a[name="${killer}"] ~~~ playsound note.harp @s`;
    this.broadcastEvent("minecraft:execute_command", execute_command);
    execute_command.data.command = `/titleraw @a[name="${hurter}"] actionbar {"rawtext":[{"text":"§l§b${killer}§r§lに倒された"}]}`;
    this.broadcastEvent("minecraft:execute_command", execute_command);
    execute_command.data.command = `/titleraw @a[name="${killer}"] actionbar {"rawtext":[{"text":"§l§c${hurter}§r§lを倒した"}]}`;
    this.broadcastEvent("minecraft:execute_command", execute_command);
  }
}

ifを使うことで、溶岩などでHPがゼロになったときに、(「名無しに倒された」という)通知が出ないようになっています。
アクションバーに倒した/倒されたプレイヤー名が出るほか、倒した/倒されたときにSE(効果音)がなるようにしました。

脚本编写完毕!

応用編の中でも難易度の高いスクリプト編でしたが、どうでしたか?
難しいと言いつつ2回分で全内容が終了してしまいました。

ここまで複数の応用編で、学びながら実際にアドオンを作っていくセクションがありましたが、それらは私が今までに作ってきたアドオンを簡易化したものです。

後半の回(今回#15)で作成した機能に、チームの概念を導入して、FF表示やチームメンバーのキル/デス通知、キルレの計算などを実装したものが、配布している「ExtraDeathMessage」というアドオンになります。

 

さらにこれを発展させてPvPに特化したものが「JustBattlePvP」というアドオンになり、

 

这个是以此为基础,专门针对雪仗的版本。

 

专注于炸弹设置/防御游戏的一种产品

 

(尚未发布)

这些计划的基础是插件的力量!而在这个插件课程中讲解的内容,将帮助我们获得实际可分发的插件开发技术!

我希望在这个附加组件课程中所学的知识能够孕育出更有趣的附加组件!

希望大家都能夠讀到最後!祝大家能夠成功地創造出自己想要的東西!辛苦了!

请转到目录中的第一项。

 

(0, 0)是指脚本引擎的版本。根据所有的例子来看,都是(0, 0),所以可以放心使用。在Javascript中,函数名更适合是entityDeath。这一次我们是根据事件名进行对齐的。

参考链接:https://bedrock.dev/docs/stable/Scripting#minecraft%3Anameable

参考链接:https://bedrock.dev/docs/stable/Scripting#minecraft%3Aentity_death

参考链接:https://bedrock.dev/docs/stable/Scripting#minecraft%3Aexecute_command

广告
将在 10 秒后关闭
bannerAds