この記事は Minecraft Command Advent Calendar 2024 シリーズ 2 22日目の記事です。
初めまして、狛寝もふたです。
超魅せるコマンド選手権2024-食べ物において、こちらの作品を投稿しました。1
この記事では、上記の作品に出てくるパズドラもどき(マッチ3ゲーム)に使った技術を紹介します。大慌てで作ったので、必ずしも最善の方法ではないことをご承知おきください。
Minecraft Java Edition 1.20.5 Pre-Release 1 にて作成しています。
1. 盤面の召喚、ドロップのランダム配置
操作検知用のinteractionをドロップの数だけごり押しで並べて盤面にしています。ドロップ自体はitem displayです。
ランダム配置は、loot spawnでitemを召喚し、NBT2をitem displayにコピーすることで行っています。
2. プレイヤーの操作 - 「2つ」の判定
interactionが2つクリックされたら、それぞれに重なるdisplayを入れ替える処理です。
# 2つクリックされたことの検知
execute at @e[(略),nbt={interaction:{}},limit=1] if entity @e[distance=0.01..,(略),nbt={interaction:{}},limit=1] run function cmn_food:exchange
クリックされた記録を持つinteractionが、複数の座標に存在するかを確認することで、2つ(以上)のinteractionがクリックされたことを判定しています。
# displayの位置入れ替え
execute as @e[type=minecraft:item_display,(略)] at @s if entity @e[distance=..0.01,type=minecraft:interaction,(略),nbt={interaction:{}}] run tp @s @e[type=minecraft:interaction,(略),nbt={interaction:{}},sort=furthest,limit=1]
(以下略)
displayから見て、クリックされたinteractionのうち最も遠いものに向けてtpします。
3. 3つそろったことの判定
あるドロップから見て、上下or左右の両方が、自分と同じアイテムを表示していれば3つ揃っている、と判定できます。
#全ドロップで実行する
#両側を見て、自分と同じitemだったらタグsameを付け、same付きが自分+2体いたら処理用タグ(combo)をつける
#左右チェック
tag @s add same
$execute positioned ~$(grid_size) ~ ~ run tag @e[type=minecraft:item_display,(略),distance=..0.01,nbt={item:$(food_item)}] add same
$execute positioned ~-$(grid_size) ~ ~ run tag @e[type=minecraft:item_display,(略),distance=..0.01,nbt={item:$(food_item)}] add same
#数える
execute store result storage cmn_food:candy int_match int 1 if entity @e[type=minecraft:item_display,(略),tag=same]
execute if data storage cmn_food:candy {int_match:3} run tag @e[type=minecraft:item_display,(略),tag=same] add combo
tag @e remove same
#上下も同様
即座にkillせずタグの付与にとどめているのは、4つ以上並んでいる場合に対応するためです。
ただ、マクロ入りfunctionをドロップの個数分実行するのは重そうな気がします。もっと良い書き方がありそうです。
4. ドロップの落下 - 「真上」の検出
盤面の上の見えない位置にteleport durationを設定したドロップを用意しておき、各マスへtpすることで落下の見た目を作っています。
それぞれのマス(interaction)にtpするドロップは、以下のような条件で探しています。
interactionから見て、
- x,zが同じ
- yが同じか大きい(上にある)
- 最も近い
# このfunctionは下から順に全マス(interaction)から実行する
execute positioned ~ ~100 ~ as @e[(略),distance=..100.01] if predicate cmn_food:same_xz run tag @s add just_above
tp @e[(略),tag=just_above,sort=nearest,limit=1] ~ ~ ~
tag @e remove just_above
{
"condition": "minecraft:entity_properties",
"entity": "this",
"predicate": {
"distance": {
"horizontal": {
"max": 0.01
}
}
}
}
x,zはpredicateで水平距離を指定することで判定しています。
このように相対座標を判定するpredicateは、execute if predicate ...
で適用する必要があります。
セレクターの引数として@e[predicate=...]
のように書くと、相対座標の基点は"this"が指すエンティティの座標になります。このpredicateであれば常に成功します。
y座標に関しては、positionedで上に移動し、移動距離より近いもの、という形で判定しています。