RPGツクールと数学のブログ

RPGツクールと数学についてのブログです。

アクションRPGの基礎(RPG2000)(応用編 鉄球)

過去ブログの転載です。

敵が鉄球をぐるぐる回してくる処理を作ってみます。簡単のため鉄球の棒部分に当たり判定はなく、丸い鉄球部分のみ当たり判定があるようにします。数学を使いますよ。

f:id:fermiumbay13:20190801133420p:plain

↑「鉄球.png
回転させるので、縦の半分より上に鉄球があります。

f:id:fermiumbay13:20190801133439p:plain

ピクチャーの表示で「回転描画」を設定すると回転させられますが、こいつの当たり判定を取得するには、鉄球部分がいまどこにあるかを正確にする必要があります。回転速度を計算する必要があるんですよね。

色々測定した結果、ピクチャーの回転角速度は個人的な推定式で以下として表されるようです。

回転速度Sのときのピクチャー回転角速度

ω=45S/32[°/f]

 1フレーム=1/60秒ですので、1/60秒で45S/32 °回転するということです。S=5なら1秒で421.875°(1回転ちょっと)回るということですね。延々回して検証しましたけど、とりあえず誤差なく合っていそうです。

f:id:fermiumbay13:20190801133455p:plain

↑(tx,ty)は敵の座標、(ax,ay)は鉄球の座標、(hx,hy)は主人公の座標です。

素材では、棒から鉄球の中心までの距離R=64[dot]、鉄球の半径r=16[dot]、としています。また、主人公の当たり判定半径rh=8[dot]としておき、鉄球の回転角度をθとしておきます。

鉄球の中心から主人公の中心までの距離Hが(r+rh)未満になったとき、主人公の当たり判定が鉄球に当たることになるので、ダメージを受けることになります。

三平方の定理から

 (a_{x}-h_{x})^{2}+(a_{y}-h_{y})^{2}\lt(r+r_{h})^{2}

が成り立つとき、主人公は鉄球に当たっています。一方、鉄球の座標(ax,ay)は図をもとに次のように表せるとわかります。

 \begin{cases} a_{x}=t_{x}+R\sin\theta \\ a_{y}=t_{y}-R\cos\theta \end{cases}

よって、これをさっきの式に入れれば、

 (t_{x}+R\sin\theta-h_{x})^{2}+(t_{y}-R\cos\theta-h_{y})^{2}\lt(r+r_{h})^{2}

が得られます。左辺を計算して、右辺より小さいかどうか判断させればいいわけです。

変数は以下のとおり:

150番「鉄球:X」
151番「鉄球:Y」
152番「鉄球:経過時間」
153番「鉄球:角度」
154番「鉄球:当たり判定X」
155番「鉄球:当たり判定Y」
156番「鉄球:ダメージ時間」
157番「正弦関数:角度」
158番「正弦関数:結果」
159番「正弦関数:一時」
160番「正弦関数:結果係数」

三角関数の計算はそのうち新ホームページに載せようと思ってますけれど、とりあえず以下で計算できます:

正弦関数
◆変数の操作:[0160:正弦関数:結果係数]代入,1
◆条件分岐:変数[0157:正弦関数:角度]が0より小さい
 ◆変数の操作:[0157:正弦関数:角度]乗算,-1
 ◆変数の操作:[0160:正弦関数:結果係数]乗算,-1
 ◆
:分岐終了
◆条件分岐:変数[0157:正弦関数:角度]が360より大きい
 ◆変数の操作:[0157:正弦関数:角度]剰余,360
 ◆
:分岐終了
◆条件分岐:変数[0157:正弦関数:角度]が270より大きい
 ◆変数の操作:[0157:正弦関数:角度]減算,360
 ◆変数の操作:[0157:正弦関数:角度]乗算,-1
 ◆変数の操作:[0160:正弦関数:結果係数]乗算,-1
 ◆
