えいまぼJEブログ

Minecraft Java Editionに関していろいろ書きます

着火されたTNTの速度と座標の計算式【Minecraft JE 1.16.5】

1. はじめに

TNTキャノン開発者向けに、着火されたTNTの速度と座標の計算式を掲示します。

検証環境はMinecraft Java Edition 1.16.5になります。

TNTの速度の計算はy、r、θの円筒座標系で行われているようです。 回転成分(θ)は計算に関係ないため、高さ成分(y)と中心軸からの半径(r)のみ掲載しています。

また、この記事中のtickはゲームティックであり、1tick = 1/20秒 とします。

2. 速度

y成分

文献*1*2より、着火されたTNTの速度のy成分v_y[block/tick]は

\displaystyle v_y = (v _ {0y} + 1.96)  \times 0.98 ^ {20t - 1} - 1.96

となります。 ただし、v _ {0y}はy方向の初速度[block/tick]、tは時間[秒]です。

なお、この記事での初速度は外部からTNTの爆発などで推進力を得た瞬間のフレームの速度としています。ただし、時間tは推進力を得るフレームの1tick前のフレームを0として計算します。

r成分

文献*3より、着火されたTNTの速度の半径成分v_r[block/tick]は

\displaystyle v_r = v _ {0r} \times 0.98 ^ {20t - 1}

となります。 ただし、v _ {0r}はr方向の初速度[block/tick]、tは時間[秒]です。

原文のツイートは統合版でしたが、Java版でもそのままの式が当てはまりました。ただし、レッドストーンティックから秒に変換する関係で累乗の中の数は変わっています*4

3. 座標

毎フレームのTNTの座標を階差数列とみなして*5、その一般項を求めることで座標の計算式を導出します。後述しますが、積分で導出すると値が小さくなるため、数列での解決になりました。

y成分

着火されたTNTのy座標 y [block]は

\displaystyle y = y _ 0 + 50 \times (v _ {0y} + 1.96) \times (1 - 0.98 ^ {20t}) - 39.2 \times t

となります。 ただし、v _ {0y}はy方向の初速度[block/tick]、tは時間[秒]、y _ 0は着火されたTNTが推進力を得るフレームの1tick前のフレームのy座標です。 補足すると、初速度はその1tick後、つまり推進力を得た瞬間のフレームの速度となります。

r成分

着火されたTNTの半径方向 r [block]は

\displaystyle r = 51 \times v _ {0r}\times (1 - 0.98 ^ {20t})

となります。 ただし、v _ {0r}はr方向の初速度[block/tick]、tは時間[秒]です。

4. 実際に計算する

適当なTNTキャノンで打った弾頭の速度、座標(弾道)を計算式で算出し、実際の値と比較していきます。

速度

横軸を時間として、速度のy成分・r成分をそれぞれグラフに表します。

f:id:rslatch:20210608172831p:plain
速度のy成分のグラフ

f:id:rslatch:20210608172902p:plain
速度のr成分のグラフ

青い線がMinecraft内で観測したデータで、オレンジの線が計算式で算出した値です。

グラフを見ると、y成分・r成分ともに観測値と計算値がよく一致しています。 なお、時刻0の部分は推進力を受ける直前のため、値は一致しません。

座標

横軸を時間として、座標のy成分・r成分をそれぞれグラフに表します。

f:id:rslatch:20210608173002p:plain
座標のy成分(y座標)のグラフ

f:id:rslatch:20210608173025p:plain
座標のr成分のグラフ

速度と同様、y成分・r成分ともに観測値と計算値がよく一致しています。

弾道

せっかくなので、弾道を出してみます。 横軸をr、縦軸をyにしてプロットします。

f:id:rslatch:20210608173055p:plain
TNTの弾道

同様に、観測値と計算値がよく一致しています。 空気抵抗の影響で後半の放物線が潰れているのが見てわかると思います。

5. あとがき

最近は全方位対応型のTNTキャノンを作っていて、弾道がわかると便利だと思い、計算式を探していました。 見つかった・導出した計算式が本当に正しいかを確かめるため、毎フレームのTNTの座標・速度を測定しました。この測定にはCarpet Modを使用しました。時間を止めたり、指定したティック数だけステップ的に時間を進められたりできるので検証が非常に楽でした。

