ルッキーのコマンドメモ

主にマイクラのコマンドやデータパックに関することを書いていきます。

(マイクラ コマンド・データパック) 視線の先にいるモブやエンティティを調べる方法

視線の先にいるモブやエンティティを調べる

今回は視線の先にエンティティがいるかを調べてそのエンティティに対してコマンドを実行する方法を紹介します。

目次

調べるコマンド

再帰呼び出しと呼ばれる方法を使い、プレイヤの視線の方向に少しづつ検知用のエンティティをとばし、そのエンティティに触れたエンティティが視線先にいると判断しています。

再帰呼び出しについてはこちらでも紹介しています。

実装例は以下のようになります。

check.mcfunction

# 検知用にタグのついたmarkerを召喚する
execute at @s anchored eyes run summon marker ~ ~ ~ {Tags:["marker"]}

# マーカーの向きを実行者の視線の方向にする
execute at @s anchored eyes run data modify entity @e[tag=marker,sort=nearest,limit=1] Rotation set from entity @s Rotation

# ループ用のカウントを設定する
scoreboard players set count test 0
scoreboard players set loop test 50

#実行者を検知してしまわないようにtagをつけておく
tag @s add executer

# 再帰呼び出しにより視線先のエンティティを探す
execute at @s anchored eyes positioned ^ ^ ^ as @e[tag=marker,sort=nearest,limit=1] if score count test < loop test run function <名前空間>:check_loop

# 検知用のmarkerをkill
kill @e[type=marker,tag=marker]

# つけたtagを消す
tag @e[tag=executer] remove executer

# 検知したエンティティに発光エフェクトをつける
effect give @e[tag=detected] glowing 1 1

# 検知したエンティティからタグを消去する
tag @e[tag=detected] remove detected

# スコアをリセットする
scoreboard players reset count test
scoreboard players reset loop test

check_loop.mcfunction

# 検知用エンティティを視線先に0.1ブロックtpさせる
tp @s ^ ^ ^0.1

# 検知用エンティティを中心とした0.01×0.01×0.01の立方体の中に当たり判定があるエンティティにdetectedタグをつける
execute at @s positioned ~0 ~0 ~0 as @e[tag=!marker,tag=!executer,dx=0] positioned ~-0.99 ~-0.99 ~-0.99 if entity @s[dx=0] run tag @s add detected

# ループ処理。 detectedタグがついたエンティティがいなければ継続する
scoreboard players add count test 1
execute unless entity @e[tag=detected] at @s if score count test < loop test run function <名前空間>:check_loop

実行結果

このコマンドを毎tick実行してみるこのような結果になります。

実行結果 (見つかった場合)

視線の先にエンティティの当たり判定があれば検知され発光します

実行結果 (見つからなかった場合)

当たり判定がなければ検知されず、発光しません。

解説

行っていることは以下のようになります。

  1. 実行者の頭の位置に検知用エンティティとしてmarkerを召喚し、markerの視線の方向を実行者と同じにする。
    check.mcfunctionの最初の2つのコマンドの部分になります。

  2. ループ回数を設定し、ループ用関数を呼び出す。
    3から6番目のコマンドが該当します。

  3. 各ループにおいて、0.1ブロックずつ視線の方向にmarkerを移動させ、エンティティがいるか調べる
    セレクタの引数であるdxを利用してエンティティの座標ではなく当たり判定を基準として存在を調べています。dxについての詳細はdx,dy,dzの使い方を確認してください

  4. エンティティが見つからなければ3に戻る

  5. もし、エンティティが見つかればdetectedタグをつけてループを終了する

  6. detectedタグがついたエンティティを発光させる

まとめ

このように、再帰呼び出しを利用することにより、視線先にいるエンティティを検知することができます。

(マイクラ コマンド・データパック)dataコマンドの基本的な使い方

data コマンドの基本的な使い方

今回はデータパックを作る時かなりの頻度で使うことになるdataコマンドの基本的な使い方について紹介していきます。

目次

dataコマンドの種類

