Hatena::Groupfatalemployeetraining

資材部の懲りない面々・あれこれブログ

「間違った社員教育」製品版委託頒布中!

2011-06-09

レーダー索敵スクリプトについて

| 20:50

Sphere Engine研究所, 制作日誌003 スクリプトにて、レーダー照射範囲を円錐状と見立てて索敵可能エリアを限定するスクリプトが紹介されています。

素敵なことしてますねー。

うちは初心者向けミッションなのでこれを使わせてもらうのは難易度的にはアレなんですが、こういうスクリプトはかっこいいので好きです。

よくわからなかった人のために先方の解説を補足すると、自機から機体へのばしたベクトル\mathbf{a}(長さがR)、自機のレーダー照射範囲円錐の軸方向単位ベクトル\mathbf{e}(長さが1)とし、2つのベクトルの成す角を\thetaとすると、ベクトル内積の公式から、

   \mathbf{a}\cdot\mathbf{e} = |\mathbf{a}||\mathbf{e}|\cos \theta = R \cos \theta

   \cos \theta = \frac{\mathbf{a}\cdot\mathbf{e}}{R}

となります。レーダー照射範囲である円錐の半頂角を\varphiとすると、\cos \theta < \cos \varphiならば、 \theta >  \varphiですから、敵機は円錐の外にいることになります。

で、該当処理のincファイル読んだ感想をば。


real_rader_thread.incについて。

12行目~40行目のループ、ちょっとわかりづらいのでfor文を使って整理した方がよいように感じました。

また、27行目のsystem();があると、1機の索敵処理をするたびに1ステップ(1フレーム)時間が経過してしまいます。それが意図した動作ならかまわないのですが、そうでないならば(1ステップ中に全機の索敵処理を済ませるつもりならば)27行目のsystem();は不要のように感じました。

こんな感じでおなじ動作になると思いますが…

	while(TRUE){
		system();
		for(rader_target = 101; rader_target <= enemy_total; rader_target++){
			//敵の生死確認
			R_enemy_destroyed = get_status("ALL_LABEL", rader_target);
			//破壊済みならフラグを0に
			if (R_enemy_destroyed == 0) {
				enemy_flag[rader_target] = 0;
			}
			//フラグが0ではなくかつ6でもないならば
			if(enemy_flag[rader_target] != 0||enemy_flag[rader_target] != 6)
				system(); //←不要かも?(ブログ本文参照)
				bsccd_length = get_length(0, rader_target); // 自機と敵との距離を測定
				if (bsccd_length <= 100) { //600以内なら発見
					rader_total(1);	//最終処理へ
				}
				else {					
					rader_azimuth(); //発見しなければ次(円錐状索敵チェック)へ
				}
			}
		}
	}

radian.incについて。

肝のcos_azimuth関数についてですが、35行目、変数R(自機と敵機の間の距離)をint(整数)で宣言すると精度が落ちてしまうと思います。floatでいいんじゃないでしょうか。

	float R = get_length(label_A, label_B);

この関数はRの値が0に近づくと精度が極端に悪化し、0になると計算できなくなりますが、それについては先ほどのrader_loop()の処理内のif文で除外できてる(そういう場合は実行されない)ので問題ないですね。

ご託はいいから遊んでみれば…ということで

| 00:35

飛んでみました。

そしてなすすべもなく物量に押し負けるorz

索敵範囲に入らないとロックオンマーカーが出ないのはなかなかいい感じです。

マーカーでなくなっても(内部的に'OBJECT'扱いになっても)'ENEMY'状態のうちに視点ロックすると持続するのね。

これはおもしろいことを知った。

押し寄せる実際の編隊をすべてイベントシーンとして見せつつ、開始するとレーダーには見えない!とかになってくると「こええええええ!見えねえええええ!」とさらに恐怖をあおられて楽しくなりそうです。

あ…っと。もう一つ検算。

| 23:03

レーダーの円錐軸が機体軸に一致する場合、機体が真北・水平を向いている場合、

 \mathbf{e}=\left(\begin{array}0\\0\\1\end{array}\right)