この記事がTNTキャノン開発の一助になることを願います。

6. 付録: 導出のためのメモ

ここからは完全におまけで、座標の計算式導出のためのメモです。興味のある方のみご覧ください。

積分は値が小さい

まず、最初は座標の導出のために数列ではなく愚直に積分をしていました。 積分をすると、y成分・r成分は以下のようになるはずです。

y成分:

\displaystyle y = \frac{v _ {0y} + 1.96}{0.98 \ln(0.98)} \times (0.98 ^ {20t} - 1) - 39.2 t + y _ 0

r成分:

\displaystyle r = \frac{v _ {0r}}{0.98 \ln(0.98)} (0.98 ^ {20t} - 1)

しかし、この計算式だと本来より値が小さく出ます。

それに、離散的な値を連続であるとして計算しているのでどこかで誤差が出るはずです(出ました)。

そういうわけで、積分で導出した式は使えないということがわかりました。

階差数列で解く

積分はダメでした。マインクラフト防衛部さんのページ*6に載っている数列の一般項を求めることにします。とりあえず簡単なr成分の方を解いていくこととして、以下のような式を立てられるはずです。


\displaystyle R _ {n+1} = R _ n + f(n) \\\
\displaystyle R _ 0 = 0 \\\
\displaystyle f(n) = v _ {0r} \times 0.98 ^ n \\\
\displaystyle n = 20t

 R _ n nティックのフレームの rとしました。

これを解くために、公式*7を使います。以下のような公式でした。


\displaystyle R _ n = R _ 0 + \sum _ {k=0} ^ {n - 1} f(k)

この公式の右辺の2項目は等比数列の和ですので、解けます。等比数列の和の公式*8を使って、


\displaystyle R _ n = R _ 0 + v _ {0r} \times \frac{1 - 0.98 ^ n}{0.02}

となります。また、 R _ 0 = 0であり、  n = 20tなので、


\displaystyle r = v _ {0r} \times \frac{1 - 0.98 ^ {20t}}{0.02}

となります。なお、勝手に r = R _ nとしましたがこれでも大丈夫です。

少し整形すると以下のようになり、はじめに紹介した計算式に近づきました。


\displaystyle r = 50 \times v _ {0r} \times (1 - 0.98 ^ {20t})

なお、y成分も同じようにして解くことができます。詳しい解説は省略します。

r成分の謎の1.02倍

しかしながら、このようにして数列の一般項を求めても、r成分だけはなぜか観測値よりも小さく出ます。 速度の観測値を数値積分していっても 50 \times v _ {0r} \times (1 - 0.98 ^ {20t})と同じ値が出るため、私の導出に間違いはないようです。おそらく、Minecraft内で速度を座標に変換するときに変な処理がされていると思われます。

このとき、積分で解いたときに少し値が小さく出たことを思い出し、定数倍すれば観測値と合うのでは?と考えました。適当に定数倍をしていき、1.02倍するとバッチリ合いました(50 × 1.02 = 51)。一応他の射撃パターンでも合うか確認しましたが、どれも合致しました。多分これが一番正確だと思います。また、1.02は2-0.98であり、一応関係ありそうな値です。とりあえずこれでFAとします。

あまり気持ちの良い解決方法ではないので、なにか理論的な導出方法があれば教えていただきたいです。

*1:日本語: https://minecraftjapan.miraheze.org/wiki/%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%83%86%E3%82%A3

*2:英語Wiki: https://minecraft.fandom.com/wiki/Entity

*3:たいぼんさんツイート: https://twitter.com/taibon852/status/1065551923351216130

*4:元のツイートの値は0.96035でしたが、それを0.5乗すると0.98に極めて近い値になります。切りの良い数字なので、そのまま0.98としました。

*5:マインクラフト防衛部: http://blog.livedoor.jp/minecraft_boueibu/archives/1059975020.html

*6:ちなみにこのページにはy成分しか載っていませんが、基本的な考え方はr成分にも適用できます。

*7:漸化式と一般項(階差形): https://www.geisya.or.jp/~mwm48961/electro/recurr_series1.htm

*8:等比数列の和: https://www.kwansei.ac.jp/hs/z90010/sugakua/suuretu/touhisum/touhisum.htm