dataコマンドには以下の4つが存在します。

  • data getコマンド (データの取得)
    データを取得するコマンドです。
    データパックではnbtやストレージに入っている数値データをスコアに代入したいときやリスト型のデータの要素数を取得したいときに使っています。

  • data mergeコマンド (データの合成)
    データを合成するコマンドです。
    個人的に使い勝手が悪く、data modifyコマンドで代用できることからあまり使っていません。

  • data modifyコマンド (データの編集)
    データを編集するコマンドです。
    できることの幅が広く、dataコマンドを使う時の大半はこのコマンドを使っています。

  • data removeコマンド (データの削除)
    そのまま、データを削除するコマンドです。

それぞれのコマンドの使い方

それぞれのコマンドの使い方を紹介していきます。

data get コマンド

data getコマンドはentityやblock、ストレージのデータの中を見ることができます。 execute store resultコマンドでスコアに結果を格納することで使用することが多いです。

data get コマンドの書き方

data get コマンドは以下のような形で使うことができます

data get (block <対象の座標>/entity <対象>/storage <対象>) <NBTパス> <倍率>

例えば、実行したプレイヤが今持っているアイテムのデータが見たいなら以下のようなコマンドになります。

data get entity @s SelectedItem

以下にdata get コマンドの使用例を紹介していきます。

満腹度が6以下になったプレイヤを調べる

プレイヤの満腹度はfoodLevelというnbtを見ることで確認できます。

foodlevel.mcfunction

  # プレイヤの満腹度をfoodlevelというスコアに代入する
  execute store result score @s foodlevel run data get entity @s foodLevel

  # 代入したスコアが6以下であれば"お腹が減って走れない..."とチャットに表示する
  execute if score @s foodlevel matches ..6 run say お腹が減って走れない...

実行したプレイヤの満腹度が6以下であれば"お腹が減って走れない..."とチャットに表示するコマンドです。

インベントリがいっぱいになったプレイヤを調べる

以前書いたプレイヤのインベントリがいっぱいか調べるでも紹介したものです。

max_inventory.mcfunction

  # インベントリのスロット数をinventoryというスコアに代入する
  execute store result score @s inventory run data get entity @s Inventory

  # 代入したスコアが41であれば、"インベントリがいっぱいだ..."とチャットに表示する
  execute if score @s inventory matches 41 run say インベントリがいっぱいだ...

data get コマンドでインベントリを調べた結果をスコアに代入すると、インベントリの埋まっているスロットの数が取得できます。

そのため、そのスコアが41(インベントリの41スロット+防具欄の4スロット+オフハンドの1スロット)であればインベントリがいっぱいだとみなし、チャットに表示しています。

data merge コマンド

data merge コマンドはデータの合成をすることができるコマンドです。
このコマンドでできることはdata modify コマンドでできるため、自分はあまり利用することはないです。

data merge コマンドの書き方

data merge コマンドは以下のような形で使うことができます

data merge (block <対象の座標>/entity <対象>/storage <対象>) <NBT>

mergeの対象となるデータにそのNBTが存在していなかった場合は追加され、存在していた場合は上書きされます。

例えば、一番近くのゾンビが持っているアイテムをダイヤの剣に変えたいならこのような書き方になります。

data merge entity @e[type=zombie,sort=nearest,limit=1] {HandItems:[{id:"minecraft:diamond_sword",Count:1b}]}

data modify コマンド

data modify コマンドはデータの編集をすることができるコマンドです。 自分がdataコマンドを使う時は大抵このコマンドを使います。

data modify コマンドの書き方

data modify コマンドはできることの幅が広く、それだけにコマンドがとても複雑になります。
このコマンドの書き方は簡単には以下のようになります。

data modify <対象のパス> <操作> <データ>

それぞれに対して解説していきます。

<対象のパス>という部分はdata get コマンドの書き方にあった(block <対象の座標>/entity <対象>/storage <対象>) <NBTパス>と同じです。

<操作>という部分は以下の5つの操作のうちのどれかになります。

  • prepend 対象のリストの最初に指定したデータを追加する
  • insert <番号> 対象のリストの指定した<番号>の位置にデータを挿入する
  • append 対象のリストの最後に指定したデータを追加する
  • merge 対象に指定したデータを合成する
  • set 対象を指定したデータに変更する

