STEP02.高さの表示を自動化しよう
ミニゲーム作成チュートリアルの2回目です。
前回は高さを取得して表示まで行いました。 毎回チャットコマンドを入力するのは面倒なので、この表示を自動化しましょう。
Tickイベントを使って、表示コマンドをティックごとに自動で実行する
TickEvent
はティックごとに自動で実行されるイベントです。
1ティック、つまり1秒間に20回、目的のプログラムを実行します。
この機能を使い、目的のコマンドを定期的に実行することで、表示を自動化します。
コマンドを使うには、どの次元 で使っているのか、あるいはどのプレイヤー が使ってるのかをはっきりさせる必要があります。
例えば/tp
を使うときに、オーバーワールドで使った場合と、ネザーで使った場合では移動する場所が違いますね。
移動先の座標の数字は同じでも、オーバーワールドとネザーでは別のワールドだからです。
また、誰が使うのかをはっきりさせれば、そのプレイヤーがどの次元にいるのかを判断できます。 そのため、コマンドを使うには「次元」か「プレイヤー」の情報が必要になります。
今回使用するTickEvent
で取得できる内容だけではコマンドを実行できないので、オーバーワールドの次元情報を事前に取得しておきます。
この情報からrunCommand()
を実行することにします。
前回書いたコードは削除して、次の内容で上書きしてください。
import * as mc from 'mojang-minecraft';
// 最初にオーバーワールドの次元情報を取得しておく
// 今回の使い方では毎回取得する必要がないので、グローバル変数に入れる
const overworld = mc.world.getDimension('overworld');
mc.world.events.tick.subscribe((event) => {
// 次元情報からコマンドを実行
overworld.runCommand(`say ${event.currentTick}`)
});
ワールドにいる全プレイヤーを取得する
次にプレイヤー情報を取得する処理を加えます。
開発時には自分ひとりしかいませんが、マルチプレイのことも考えて、プレイヤー全員に対して処理を行うようにしておきます。
プレイヤーの情報は、次元情報から取得できます。 上で取得したオーバーワールドの次元情報を今回も使用します。
まずはプレイヤー情報を取得できていることを確かめるために、名前だけを表示してみましょう。 すべての処理を一気に描くのではなく、ひとつずつ進めていきます。
import * as mc from 'mojang-minecraft';
const overworld = mc.world.getDimension('overworld');
mc.world.events.tick.subscribe((event) => {
// オーバーワールドにいるプレイヤーを取得する
const players = overworld.getPlayers();
// プレイヤーごとに繰り返し
for (const player of players) {
// そのプレイヤーの名前を表示
overworld.runCommand(`say ${player.nameTag}`)
}
});
プレイヤーの取得は変数に入れずに、直接for文の中に書くこともできます。 上では、途中の処理をわかりやすくするため、分けて書きましたが、この場合は直接for文の中に書いても良いでしょう。
for (const player of overworld.getPlayers()) {
// ...
}
高さをアクションバーに表示する
オーバーワールドにいるプレイヤー全員分の名前が表示されたら成功です。 しかし、本当に表示したいのは、それぞれのプレイヤーのいる「高さ」でした。 次はこれを表示するようにしましょう。
高さを取得する処理は前回と同じです。
今回は各プレイヤーが自分の情報だけを知れれば良いので、共通のチャット画面ではなく、そのプレイヤーのアクションバーに表示させます。
アクションバーに表示させるのは/title
コマンドです。
また、今回のrunCommand()
メソッドはプレイヤーから使用します。
この場合、コマンド文の@s
は、このメソッドを実行したプレイヤーのことになります。
次元情報からrunCommand()
を使用した場合、@s
は無効になるので注意してください。
import * as mc from 'mojang-minecraft';
const overworld = mc.world.getDimension('overworld');
mc.world.events.tick.subscribe((event) => {
for (const player of overworld.getPlayers()) {
const height = Math.floor(player.location.y);
const text = `現在の高さは ${height} です。`;
// titleコマンドでアクションバーに表示する
player.runCommand(`title @s actionbar ${text}`);
}
});
実行回数を制限する
上の方法では1秒間に20回、表示コマンドが実行されます。 今回の目的では、ここまで何度も書き換える必要はないので、回数を制限しましょう。
event.currentTick
で現在の総ティック数を取得できるので、これを使用します。
また、%
演算子を使うと、割った余りを求めることができます。
この場合の記号に元の百分率(パーセント)の意味はありません。
下の例の場合はティック数を10
で割った余りが0
のときにだけ実行できます。
つまり、ティック数が10の倍数のときだけ、条件式の判定が真になり、目的のコマンドを実行します。
import * as mc from 'mojang-minecraft';
const overworld = mc.world.getDimension('overworld');
mc.world.events.tick.subscribe((event) => {
// 10ティック(0.5秒)ごとに1回実行する
if (event.currentTick % 10 === 0) {
for (const player of overworld.getPlayers()) {
const height = Math.floor(player.location.y);
const text = `現在の高さは ${height} です。`;
// titleコマンドでアクションバーに表示する
player.runCommand(`title @s actionbar ${text}`);
}
}
});
この例では10ティックごとに目的のコマンドを実行しています。 つまり、それぞれのプレイヤーの高さ情報を0.5秒ごとに更新しています。
もし更新が遅いと感じたら、数字を調整してみましょう。 更新が多すぎると、ゲームが重くなってしまうので、処理内容に合わせてうまく制限してください。 (毎ティック実行した方が良い場合もあります)
コードを整理する
最後にコードの整理を行います。
ここまでのコード自体は間違っていません。 しかし、このままひとつの関数に処理を加え続けると、コードが読みづらくなっていきます。 これを避けるために、処理のまとまりを関数に置き換えて分離します。
理想的な関数の書き方はありますが、まずは意味のまとまりで切り出す、というところから始めてください。
次の場合は、アクションバーに表示する処理を切り出しています。
import * as mc from 'mojang-minecraft';
const overworld = mc.world.getDimension('overworld');
mc.world.events.tick.subscribe((event) => {
if (event.currentTick % 10 === 0) {
for (const player of overworld.getPlayers()) {
// 関数を呼び出し
showActionBar(player);
}
}
});
// 自分の高さ(y座標)をアクションバーに表示する
function showActionBar(player: mc.Player) {
const height = Math.floor(player.location.y);
const text = `現在の高さは ${height} です。`;
player.runCommand(`title @s actionbar ${text}`);
}
このように関数に切り出すことで、コードが読みやすくなります。 この場合は「プレイヤーごとにアクションバーを表示させる」という意図がはっきりします。