:それ以外の場合
 ◆条件分岐:変数[0157:正弦関数:角度]が180より大きい
  ◆変数の操作:[0157:正弦関数:角度]減算,180
  ◆変数の操作:[0160:正弦関数:結果係数]乗算,-1
  ◆
 :それ以外の場合
  ◆条件分岐:変数[0157:正弦関数:角度]が90より大きい
   ◆変数の操作:[0157:正弦関数:角度]減算,180
   ◆変数の操作:[0157:正弦関数:角度]乗算,-1
   ◆
  :分岐終了
  ◆
 :分岐終了
 ◆
:分岐終了
◆変数の操作:[0159:正弦関数:一時]代入,変数[0157]の値
◆変数の操作:[0159:正弦関数:一時]乗算,変数[0157]の値
◆変数の操作:[0159:正弦関数:一時]乗算,64
◆変数の操作:[0159:正弦関数:一時]除算,2025
◆変数の操作:[0158:正弦関数:結果]代入,変数[0159]の値
◆変数の操作:[0158:正弦関数:結果]乗算,-20
◆変数の操作:[0158:正弦関数:結果]加算,12000
◆変数の操作:[0159:正弦関数:一時]乗算,変数[0159]の値
◆変数の操作:[0159:正弦関数:一時]除算,100
◆変数の操作:[0158:正弦関数:結果]加算,変数[0159]の値
◆変数の操作:[0158:正弦関数:結果]乗算,変数[0157]の値
◆変数の操作:[0158:正弦関数:結果]除算,6750
◆変数の操作:[0158:正弦関数:結果]乗算,変数[0160]の値

敵の行動:

◆ウェイト:2.0秒
◆条件分岐:変数[0022]が999999以外
 ◆効果音の演奏:大地2
 ◆変数の操作:[0150:鉄球:X]代入,EV0002の画面X
 ◆変数の操作:[0151:鉄球:Y]代入,EV0002の画面Y
 ◆変数の操作:[0151:鉄球:Y]減算,8
 ◆変数の操作:[0152~0153]代入,0
 ◆ピクチャーの表示:10,鉄球,(V[0150],V[0151])【透明色あり、回転速度5】
 ◆繰り返し処理
  ◆変数の操作:[0150:鉄球:X]代入,EV0002の画面X
  ◆変数の操作:[0151:鉄球:Y]代入,EV0002の画面Y
  ◆変数の操作:[0151:鉄球:Y]減算,8
  ◆ピクチャーの移動:10,(V[0150],V[0151]),0.0秒【ウェイトなし、透明色あり、回転速度5】
  ◆条件分岐:変数[0156:鉄球:ダメージ時間]が0
   ◆変数の操作:[0153:鉄球:角度]代入,変数[0152]の値
   ◆変数の操作:[0153:鉄球:角度]乗算,225
   ◆変数の操作:[0153:鉄球:角度]除算,32
   ◆変数の操作:[0157:正弦関数:角度]代入,変数[0153]の値
   ◆イベントの呼び出し:正弦関数
   ◆変数の操作:[0158:正弦関数:結果]乗算,64
   ◆変数の操作:[0158:正弦関数:結果]除算,100
   ◆変数の操作:[0154:鉄球:当たり判定X]代入,EV0002の画面X
   ◆変数の操作:[0154:鉄球:当たり判定X]加算,変数[0158]の値
   ◆変数の操作:[0154:鉄球:当たり判定X]減算,主人公の画面X
   ◆変数の操作:[0154:鉄球:当たり判定X]乗算,変数[0154]の値
   ◆変数の操作:[0157:正弦関数:角度]代入,変数[0153]の値
   ◆変数の操作:[0157:正弦関数:角度]加算,90
   ◆イベントの呼び出し:正弦関数
   ◆変数の操作:[0158:正弦関数:結果]乗算,64
   ◆変数の操作:[0158:正弦関数:結果]除算,100
   ◆変数の操作:[0155:鉄球:当たり判定Y]代入,EV0002の画面Y
   ◆変数の操作:[0155:鉄球:当たり判定Y]減算,変数[0158]の値
   ◆変数の操作:[0155:鉄球:当たり判定Y]減算,主人公の画面Y
   ◆変数の操作:[0155:鉄球:当たり判定Y]乗算,変数[0155]の値
   ◆変数の操作:[0154:鉄球:当たり判定X]加算,変数[0155]の値
   ◆条件分岐:変数[0154:鉄球:当たり判定X]が576より小さい
    ◆変数の操作:[0156:鉄球:ダメージ時間]代入,30
    ◆効果音の演奏:しびれ2
    ◆キャラクターのフラッシュ:主人公,0.5秒(赤31緑0青0強さ31、ウェイトなし)
    ◆キャラクターの動作指定:主人公,ジャンプ開始,180度方向転換,一歩前進,ジャンプ終了
    ◆HPの増減:メンバー全員のHPを5減らす
    ◆
   :分岐終了
   ◆
  :分岐終了
  ◆変数の操作:[0152:鉄球:経過時間]加算,1
  ◆条件分岐:変数[0156:鉄球:ダメージ時間]が0より大きい
   ◆変数の操作[0156:鉄球:ダメージ時間]減算,1
   ◆
  :分岐終了
  ◆ウェイト:0.0秒
  ◆条件分岐:変数[0152:鉄球:経過時間]が150以上
   ◆繰り返し処理の中断
   ◆
  :分岐終了
  ◆
 :以上繰り返し
 ◆ピクチャーの消去:10
 ◆