最後に<データ>です。指定するデータを表す部分になります。
以下の3つのうちのどれかになります。

  • from (block <取得元の座標>/entity <取得元>/storage <取得元>) <取得元のパス>
    <対象のパス>と同様の書き方です。すでにあるデータを指定する場合にこれを使います。

  • string (block <取得元の座標>/entity <取得元>/storage <取得元>) <取得元のパス> <最初の文字数> <最後の文字数>
    文字列や数値の一部を切り取ってきたい場合に使う操作です。自分は使ったことがないのでよく知りません。

  • value <値>
    直接指定するデータを書き込む操作です。

data modify コマンドを使って、data merge コマンドと同様に、一番近くのゾンビの持っているアイテムをダイヤの剣にするコマンドは以下のようになります。

data modify entity @e[type=zombie,sort=nearest,limit=1] {} merge value {HandItems:[{id:"minecraft:diamond_sword",Count:1b}]}

data modify コマンドはあまりにも使用できる幅が広いので、具体的な使用例などはまた別の記事に書きたいと思います。

data remove コマンド

data remove コマンドは特定のデータを削除することができるコマンドです。

data remove コマンドの使い方

data remove コマンドの書き方は以下のような形になります。

  data remove (block <対象の座標>/entity <対象>/storage <対象>) <NBTパス>

例えば、一番近くのゾンビが持っているアイテムを削除したい場合はこのようにかけます

  data remove entity @e[type=zombie,sort=nearest,limit=1] HandItems[0]

また、足元のブロックの中から石ブロックだけを消したい場合にはこのように書けます

  data remove block ~ ~-1 ~ Items[{id:"minecraft:stone"}]

まとめ

dataコマンドにはget,merge,modify,removeの操作があり、それぞれデータの取得、合成、編集、削除を行うことができます。
このコマンドはできることが非常に多く、それだけに覚えるのは大変ですが少しづつ勉強していきましょう。

(マイクラ コマンド・データパック )ループ処理を行う方法

ループ処理を行いたい

データパックを書いているとプログラムのfor文やwhile文のように、特定の条件を満たすまで同じ処理を繰り返したいということがよくあります。自分は壁に当たるまでエンティティを前に動かすという処理を行うときにこれを利用します。今回はそんなループ文を書く方法として再帰呼び出しと呼ばれる方法を紹介します。

目次

どうやって実装するのか

コマンドではループ処理は難しい......

残念ながら、現在for文やwhile文のような処理を行うコマンドは存在しないようです。
その代わりにデータパックで再帰呼び出しという方法を利用して、ループ処理を行うことができます。

再帰呼び出しとは

再帰呼び出しとは自分自身を呼び出すことによりループ処理を行うことです。
具体的には以下のようなfunctionが再帰呼び出しを実装したものになります。

summon.mcfunction

# ループ回数のスコアを設定する
scoreboard players set loop test 3
scoreboard players set count test 0

# 条件を満たせば再帰呼び出し用のfunctionを実行
execute if score count test < loop test run function <名前空間>:summon_loop

summon_loop.mcfunction

# ゾンビを召喚
summon zombie
# カウントを1増やす
scoreboard players add count test 1
# 条件を満たさなくなるまで再帰呼び出し用のfunctionを実行
execute if score count test < loop test run function <名前空間>:summon_loop

あらかじめ以下のコマンドを実行して、testというスコアを作っておく必要があります。

scoreboard objectives add test dummy

そして、summon.mcfunctionを実行すると以下のようにゾンビが3体召喚されます。

再帰呼び出しの流れ

