敵の方向を向く

誘導弾なんかをつくる場合、今向いてる方向から相手の方向に角度を足しこむことをします。自分の角度が相手より小さかったら角度を足して、相手より大きかったら角度を引けば相手の角度に近づくわけです。1フレームに加減する角度量を調節してやれば、立派な誘導弾の出来上がりです。

ところがどっこい、角度つうのは一回りすると同じところに戻ってくると云う、クソい仕様があるため、一筋縄ではいきません。例えば、相手が自分に対して270度の位置に居る場合は、相手の方が角度が大きいですが、角度を足してゆくより引いてゆく方が早く相手に到達できるのです。これに自分と相手の間に0度(360度)があったりなかったりするとよく判らん場合わけが発生します。そんな感じで書いたのが以下のソース。

// 自分と相手の角度から向くべき角度を導出する

// MAngle::自分の角度(4096で一周)
// TAngle::相手の角度(4096で一周)
// Max::一度に足す角度の量
int YudoKaito( int MAngle, int TAngle, int Max)
{
	if( ((MAngle > TAngle-2048 ) && (MAngle<TAngle)) || ((MAngle > TAngle+2048)&&(MAngle>TAngle)) )
	{
		if( ((MAngle+Max > TAngle-2048 ) && (MAngle+Max<TAngle)) || ((MAngle+Max > TAngle+2048)&&(MAngle+Max>TAngle)) )
			MAngle = (MAngle + Max)&4095;
		else
		{
			MAngle = TAngle;
		}
	}
	else
	{
		if( ((MAngle-Max < TAngle-2048 ) && (MAngle-Max<TAngle)) || ((MAngle-Max < TAngle+2048)&&(MAngle-Max>TAngle)) )
			MAngle = (MAngle + 4096 - Max)&4095;
		else
		{
			MAngle = TAngle;
		}
	}
	return MAngle;
}

…と、数年間思ってたんけど、4096分周の場合だと、4095でビットマスクとってあげると正規化されることに、今日ようやく気づきました。−1024(−90度)の場合、(-1024 & 4095) == 3072(270度)

そんな感じで取り敢えず自分と相手の相対角度で+に回ったらいいのか−で回るべきかの評価関数が以下の感じに

static int	Compare( int    src, int    dst )
{
	return ((src - dst) & 4095) - 2048;
};

関数名は気にするな。+回りの時は正数、−回りの時は負数を返す。因みに、角度が一致してる場合も負数が返るね。

そんなわけで、相手の方向を向く関数がスッキリ書けました

int YudoKaito( int MAngle, int TAngle, int Max)
{
	int tmpKekka;
	int tmpAngle;

	// 正方向回りか、負方向回りかを判定
	tmpKekka = Compare( MAngle, TAngle );
	// 正回りだったら角度を足す、負回りだったら角度を引く
	tmpAngle = (tmpKekka >= 0) ? (MAngle + Max) : (MAngle - Max);
	// 角度を足した結果が相手の角度を超えたかどうかを判定(これをしないと蛇行する)
	tmpKekka ^= Compare( tmpAngle, TAngle );

	// 相手を超えてたら相手と同じ角度を返す。超えてなかったら角度を加減した値を返す
	return (tmpKekka & (1<<31)) ? TAngle : tmpAngle;
}

はい、3項演算子とか判りにくい表現つかいまくりで読みづらいですね。ごめんごめん。