:分岐終了

2秒おきに、敵2番(ダメージ量は変数22番に管理)が鉄球を放ってきます。
鉄球の座標は敵2番の画面座標から出します。ただし、キャラクターから得られる画面Yは足元の座標になりますので、中心に合わせるために画面Yだけ8減算したものを入れます。鉄球を放ってからの経過時間と鉄球の回転角度を0にし、鉄球を表示させます。
ここでは、回転速度を5としています。

鉄球を表示したら、2.5秒間鉄球が回ります。繰り返し処理を入れ、常に鉄球の座標を取得して表示(ピクチャーの移動)するようにします。

鉄球によるダメージを連続で受けないように、変数「鉄球:ダメージ時間」というものを用意します。ここでは0.5秒間はダメージを受けないようにしたいので、鉄球に当たったら30(フレーム)を代入し、1/60秒ごとに1ずつ減らします。これが0になっていないと、鉄球によるダメージ処理は行わないようにします。

鉄球のダメージ処理では、まず鉄球の角度を取得します。
θ=ωt  ω=45S/32[°/f]
ですので、経過時間を代入し、角速度を掛け算します。

回転速度5にしているので、ω=225/32[°/f]となりますから、経過時間を225倍して32で割ったものを角度に代入します。回転速度を変えるときは、ピクチャーの表示と移動のほか、ここの数値だけ変えればOKです。

次に、当たり判定の不等式の左辺を計算します。sinθを計算するため、θを使って「正弦関数」を呼び出し、「結果」に計算結果の100倍を代入します。
(例:sin30°=0.5 なので、「結果」には50が代入される)
これを、R倍すれば良いのですから、R=64より、64を掛けます。sinの計算結果は実際の値の100倍なので、更にこれを100で割ります。これでRsinθが計算できました。これに敵の画面Xを足し、主人公の画面Xを引いて2乗すれば、X成分は終わりです。

Y成分ではRcosθを計算します。cosθ=sin(θ+90°)なので、角度に90足したものを「正弦関数」に入れれば良いです。同様に式通り足し算引き算します。画面Yは前述通り足元の座標なので、中心にするために8引きます。

X成分+Y成分で左辺の式になります。これを「当たり判定X」に代入します。右辺の値は(r+rh)^2=(16+8)^2=576になるので、当たり判定Xにいま代入された値が576より小さいとダメージです。ダメージの処理を入れ、ダメージ時間を30に設定します。

ダメージ時間は0より大きいとき1ずつ減算します。経過時間は1/60秒おきに1ずつ加算されるため、0.0秒ウェイトの所に入れています。経過時間が2.5秒=150フレーム以上になれば終わりなので、繰り返し中断して鉄球のピクチャーを消去すればおしまいです。