どのような流れで上記のような実行結果になったのかを詳しく説明します。

  • summon.mcfunctionが呼び出され、ループ用の値が設定される

    まず、summon.mcfunctionの処理が行われます。loopというスコアを3に設定し、countというスコアを0にします。ここでloopというスコアを別の数字に変えると、その数だけゾンビが召喚されます。

  • summon_loop.mcfunctionが呼び出される

    execute if score count test < loop test run function <名前空間>:summon_loopという3つ目のコマンドにより、loopというスコアの値がcountというスコアの値よりも大きければ、summon_loop.mcfunctionが呼び出されます。
    今回はloopが3でcountが0なので条件を満たし、summon_loop.mcfunctionが呼び出されます。

  • 条件を満たさなくなるまでsummon_loop.mcfunctionが実行され、ゾンビが召喚される

    まず、summon_loop.mcfunctionの1つ目のコマンドでゾンビが召喚されます。
    次に2つ目のコマンドにより、countのスコアが1増加します。
    そして3つ目のコマンドにより、loopの値がcountの値よりも大きければ、summon_loop.mcfunctionがまた呼び出されます。
    今回もloopが3でcountが1なので条件を満たし、summon_loop.mcfunctionが呼び出されます。

    このように、summon_loop.mcfunctionが呼び出されるたびにcountが1ずつ増加していきます。
    summon_loop.mcfunctionが3回呼び出されると、countが3になり、loopがcountより大きいという条件がなくなるので、これ以上summon_loop.mcfunctionが呼び出されなくなります。

再帰呼び出しの欠点

このように、再帰呼び出しを利用することで、特定の条件を満たすまで同じfunctionを実行し続けることができます。
しかし、1tickのうちに何度も同じコマンドを繰り返すことになるため、処理が重くなってしまうことも多い点、ループを行う条件を間違えると永遠にループが終わらなくなってしまうという点など、利用する際には気をつけないといけない部分がたくさんあります。

再帰呼び出しの利用例

プレイヤを10ブロック先にTPさせる

再帰呼び出しの利用例として、プレイヤを10ブロック先にTPさせるfunctionを紹介します。
ただTPさせるだけであれば再帰呼び出しを使わなくても実装することができますが、再帰呼び出しを利用することで、壁にぶつかる場合にはそこでTPを止めるという条件をつけることができます。

コマンドは以下のようになります。

teleport.mcfunction

# ループスコアの設定
scoreboard players set loop test 100
scoreboard players set count test 0
# 条件を満たさなくなるまで再帰呼び出し用のfunctionを実行
execute if block ~ ~ ~ air if score count test < loop test run function <名前空間>:teleport_loop

teleport_loop.mcfunction

# プレイヤを0.1ブロック先にtpさせる
execute at @s run tp @s ^ ^ ^0.1
# カウントを1増やす
scoreboard players add count test 1
# 条件を満たさなくなるまで再帰呼び出し用のfunctionを実行
execute if block ~ ~ ~ air if score count test < loop test run function <名前空間>:teleport_loop

これを実行すると、以下のように壁に当たるか、10マス先までtpすることができます。

teleport前

teleport後

まとめ

データパックでループ処理を行いたいという場合には、再帰呼び出しと呼ばれる方法を使って同じfunctionを何度も呼び出すことで実装することができます。
この方法を使うと、1tickの間に同じ処理を何度も行うことができるのでとても便利ですが、その分処理が重くなったり、ループの条件を間違えると無限にfunctionが呼び出され続けてしまうという問題点があります。

(マイクラ コマンド・データパック) プレイヤのクリックを検知する方法

クリックを検知する

今回はプレイヤがクリックしたことを検知する方法を紹介します

目次

クリック検知する方法

エンティティのinteractionを利用することでプレイヤのクリックを検知することができます。
interactionエンティティは左クリックしたエンティティと右クリックしたエンティティのUUIDをそれぞれattackとinteractionというnbtに格納するので、ここに書かれているUUIDを持ったプレイヤを対象にコマンドを実行することで、クリックしたプレイヤを対象にコマンドを実行できます。

  • まず、毎tick以下のコマンドを実行することにより、プレイヤの頭の部分に常にinteractionが存在している状態にする。

    まず、以下のようにexecuteコマンドのanchoredを使うことによってプレイヤの頭の位置にinteractionエンティティを召喚します

  execute as @a at @s anchored eyes positioned ^ ^ ^ run summon interaction ~ ~-0.5 ~
  • interactionにattackとinteractionのnbtが存在しているかをしらべることでクリックを行なったプレイヤがいるかをしらべ、そのプレイヤを対象にコマンドを実行する。

    attackとinteractionのnbtに入っているUUIDのプレイヤに対して操作を行うのが正確ですが、ここでは一番近くのプレイヤをクリックを行なったプレイヤとして操作を行います。

    check.mcfunction

  # 左クリック
  execute as @e[type=interaction] if data entity @s attack at @s as @a[sort=nearest,limit=1] run say left click

  # 右クリック
  execute as @e[type=interaction] if data entity @s interaction at @s as @a[sort=nearest,limit=1] run say right click

