スコアボード × /execute:スコアで条件分岐しよう

この記事では、前回作ったウェルカムDatapackの execute if score をさらに深掘りします。スコアの範囲チェックに加え、複数条件を同時に満たすときだけ処理を走らせる「AND条件の書き方」と、2つのスコアを比べる「スコア同士の比較」を身につけましょう。これを覚えるだけで、「HPが少なくてかつ空腹のとき警告する」「プレイヤーAよりプレイヤーBのスコアが高いとき演出する」といった実用的な条件分岐が書けるようになります。

対応バージョン:Java Edition 1.21.11

目次

前提知識

この記事は前回作成したDatapack(setup.mcfunction / tick.mcfunction / welcome.mcfunction / reset.mcfunction)がある状態から続けます。まだ作っていない方は前回の記事を先に読んでから戻ってきてください。

おさらい:if score matches の範囲指定

前回の welcome.mcfunction でも使いましたが、if score の範囲指定は4パターンあります。まずここを整理しておきましょう。

execute if score @s join_count matches 1    run ...   # ちょうど1
execute if score @s join_count matches 2..  run ...   # 2以上(上限なし)
execute if score @s join_count matches 1..5 run ...   # 1以上5以下
execute if score @s join_count matches ..0  run ...   # 0以下(下限なし)

