前提
このサイトの読者なら既にご存じかとは思いますが、マインクラフトにはScriptAPIと呼ばれる拡張機能が存在します。簡単に言えば、Javascriptというプログラミング言語を用いてゲームシステムをカスタマイズする機能のことです。
これはScriptAPIの一例で、「プレイヤーがジャンプしたらkillコマンドを実行する」というスクリプトです。これは縛りプレイなどに用いられますが、このようにしてゲームシステムを改変できるわけですね。ScriptAPIについての詳細はこちらをご覧ください:
scoreboardコマンド
さて、話は変わりますが、同様にマインクラフトにはスコアボードと呼ばれる機能が存在します。これは、プレイヤーやエンティティにつけられた値のことであり、主にscoreboardコマンドを介して閲覧・編集することができます。主に配布ワールドなどでプレイヤーに点数をつけるのに用いられますね。
具体的には、scoreboardのオブジェクトを追加する場合は、
scoreboard objectives add test_score dummy
※「test_score」はオブジェクトの名前です。ここには各自好きな名前を入れることができます。
というコマンドを打ち込めばよいですし、プレイヤーに付与する場合は、
scoreboard players add @s test_score 1
といったコマンドによって可能です。(※上記はスコアを1付与する例ですが、「add」を「remove」に変えることで減らすこともできますし、「set」にすると任意の値に設定できます)
そして付与されたスコアを使って何かを行う場合は、
give @a[scores={test_score=3}] diamond 1
のように、ターゲットセレクターと併せてコマンドを使用することが一般的です。これは、test_scoreが3のプレイヤーにダイアモンドを1個与える例です。
問題点
一見するとこれは非常に自由度が高いように見えますが、動的に何かを起こそうとするとscoreboardコマンドはあまりに非力です。例えば、test_scoreが3の場合は3個のダイアモンドを、スコアが5の場合は5個のダイアモンドを与える、といった具合です。これを達成する場合、
give @a[scores={test_score=3}] diamond 3
give @a[scores={test_score=4}] diamond 4
give @a[scores={test_score=5}] diamond 5
give @a[scores={test_score=6}] diamond 6
のように非常に多くのコマンドが必要になり、数が多い場合この方法はあまりに非現実的です。
効率的に、スコアに応じて動的な処理を行う方法はないのでしょうか?
次章では、この問題に対する解決策を提示します。
解決策
この問題は、前述のAPIScriptを用いることで解決します。すなわち、プレイヤーのスコアを読み取る関数を次のように定義します。
function get_score(score_name, player_name){
try{
const scoreboard = server.world.scoreboard;
let objective = scoreboard.getObjective(score_name);
let score = objective.getScore(player_name.scoreboardIdentity);
if (score != undefined){
return score;
}else{
return 0;
}
} catch{
return 0; //scoreboardが定義されていないかも?
}
}
これは、スコアボードのオブジェクトとプレイヤーの名前を引数としてそのプレイヤーのスコアを読み取る関数です。エラーを起こした場合、0を返し、その他の場合はスコアを整数型で返します。特に当該スコアオブジェクトが定義されていない場合0を返すので注意しましょう。
使用例
この関数を用いて動的な処理を行う例を提示します。
server.system.runInterval(ev => {
for (const player of server.world.getAllPlayers()){
player.runCommand("say 私のスコアは" + get_score("test_score",player) + "です");
}
});
これは、現在のスコアを読み取ってそれをsayコマンドに組み込んだ例です。実際にこれを保存してゲームを動かすと、現在のスコアを発言すると思います(実機検証済)。
同様に、現在のスコアの分だけダイアモンドをプレイヤーに与えるスクリプトを書くこともできます:
server.system.runInterval(ev => {
for (const player of server.world.getAllPlayers()){
player.runCommand(`give @s[scores={test_score=${get_score("test_score",player)}}] diamond ${get_score("test_score",player)}`);
}
});
これによって、先ほどの大量のコマンド群を書く必要がなくなり、非常にスマートです。
おしまい
このようにして、ScriptAPI上でプレイヤーのスコアを読み取って動的な処理を行うことが可能になります。本記事の内容が皆様のお役に立てれば幸いです。