これにより、左クリックを行なったプレイヤが入ればleft click、右クリックを行ったプレイヤが入ればright clickとチャットに表示されます

  • interactionをkillする

    このままでは1のコマンドによって無限にinteractionが召喚されるので、interactionをkillするコマンドも毎tick実行します。

    kill_interaction.mcfunction

  kill @e[type=interaction]

利用例

プレイヤが行なったクリックをチャットに表示する

シンプルにプレイヤが左クリックを行なったらleft click, 右クリックを行ったright clickと表示するfunctionです。
以下のコマンドを毎tick実行します。

click_check.mcfunction

# 左クリック
execute as @e[type=interaction] if data entity @s attack at @s as @a[sort=nearest,limit=1] run say left click

# 右クリック
execute as @e[type=interaction] if data entity @s interaction at @s as @a[sort=nearest,limit=1] run say right click


# 前のtickで召喚したinteractionをkill
kill @e[type=interaction]

# interactionを召喚
execute as @a at @s anchored eyes positioned ^ ^ ^ run summon interaction ~ ~-0.5 ~

実行結果

このようにチャットに行なったクリックが表示されます。

左クリックしたプレイヤの視点先に雷を落とす

左クリックしたプレイヤが向いている方向の10ブロック先に雷を落とすコマンドです。

実は、左クリックだけであればexecuteコマンドのon attackerを利用すると簡単にプレイヤを見つけられます。

以下のコマンドを毎tick実行

lightning.mcfunction

# 左クリックしたプレイヤが向いている方向の10ブロック先に雷を落とす
execute as @e[type=interaction] if data entity @s attack on attacker at @s anchored eyes positioned ^ ^ ^10 run summon lightning_bolt

# 前のtickで召喚したinteractionをkill
kill @e[type=interaction]

# interactionを召喚
execute as @a at @s anchored eyes positioned ^ ^ ^ run summon interaction ~ ~-0.5 ~

実行結果

このように、左クリックすると雷が落ちます

まとめ

interactionエンティティを利用することで、プレイヤの右クリックと左クリックを検知することができます。

(マイクラ コマンド・データパック) プレイヤが食べ物を食べたことをしらべる方法

食べ物を食べたことを検知する

今回は特定の食べ物を食べたことを検知してコマンドを実行する方法を紹介します。
これを利用すると、食べるとエフェクトのかかる食料を作ることができます。

目次

特定の食べ物を食べたことを検知する

スコアボードを使う方法

食べ物を食べたことはスコアボードを使うことで調べることができます。 あらかじめ、以下のコマンドを実行してスコアを作成します。

# eatという特定の食べ物を食べたことを検知するスコアを作成
scoreboard objectives add eat minecraft.used:minecraft.<検知したい食べ物>

そして、スコアが1以上になったプレイヤに対してコマンドを実行することで、その食べ物を食べたプレイヤに対してコマンドを動かせます。

# eatのスコアが1以上の時にそのプレイヤに耐性のエフェクトをかける
execute as @a if score @s eat matches 1.. run effect give @s minecraft:resistance 3 0
# スコアをリセットする
scoreboard players reset @a eat

advancementを利用する方法

advancementのconsume_itemを利用する方法でも食料を食べたことを検知することができます。
データパック内でdata/<名前空間>/advancements/<好きな名前>.jsonというようにファイルをつくり、以下のように記述します。

{
  "criteria": {
    "requirement": {
      "trigger": "minecraft:consume_item",
      "conditions": {
        "item": {
          "items": [
            "minecraft:<検知したい食べ物>"
          ]
        }
      }
    }
  }
}

そしてコマンドでこの進捗を達成しているプレイヤに対してコマンドを実行することで、食料を食べたプレイヤにコマンドを実行できます。

execute as @a[advancements={<名前空間>:<設定した名前>=true}] run effect give @s minecraft:resistance 3 0
advancement revoke @a only <名前空間>:<設定した名前>

