角度を絞っての当たり判定ができません

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
奥兵

角度を絞っての当たり判定ができません

#1

投稿記事 by 奥兵 » 14年前

現在シューティングゲームのようなものを製作しているのですが、敵の角度を絞っての当たり判定ができません。

 ある敵を正面からは射撃でダメージが通らず、回り込んで背面もしくは側面から攻撃しなければならないようにしたいのですがうまくいきません。
プログラムを走らせると最初は正面からの攻撃は判定をとらないのですが、
しばらく適当に動いていると何故か攻撃が正面から通るようになってしまいます。

VC++2008 DXライブラリ使用 OSは7です。
プログラミングは初心者です。

↓判定の関数です

コード:

void huntei(struct bullet *bullet,struct uni *mainuni,struct zyoukyou *fase,struct enemys *ene,struct obj *obj){
		int White;
		White=GetColor(0,0,0);
		int i,j,range;
		int x,y;
 	

	for(j=0;j<32;j++){		
		range=ene->size[j]*ene->size[j];
	for(i=0;i<30;i++){
		if((range>((ene->x[j]-bullet[i].x)*(ene->x[j]-bullet[i].x)+(ene->y[j]-bullet[i].y)*(ene->y[j]-bullet[i].y))&&(bullet[i].fl==1))){	
				if(ene->HP[j]>0){
					bullet[i].fl=0;
					if(j!=4){//四番が正面から通したくない敵です
						ene->HP[j]=ene->HP[j]-1;
					}else{
						if(abs(ene->rad[j]-bullet[i].rad)>(PI)){//ここで角度の差を出そうとしてます
							ene->HP[j]-=3;
						}		
					}

					if(ene->HP[j]<=0){
						ene->cdie[j]=25;
					}
					if(fase->tyakudann==0){

						fase->tyakudann=5;
						fase->x=(int)bullet[i].x-10;
						fase->y=(int)bullet[i].y-20;

					}
				}
		}
	}
	}
	//DrawFormatString(100,200, White , "x=%d y=%d mx=%d " ,ene->HP,3,3);
	//obj のテスト
	for(j=0;j<32;j++){
		range=obj->size[j]*obj->size[j];
	for(i=0;i<30;i++){
		if((range>((obj->x[j]-bullet[i].x)*(obj->x[j]-bullet[i].x)
				  +(obj->y[j]-bullet[i].y)*(obj->y[j]-bullet[i].y))&&(bullet[i].fl==1))){	
				if(obj->HP[j]>0){
					bullet[i].fl=0;
					if(fase->tyakudann==0){
						fase->tyakudann=10;
						fase->x=(int)bullet[i].x-10;
						fase->y=(int)bullet[i].y-20;
					}
				}
		}
	}
	}

	if(fase->tyakudann>0){
		fase->tyakudann-=1;
		DrawGraph( fase->x , fase->y ,mainuni->image[6+(GetRand(2))],TRUE);
	}

	

	
		x=(int)(mainuni->x+(sin(mainuni->rad)*10)+cos(mainuni->rad)*30);
		y=(int)(mainuni->y+(cos(mainuni->rad)*-10)+sin(mainuni->rad)*30);
	
	for(j=0;j<32;j++){	
			range=ene->size[j]*ene->size[j];
		if((mainuni->clock>12)&&(mainuni->clock<30)){
			if((range>((ene->x[j]-x)*(ene->x[j]-x)+(ene->y[j]-y)*(ene->y[j]-y)))){	
					if(ene->HP[j]>0){
						ene->HP[j]=ene->HP[j]-3; //ここは格闘なのでスルーしてください
						//mainuni->clock=30;
					}
					if(ene->HP[j]<=0){
						ene->cdie[j]=35;
					}
			}
		} 
	}
	

}

jay
記事: 314
登録日時: 14年前
住所: 大阪市
連絡を取る:

Re: 角度を絞っての当たり判定ができません

#2

投稿記事 by jay » 14年前

なんだか元も子もないこと言ってるような気もしますが

特定の角度だけなんて考えるとややこしくなるので
敵の正面にバリアのようなものを置いて(実際に画像を描画するかどうかはさておき)
そのバリアに自分の弾が当たったら弾は消滅する、という仕様にすれば結果として同じようになると思います。
この方法なら的に当たった時の角度なんてややこしい計算をしなくても、ただ単に弾とバリアの判定をすればいいだけですしね。

もっともなんらかの理由でしっかりと角度を計算しなければならないのならばこの方法は役に立たないですけどね(苦笑)
♪僕たちは まだ森の中 抜け出そう 陽のあたる場所へ