となります。

機体のピッチ角が \psi _p、方位角が \psi _vの場合、さきほどの \mathbf{e}を、x軸(東方向)まわりに \psi _p回してから、y軸(鉛直軸まわり)に \psi _v回せばいいです。回転行列をかけると

 \mathbf{e}=\left(\begin{array}\cos \psi_v&0&\sin \psi_v\\0&1&0\\-\sin \psi_v&0&\cos \psi_v \end{array}\right)\left(\begin{array}1&0&0\\0&\cos \psi_p&\sin \psi_p\\0&-\sin \psi_p&\cos \psi_p \end{array}\right)\left(\begin{array}0\\0\\1\end{array}\right)

となります(数学の教科書と違うように見えるかもしれませんが、RSのxyz座標系にマッチするようにするとこうなる…はず)。

すると、

 \mathbf{e} = \left(\begin{array}\sin \psi_v \cos \psi_p\\\sin \psi_p\\\cos \psi_v \cos \psi_p\end{array}\right)

となりますね。(…手計算なのでちょっと心配ですが。)

radian.incの45行目を見ると、一見よさそうに見えます。

が、問題は、レーダー軸が機体軸に対し、相対ピッチ角 \phi _p相対方位角 \phi _vずれている場合についての処理です。

この場合、上記行列演算を行う前に、事前に相対角変化ぶんの回転行列をかけねばなりません。(単純に+すればいいわけではないです。)

つまり、まず

 \left(\begin{array}\cos \phi_v&0&\sin \phi_v\\0&1&0\\-\sin \phi_v&0&\cos \phi_v \end{array}\right)\left(\begin{array}1&0&0\\0&\cos \phi_p&\sin \phi_p\\0&-\sin \phi_p&\cos \phi_p \end{array}\right)

をかけてから

 \left(\begin{array}\cos \psi_v&0&\sin \psi_v\\0&1&0\\-\sin \psi_v&0&\cos \psi_v \end{array}\right)\left(\begin{array}1&0&0\\0&\cos \psi_p&\sin \psi_p\\0&-\sin \psi_p&\cos \psi_p \end{array}\right)

をかけます。

つまり

 \fs1 \mathbf{e}=\left(\begin{array}\cos \psi_v&0&\sin \psi_v\\0&1&0\\-\sin \psi_v&0&\cos \psi_v \end{array}\right)\left(\begin{array}1&0&0\\0&\cos \psi_p&\sin \psi_p\\0&-\sin \psi_p&\cos \psi_p \end{array}\right)\left(\begin{array}\cos \phi_v&0&\sin \phi_v\\0&1&0\\-\sin \phi_v&0&\cos \phi_v \end{array}\right)\left(\begin{array}1&0&0\\0&\cos \phi_p&\sin \phi_p\\0&-\sin \phi_p&\cos \phi_p \end{array}\right)\left(\begin{array}0\\0\\1\end{array}\right)

となります。

手計算の結果ですが、

 \mathbf{e} = \left(\begin{array}e_x\\e_y\\e_z\end{array}\right)

 \fs1 e_x = \cos \psi_v \sin \phi_v \cos \phi_p - \sin \psi_v \sin \psi_p \sin \phi_p + \sin \psi_v \cos \psi_p \cos \phi_v \cos \phi_p

 \fs1 e_y = \cos \psi_v \sin \phi_p + \sin \psi_p \cos \phi_v \cos \phi_p

 \fs1 e_z = -\sin \psi_v \sin \phi_v \cos \phi_p -\cos \psi_v \sin \psi_p \sin \phi_p +\cos \psi_v \cos \psi_p \cos \phi_v \cos \phi_p

となるようです。(ちょっと量が多いのであやしいですが…)確認しました。

radian.inc中では、

 e_x = \sin (\psi_v + \phi_v) \cos (\psi_v + \phi_v)

 e_y = \sin (\psi_p + \phi_p)

 e_z = \cos (\psi_v + \phi_v) \cos (\psi_v + \phi_v)