あるいは、以下のようにadvancementの達成報酬としてfunctionを実行する方法もあります。

<名前空間>:<設定した名前>.json

{
  "criteria": {
    "requirement": {
      "trigger": "minecraft:consume_item",
      "conditions": {
        "item": {
          "items": [
            "minecraft:<検知したい食べ物>"
          ]
        }
      }
    }
  },
  "rewards": {"<名前空間>:<function名>"}
}

<名前空間>:<function名>.mcfunction

effect give @s minecraft:resistance 3 0
advancement revoke @s only <名前空間>:<設定した名前>

少し面倒に感じますが、function内で@s以外のセレクタを使う必要がなく、進捗が達成された時にしかfunctionを実行しなくていいので、処理が軽くなるという利点があります。

ケーキを食べたことを検知する場合

ケーキを食べたことを検知する場合、上記の方法では検知することができません。 以下のようなスコアボードを設定して、検知します。

# eat_cakeというケーキを食べたことを検知するスコアを作成
scoreboard objectives add eat_cake minecraft.custom:minecraft.eat_cake_slice

eat_cake.mcfunction

# eat_cakeのスコアが1以上の時にそのプレイヤに耐性のエフェクトをかける
execute as @a if score @s eat_cake matches 1.. run effect give @s minecraft:resistance 3 0
# スコアをリセットする
scoreboard players reset @a eat_cake

複数の食べ物のうちのどれかを食べたことを検知する場合

複数の食べ物うちのどれかを食べたことを検知したい場合には、単純にスコアの数を増やせば良いです。 しかし、スコアによって検知する方法では食べ物の数が増えると大変になる上、個別にexecute if コマンドを実行することになるので処理も重くなってしまいます。
以下に魚を食べたことを検知する例のスコアボードによる実装とadvancementによる実装をそれぞれ示します。

スコアボードによる実装

あらかじめ使用しておく

# スコアボードの作成
scoreboard objectives add eat_cod minecraft.used:minecraft.cod
scoreboard objectives add eat_cooked_cod minecraft.used:minecraft.cooked_cod
scoreboard objectives add eat_salmon minecraft.used:minecraft.salmon
scoreboard objectives add eat_cooked_salmon minecraft.used:minecraft.cooked_salmon
scoreboard objectives add eat_pufferfish minecraft.used:minecraft.pufferfish
scoreboard objectives add eat_tropical_fish minecraft.used:minecraft.tropical_fish

検知用function

# 魚を食べたプレイヤにエフェクトをかける
execute as @a if score @s eat_cod matches 1.. run effect give @s minecraft:resistance 3 0
execute as @a if score @s eat_cooked_cod matches 1.. run effect give @s minecraft:resistance 3 0
execute as @a if score @s eat_salmon matches 1.. run effect give @s minecraft:resistance 3 0
execute as @a if score @s eat_cooked_salmon matches 1.. run effect give @s minecraft:resistance 3 0
execute as @a if score @s eat_pufferfish matches 1.. run effect give @s minecraft:resistance 3 0
execute as @a if score @s eat_tropical_fish matches 1.. run effect give @s minecraft:resistance 3 0
# スコアをリセットする
scoreboard players reset @a eat_cod
scoreboard players reset @a eat_cooked_cod
scoreboard players reset @a eat_salmon
scoreboard players reset @a eat_cooked_salmon
scoreboard players reset @a eat_pufferfish
scoreboard players reset @a eat_tropical_fish

advancementによる実装

eat_fish.json

{
  "criteria": {
    "requirement": {
      "trigger": "minecraft:consume_item",
      "conditions": {
        "item": {
          "items": [
            "minecraft:tropical_fish",
            "minecraft:pufferfish",
            "minecraft:cooked_salmon",
            "minecraft:salmon",
            "minecraft:cooked_cod",
            "minecraft:cod"
          ]
        }
      }
    }
  },
  "rewards": {"<名前空間>:eat_fish"}
}

eat_fish.mcfunction

effect give @s minecraft:resistance 3 0
advancement revoke @s only <名前空間>:eat_fish