奥兵

Re: 角度を絞っての当たり判定ができません

#3

投稿記事 by 奥兵 » 14年前

回答ありがとうございますm(_ _)m。
いま制作中のものは敵は自機の方向を向いてきて、自機は複数の敵のどれかを向くようにしてあるので、敵の向いている方向の正面に
別の判定を作るよりは弾丸の角度と敵機の角度の差を求め、それで判断できたら簡単かなと考えたのですが、やはり前者のほうが簡単になりますかね?

アバター
GRAM
記事: 164
登録日時: 14年前
住所: 大阪

Re: 角度を絞っての当たり判定ができません

#4

投稿記事 by GRAM » 14年前

すみません
if(abs(ene->rad[j]-bullet.rad)>(PI))
この判定の本来の意味はなんでしょうか?

具体的にはene->rad[j]であらわされるラジアンというのはどこから測った角度で
bulletのものも同様にどこから測った角度で何を意味しているのでしょうか?

簡単な絵でもあれば助かります

角度に頼らずに背後からの判定をとろうとすれば、進行方向のベクトル同士の内積から正(背後から)か負か(正面から)かを判断する方法があります
(弾が(x1,y1)の方向に進んでいて、敵が(x2,y2)の方向を向いているならx1x2+y1y2の符号で判定できます)

角度のみに頼るとなると、一周したときに359°→0°になるときの境界の判定などを行う必要があります。

奥兵

Re: 角度を絞っての当たり判定ができません

#5

投稿記事 by 奥兵 » 14年前

 丁寧にありがとうございます。

bulletの角度は発射した瞬間の自機の角度を代入しています。
eneの角度は自機の方向を向くようにしています。

if(abs(ene->rad[j]-bullet.rad)>(PI))
↑でeneとbulletの角度の差が90°以上ならHPを減らす、
と考えたのですが・・・

また、弾のダメージが通る角度を任意に設定する必要が出てくるかもしれないので、
出来ればでよいのですが、できるだけ角度で求めたいと考えています。

↓が自機の角度を決定している部分です

コード:

//mainuni->rockは現在ロックしている敵機です

if(ene->HP[mainuni->rock]>0){
			mainuni->rad=atan2(ene->y[mainuni->rock]-mainuni->y,ene->x[mainuni->rock]-mainuni->x);
		}else{
			mainuni->rad=-PI/2;//敵がいないなら正面を向く
		}
↓が敵機の角度を計算している部分です

コード:

	for(i=0;i<32;i++){	
	if(ene->HP[i]>0){
		rad[i] = atan2(mainuni->y - ene->y[i], mainuni->x - ene->x[i])-(PI/2);
	
	 d[i] = rad[i] - ene->rad[i];
	 
		if (sin(d[i]) > 0) {
			ene->rad[i] += 0.02;
		} else {
			ene->rad[i] -= 0.02;
		}
	
	DrawBox   ( (int) ene->x[i] , (int)ene->y[i]-60 , (int)ene->x[i]+ene->HP[i] , (int)ene->y[i]-50 , Green , TRUE ) ;

		
			DrawRotaGraph((int)ene->x[i],(int)ene->y[i],1.0,ene->rad[i], ene->image[i], TRUE );
	}
	}

奥兵

#6

投稿記事 by 奥兵 » 14年前

すいません書き忘れてました。
俯瞰目線のシューティングで角度は、その敵の向いている向き(その機体の正面)です。

しひ

Re: 角度を絞っての当たり判定ができません

#7

投稿記事 by しひ » 14年前

こんばんわ。
いくつか気になるところがあったのですが、いかんせん試しようがなく
原因がつかめなかったので貼って動くサンプルを書いてみました。
C言語とC++が混ざってて分からないところもあるかと思うので、
「ここから~ここまで」のところだけを読んでみて下さい。

コード:

#include <algorithm>
#include <cmath>
#include "dxlib.h"

// ここから =======================================================================

// 円周率の定義
const float PI = 6.0f * std::asin( 0.5f );

// キャラクタのデータを保持する構造体
struct Actor
{
	float x, y; // 座標
	float angle; // 現在のキャラクタの向いている方向
	const float radius; // キャラクタの半径
	const float speed; // 敵の回転する速度、自機では使っていない
};

// 2つのキャラクタ間の角度を取得する関数
double getAngle( const Actor& actor, const Actor& target )
{
	return std::atan2( target.y-actor.y, target.x-actor.x );
}