フェイクプレイヤー(# 付きスコア)とは

スコアボードは実在するプレイヤーだけでなく、# で始まる任意の名前にも値を持たせることができます。これを「フェイクプレイヤー」と呼びます。実際にはゲームに存在しない架空のエントリですが、スコアボードにはきちんと値が保存されます。

# フェイクプレイヤーに定数をセットする
scoreboard players set #veteran join_count 5

# 確認する(エンティティが存在しなくてもOK)
scoreboard players get #veteran join_count

フェイクプレイヤーの重要な特徴として、# で始まる名前はサイドバーや他のディスプレイには表示されません。 たとえば join_count をサイドバーに表示していても、#veteran のスコアは画面に出てきません。プレイヤーが目にするスコア表示を汚さずに、コマンド専用の「内部変数」として使えるのがポイントです。

対して # をつけない名前(例:dummy_playerSteve)でスコアを持たせると、そのエントリはサイドバーにも表示されてしまいます。プレイヤーに見せたくない管理用の値には必ず # をつけましょう。

サイドバーに join_count が表示されているが #veteran のエントリは表示されていない状態のスクリーンショット

ステップ1:AND条件 — 複数の if をひとつの execute に並べる

execute では、ifunless を1行の中にいくつでも並べることができます。並べたすべての条件を満たしたときだけ run が実行される、いわゆる「AND条件」です。

# join_count が 3 以上 かつ tag=vip を持っているときだけメッセージを送る
execute as @a at @s if score @s join_count matches 3.. if entity @s[tag=vip] run tellraw @s [{"text":"VIP常連ボーナス!","color":"gold"}]

if score @s join_count matches 3..if entity @s[tag=vip] の2つが両方通過したときだけ run が走ります。条件を追加するときは、run の前に if ... をそのまま続けて書くだけです。unless も同じように並べられるので、「条件Aを満たして、かつ条件Bを満たさないとき」も1行で書けます。

# welcome.mcfunction:5回以上参加 かつ ダイヤモンドを持っていないときだけ渡す
execute if score @s join_count matches 5.. unless entity @s[nbt={Inventory:[{id:"minecraft:diamond"}]}] run give @s minecraft:diamond 1

ステップ2:OR条件 — execute の行を分けて書く+/return で処理を止める

「条件AまたはBのとき」のOR条件は、1行では書けません。シンプルに行を分けて書くのが基本です。

# join_count が 1 のとき、または tag=newcomer を持っているとき — どちらかでメッセージを送る
execute as @a at @s if score @s join_count matches 1    run tellraw @s [{"text":"初参加!"}]
execute as @a at @s if entity @s[tag=newcomer]          run tellraw @s [{"text":"ようこそ新人!"}]

ただし「両方の条件を同時に満たすと2回実行されてしまう」という問題があります。これを防ぐには return run を使う方法が便利です。

return run はコマンドを実行したあとにそのファンクションの処理をその場で止める命令です(Java Edition 1.20.2以降)。if と組み合わせると「条件を満たした時点で処理を止め、後続の行を実行しない」という if-else に近い書き方ができます。

# join_count が 1 なら「はじめまして」を送って処理を止める
execute if score @s join_count matches 1 run return run tellraw @s [{"text":"はじめまして!ゆっくりしていってね。","color":"gold","bold":true}]

# ここに到達するのは join_count が 1 でないプレイヤーのみ
# → 「はじめまして」と「またきてくれましたね!」が両方出てしまう心配がない
execute if score @s join_count matches 2.. run tellraw @s [{"text":"またきてくれましたね!","color":"aqua"}]

return run は「呼び出されたファンクション内」でのみ処理を止めます。welcome.mcfunction の中で書けばそのファイルの処理がそこで止まり、呼び出し元の tick.mcfunction には戻ります。tick.mcfunction 自体は止まらないので、意図通りに動きます。

ステップ3:スコア同士を比べる — if score vs score

2つのスコアをその場で比較したいときは if score ... >= ... の書き方を使います。演算子は =(等しい)、<(小さい)、>(大きい)、<=>= の5種類です。

ここでフェイクプレイヤーが活躍します。基準値を setup.mcfunction でフェイクプレイヤーにセットしておけば、コマンドの中に数値をベタ書きせずに比較できます。「常連ライン」を変えたくなったときも setup.mcfunction の1行を書き換えるだけで済みます。

# setup.mcfunction に追加:フェイクプレイヤー #veteran に基準値 5 をセットする
scoreboard players set #veteran join_count 5
# welcome.mcfunction:プレイヤーのスコアが #veteran 以上 かつ ダイヤを持っていないとき
execute if score @s join_count >= #veteran join_count unless entity @s[nbt={Inventory:[{id:"minecraft:diamond"}]}] run tellraw @s [{"text":"常連ボーナス!ダイヤをどうぞ。","color":"aqua"}]
execute if score @s join_count >= #veteran join_count unless entity @s[nbt={Inventory:[{id:"minecraft:diamond"}]}] run give @s minecraft:diamond 1
join_count が #veteran の閾値以上になったときに「常連ボーナス!」がチャットに表示されダイヤが渡されるようすのGIF

ステップ4:welcome.mcfunction の完成形

setup.mcfunction(変更あり)

scoreboard objectives add join_count dummy "参加回数"
scoreboard objectives add leave_game minecraft.custom:minecraft.leave_game "退出回数"
scoreboard objectives setdisplay sidebar join_count

# フェイクプレイヤーで「常連」ラインを管理(サイドバーには表示されない)
scoreboard players set #veteran join_count 5

welcome.mcfunction(変更あり)

tag @s add welcomed
scoreboard players add @s join_count 1

tellraw @s [{"text":"ようこそ!","color":"gold","bold":true},{"text":"このサーバーに参加してくれてありがとう。","color":"white"}]
give @s minecraft:bread 5
effect give @s minecraft:speed 30 1 true
playsound minecraft:entity.player.levelup master @s ~ ~ ~ 1 1

tellraw @s [{"text":"あなたの参加回数:","color":"aqua"},{"score":{"name":"@s","objective":"join_count"},"color":"white"}]

# return run でif-else:1回目 → はじめまして、2回目以降 → おかえり
execute if score @s join_count matches 1 run return run tellraw @s [{"text":"はじめまして!ゆっくりしていってね。","color":"gold","bold":true}]
execute if score @s join_count matches 2.. run tellraw @s [{"text":"またきてくれましたね!","color":"aqua"}]

# AND条件:#veteran 以上 かつ ダイヤを持っていないとき常連ボーナス
execute if score @s join_count >= #veteran join_count unless entity @s[nbt={Inventory:[{id:"minecraft:diamond"}]}] run tellraw @s [{"text":"常連ボーナス!ダイヤをどうぞ。","color":"aqua"}]
execute if score @s join_count >= #veteran join_count unless entity @s[nbt={Inventory:[{id:"minecraft:diamond"}]}] run give @s minecraft:diamond 1

動作確認の手順

  1. /scoreboard players get #veteran join_count を実行し、値が 5 になっているか確認する
  2. サイドバーに #veteran のエントリが表示されていないことを確認する
  3. /scoreboard players set @s join_count 4 でスコアを4にセットし、ワールドを出入りする
  4. join_count が5になったタイミングでダイヤと「常連ボーナス!」が届くことを確認する
  5. もう一度出入りしてもダイヤが重複して渡されないことを確認する
  6. 初回(join_count = 1)のとき「はじめまして」だけ表示され、「またきてくれましたね!」が表示されないことを確認する(return run が効いている)
/scoreboard players get #veteran join_count を実行して値が 5 と返ってきているチャット画面のスクリーンショット

まとめ

  • # で始めるフェイクプレイヤーはゲームに存在しない「変数」。定数や閾値の管理に使い、サイドバーには表示されないのでプレイヤーの画面を汚さない
  • # をつけない名前でスコアを持たせると、サイドバーにも表示されてしまうので注意する
  • 1行の executeif / unless を並べることで、すべての条件を同時に満たすAND条件が書ける
  • OR条件は行を分けて書く。return run を使えば「条件を満たしたらそこで処理を止める」if-elseに近い書き方ができる(1.20.2以降)
  • if score A objective >= B objective で2つのスコアをその場で比較できる

次の記事「タグでブロック・アイテムをグループ化しよう」では、#minecraft:logs のようなバニラタグの仕組みと、独自のブロック・アイテムタグを tags/blocktags/item フォルダを使って自作する方法を解説します。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次