このように、検知したい食べ物の種類が複数ある場合には、advancementを使った方が簡単で、処理も軽くなります。

全ての食べ物のうちのどれかを食べたことを検知したい

おまけとして、全ての食べ物のうちのどれかを食べたことを検知するadvancementを載せておきます

eat_food.json

{
  "criteria": {
    "requirement": {
      "trigger": "minecraft:consume_item",
      "conditions": {
        "item": {
          "items": [
            "minecraft:suspicious_stew",
            "minecraft:rabbit_stew",
            "minecraft:beetroot_soup",
            "minecraft:mushroom_stew",
            "minecraft:spider_eye",
            "minecraft:rotten_flesh",
            "minecraft:pumpkin_pie",
            "minecraft:cookie",
            "minecraft:bread",
            "minecraft:pufferfish",
            "minecraft:tropical_fish",
            "minecraft:cooked_salmon",
            "minecraft:salmon",
            "minecraft:cooked_cod",
            "minecraft:cod",
            "minecraft:cooked_rabbit",
            "minecraft:rabbit",
            "minecraft:cooked_chicken",
            "minecraft:chicken",
            "minecraft:cooked_mutton",
            "minecraft:mutton",
            "minecraft:cooked_porkchop",
            "minecraft:porkchop",
            "minecraft:cooked_beef",
            "minecraft:beef",
            "minecraft:dried_kelp",
            "minecraft:beetroot",
            "minecraft:poisonous_potato",
            "minecraft:baked_potato",
            "minecraft:potato",
            "minecraft:golden_carrot",
            "minecraft:carrot",
            "minecraft:chorus_fruit",
            "minecraft:glow_berries",
            "minecraft:sweet_berries",
            "minecraft:melon_slice",
            "minecraft:enchanted_golden_apple",
            "minecraft:golden_apple",
            "minecraft:apple"
          ]
        }
      }
    }
  }
}

これと、ケーキを食べたことを検知する方法を利用することで、プレイヤが何かアイテムを食べたことを検知できます。

まとめ

特定の食べ物を食べたことを検知する場合にはスコアボードかadvancementを使うことができます。
検知したい食べ物が1,2個程度で比較的少ない場合にはスコアボードによる実装が簡単ですが、検知したい食べ物がたくさんある場合にはadvancementを使って実装する方が簡単で処理も軽くなります。

(マイクラ データパック) 現在の天候を調べてコマンドを実行する

現在の天候を調べる

今回は現在の天候を調べてコマンドを実行する方法について紹介します。

目次

天候の調べ方

データパック限定の手段にはなりますが、predicateのweather_checkを利用することで現在の天候を調べることができます。

雨が降っているか調べる

データパックのdata/<名前空間>/predicates内に<好きな名前>.jsonという名前のファイルを作成し、以下のように記述します。

rain.json

{
  "condition": "minecraft:weather_check",
  "raining": true
}

そして、function内でexecute if predicateなどを利用することにより、天候を検知してコマンドを呼び出せます。

# 雨が降っている時、rainingとチャットに表示する。
execute if predicate <名前空間>:rain run say raining

晴れているかを調べる

json内の"raining"をfalseにするだけで検知できます。

sunny.json

{
  "condition": "minecraft:weather_check",
  "raining": false
}

雷雨の時のみを調べる

json内で"raining"ではなく、"thundering"を指定することで検知できます。

{
  "condition": "minecraft:weather_check",
  "thundering": true
}

応用例

次に天候の検知を応用したコマンドを紹介します。

雨に当たっているプレイヤをkillする

地表にいるプレイヤを検知するでも紹介しましたが、雨が降っていることの検知と、プレイヤの頭上にブロックがないことを検知することにより、雨に当たっているプレイヤを検知することができます。 functionはこんな感じ。

# 雨に当たっているプレイヤに風邪をひいてしまったと発言させる。
execute as @a at @s positioned over world_surface if entity @s[dy=0] if predicate test:rain run say は雨に当たって風邪をひいてしまった。

# 雨に当たっているプレイヤをkill
execute as @a at @s positioned over world_surface if entity @s[dy=0] if predicate test:rain run kill @s

雨が降っている時に走ったプレイヤをkillする