// 敵(画面中央にいる大きい方の円)を回転させる関数
void rotateEnemy( Actor& enemy, const Actor& target )
{
	// 今どれくらい向きが違うのかを取得
	const double radian = getAngle( enemy, target );
	if( radian < enemy.angle ){
		enemy.angle -= enemy.speed;
	}
	else if( enemy.angle < radian ){
		enemy.angle += enemy.speed;
	}

	// 下2行が何をしているかは、コメントアウトすると分かるかと思います
	if( PI < radian-enemy.angle ){ enemy.angle += 2*PI; }
	if( radian-enemy.angle < -PI ){ enemy.angle -= 2*PI; }
}

// 攻撃が有効かどうかを判断する関数
bool isEffectiveAttack( const Actor& enemy, const Actor& player )
{
	// 絶対値を取る
	const double radian = std::abs( getAngle( enemy, player )-enemy.angle );
	// 向きの差が45度(π/4)より大きかったら攻撃は有効
	return (PI/4 < radian);
}

// ここまで =======================================================================

struct Bounds
{
	int x, y, w, h;
};

void movePlayer( Actor& actor, const Bounds& range )
{
	if( CheckHitKey( KEY_INPUT_UP ) ){ // 上
		actor.y = (std::max)( actor.y-actor.speed, range.y+actor.radius ); // ()でくくるのは競合対策
	}
	if( CheckHitKey( KEY_INPUT_DOWN) ){ // 下
		actor.y = (std::min)( actor.y+actor.speed, range.h-actor.radius );
	}
	if( CheckHitKey( KEY_INPUT_RIGHT ) ){ // 右
		actor.x = (std::min)( actor.x+actor.speed, range.w-actor.radius );
	}
	if( CheckHitKey( KEY_INPUT_LEFT ) ){ // 左
		actor.x = (std::max)( actor.x-actor.speed, range.x+actor.radius );
	}
}

int main()
{
	if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; 
	SetDrawScreen(DX_SCREEN_BACK);

	const Bounds window = { 0, 0, 640, 480 };
	Actor player = { window.w/2.0f-16.0f, window.h-16.0f, 0.0f, 16.0f, 0.0f };
	Actor enemy = { window.w/2.0f-16.0f, window.h/2.0f-16.0f, 0.0f, 32.0f, 0.005f };
	
	while( !ProcessMessage() && !CheckHitKey( KEY_INPUT_ESCAPE ) ){ // Escで終了
		ClearDrawScreen();

		movePlayer( player, window );
		rotateEnemy( enemy, player );
		
		// 攻撃が有効かどうかで線の色を変える
		const int color = ( isEffectiveAttack( enemy, player ) )? GetColor( 255, 0, 0 ): GetColor( 0, 0, 255 );
		DrawLine( player.x, player.y, enemy.x, enemy.y, color );
		// プレイヤの描画
		DrawCircle( player.x, player.y, player.radius, 0xffffff );
		// 敵の向いている方向を示す線
		DrawLine( enemy.x, enemy.y, enemy.x+(std::sin( enemy.angle )*200), enemy.y+(std::cos( enemy.angle )*200), 0xffff00 );
		// 敵の描画
		DrawCircle( enemy.x, enemy.y, enemy.radius, 0xffffff );

		ScreenFlip();
	}
	DxLib_End();

	return 0;
}
線が赤い時は攻撃が有効、青のときは無効です。

角度の単位はラジアンで、範囲はatan2()関数の返り値そのままです。
右が0、上がπ/2、左がπ(-π)、下が-π/2、だったはず。

奥兵

Re: 角度を絞っての当たり判定ができません

#8

投稿記事 by 奥兵 » 14年前

詳しいソースありがとうございます。
おかげさまでなんとか解決することができました
感謝です^^。

しひ

Re: 角度を絞っての当たり判定ができません

#9

投稿記事 by しひ » 14年前

今更ながら・・・・・・「貼って動くサンプル」とか書いておきながら動きませんねこれ。
80行目は

コード:

    Actor player = { window.w/2.0f-16.0f, window.h-16.0f, 0.0f, 16.0f, 2.0f };
の間違いでした。

しひ

Re: 角度を絞っての当たり判定ができません

#10

投稿記事 by しひ » 14年前

95行目も

コード:

        DrawLine( enemy.x, enemy.y, enemy.x+(std::cos( enemy.angle )*200), enemy.y+(std::sin( enemy.angle )*200), 0xffff00 );
の誤りです。本当に申し訳ない。

閉鎖

“C言語何でも質問掲示板” へ戻る