となっているようですが、三角関数の公式を使って整理展開してもこれらは一致しないように見えます。

単純に真後ろを向いている後方警戒レーダーの計算の場合でも、両者は結果が異なります。

(例えば e_yに値を入れた結果を見てみてください。)

一度検算してみていただいたほうがよいと思います。

スクリプトの改善に役立てば幸いです。

3次元の回転についての参考:座標変換(東北大・ロボット基礎工学)


追記…

| 23:47

作者様ご自身のご指摘があったのですが、これ、円錐軸を斜めに向ける時点で、機体のバンク角も考慮しないといけませんね。ということはもう一個行列をかける必要がありますね。

RSEの場合はバンク(z軸まわり)→ピッチ(x軸まわり)→方位(y軸まわり)の順に回せばいいはずなので…機体のバンク角 \psi_bとするなら

 \fs1 \mathbf{e}=\left(\begin{array}\cos \psi_v&0&\sin \psi_v\\0&1&0\\-\sin \psi_v&0&\cos \psi_v \end{array}\right)\left(\begin{array}1&0&0\\0&\cos \psi_p&\sin \psi_p\\0&-\sin \psi_p&\cos \psi_p \end{array}\right)\left(\begin{array}\cos \psi_b&-\sin \psi_b&0\\\sin \psi_b&\cos \psi_b&0\\0&0&1\end{array}\right)\left(\begin{array}\cos \phi_v&0&\sin \phi_v\\0&1&0\\-\sin \phi_v&0&\cos \phi_v \end{array}\right)\left(\begin{array}1&0&0\\0&\cos \phi_p&\sin \phi_p\\0&-\sin \phi_p&\cos \phi_p \end{array}\right)\left(\begin{array}0\\0\\1\end{array}\right)

になります。


計算してみます。

 \mathbf{e} = \left(\begin{array}e_x\\e_y\\e_z\end{array}\right)

 \fs1\begin{array}{lcl}e_x&=&\cos \phi _p (\sin \phi _v (\cos \psi _b \cos \psi _v-\sin \psi _b \sin \psi _p \sin \psi _v)+\cos \phi _v \cos \psi _p \sin \psi _v)\\&&+\sin \phi _p (\sin \psi _b (-\cos \psi _v)-\cos \psi _b \sin \psi _p \sin \psi _v)\end{array}

 \fs1 e_y = \cos \phi _p (\sin \phi _v \sin \psi _b \cos \psi _p+\cos \phi _v \sin \psi _p)+\sin \phi _p \cos \psi _b \cos \psi _p

 \fs1\begin{array}{lcl}e_z&=&\cos \phi _p (\sin \phi _v (\sin \psi _b \sin \psi _p (-\cos \psi _v)-\cos \psi _b \sin \psi _v)+\cos \phi _v \cos \psi _p \cos \psi _v)\\&&+\sin \phi _p (\sin \psi _b \sin \psi _v-\cos \psi _b \sin \psi _p \cos \psi _v)\end{array}

これはさすがに、回転行列を1個かける計算を関数化して5個かけていったほうがすっきりしていいかもしれませんね…

計算やっかいですが、この修正ができれば、ルックダウン性能とかすらも表現できるすごい機能になるので…、期待してます。がんばってくださいっ!

FROSTFROST2011/06/09 22:56貴重な意見ありがとうございます。float Rはその通りですね。今のところ精度は気にならないですが、他の人にとっては気になるかもしれませんし。
あと、1機索敵するごとに1フレームかかるのは仕様です。敵がたくさんいたらレーダーも処理が遅れそうだと思ったので、そうしました。100機も登場させるようなミッションを作らなければ大丈夫ですし、それに数フレームで何十機も処理したら、ゲーム処理も大きくなりそうでしたので。

FROSTFROST2011/06/10 00:12こんな面倒な計算をわざわざすみません。 二次元空間の回転行列は理解できるのですが…