走っていることは事前に/scoreboard objectives add running minecraft.custom:minecraft.sprint_one_cmで走った距離を検知するスコアボードを作っておくことで調べられます。

コマンドの実装はこのようになります。

# 雨に当たっており、走った距離を検知するスコアが1以上なら滑って転んでしまったと発言させる
execute as @a if score @s runnning matches 1.. if predicate test:rain run say は滑って転んでしまった。

# そのプレイヤをkill
execute as @a if score @s runnning matches 1.. if predicate test:rain run kill @s

# 走ったことを検知するスコアをリセット
scoreboard players reset @a running

まとめ

天候を調べるときはpredicateのweather_checkを利用することで調べることができます。

(マイクラ コマンド・データパック) 複数の種類のエンティティを対象にしてコマンドを実行する

複数の種類のエンティティを指定してコマンドを実行する

今回は、複数の種類のエンティティを対象にしてコマンドを実行する方法について書いていきます。

目次

セレクタのtype引数は一度に複数回使えない......

複数の種類のエンティティを対象として実行しようとすると、まずは以下のようなコマンドが思い浮かぶと思います。

# エラーになる例
kill @e[type=cow,type=pig]

このようなコマンドはエラーになってしまいます。
セレクターの引数であるtypeは1度に複数回使えないからです。
(そもそも、このような文では牛であり豚でもあるエンティティという訳のわからないエンティティを指定することになるため、実行できたとしても思った通りには動作しないと思われます。)

どうやって複数のエンティティを対象にするか

上記のように、単にtype引数を複数並べるだけではエラーとなってしまい、複数のエンティティを指定することはできません。

最も簡単な解決策

シンプルな解決策として、コマンドの数を増やすというものがあります。

kill @e[type=cow]
kill @e[type=pig]

このように一度に使うtype引数を1つにして、同じコマンドを複数回実行すれば、複数のエンティティを対象に実行できます。

何度も同じ対象を呼び出す場合

何度も同じ対象にコマンドを実行する場合、あらかじめタグをつけておくをつけておくことで以降の呼び出しを簡単にできます。

#対象に同じタグをつけておく
tag @e[type=cow] add cow_or_pig
tag @e[type=pig] add cow_or_pig

# 先にタグをつけておけば1コマンドで指定できる
execute @e[tag=cow_or_pig] say yes
kill @e[tag=cow_or_pig]

1コマンドで対象を指定する方法

上記のような方法では指定したいエンティティの種類が増えてくるとコマンドの数がとても多くなってしまうため、書くのがとても大変になります。
そこで、1コマンドだけで複数のエンティティを対象にする方法を紹介します。

execute as @e unless entity @s[type=!cow,type=!pig] run kill @s

このように書くことで、1コマンドだけで豚と牛の両方をkillすることができます。
先ほど、type引数は一度に1回しか使えないと言いましたが、実は、type=!<エンティティ>という形でそのエンティティ以外を対象にしたい場合には一度に何度も使うことができます。

この性質を利用して、牛でも豚でもないエンティティ以外のエンティティを対象としてコマンドを実行することで、牛と豚のみを対象にとることができます。

entity_typesを利用する方法

最後に、データパックでのみ使える方法ですが、entity_typesを用いて複数の対象を指定する方法を紹介します。

データパックのdata/<名前空間>/tags/entity_typesに、<好きな名前>.jsonというファイルを作り、以下のように記述します。

{
  "values": [
    "pig",
    "cow"
  ]
}

こうすることにより、以下のようにしてこのファイルに書いたエンティティを対象にコマンドを実行できます。

kill @e[type=#<名前空間>:<指定した名前>]

一見、これはとても面倒な方法に思えますが、対象にとるエンティティを後から変えたくなった場合に、先ほど記述したjsonファイルの中身を変えるだけで全てのコマンドの対象が変化するため、管理がとても楽になるという利点があります。

まとめ

複数種類のエンティティを対象にコマンドを実行したい場合には以下の要な方法があります。

  • コマンドの数自体を増やす
  • execute unlessを利用する
  • entity_typesを利用する

それぞれの方法に利点と欠点があると思うので用途に合わせて使い分けていきましょう。