ルッキーのコマンドメモ

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

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

ループ処理を行いたい

データパックを書いているとプログラムの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が呼び出され続けてしまうという問題点があります。