回転する矩形とカーソルの当たり判定について

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

回転する矩形とカーソルの当たり判定について

#1

投稿記事 by プリン太 » 12年前

回転する矩形にマウスカーソルが当たっているかの判定プログラムを作ろうと思ったのですが
ベクトルは良く分からないので以下の方法を考えてみました。
ちなみにC言語+Dxライブラリ、VC++2008の環境です。

コード:

#include "DxLib.h"
#include <math.h>

#define RED	GetColor(255,0,0)
#define WHT	GetColor(255,255,255)
#define	W	640
#define	H	480
#define PI	3.141592653589793238

typedef struct{
	int x, y;
}Mouse;

typedef struct{
	int x0, y0; //中心座標
	int  h,  w; //縦横
	int x1, y1;	//左上座標
	int x2, y2;	//右上座標
	int x3, y3;	//右下座標
	int x4, y4; //左下座標
	int angle;	//矩形の傾き
}Box;

double rad(double angle);	//度数→ラジアン変換

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int){
	ChangeWindowMode(TRUE);
	SetDrawScreen(DX_SCREEN_BACK);
	DxLib_Init();

	Mouse mouse;
	Box box={W/2, H/2, 150, 50};
	double angle;	//中心から角までの角度
	double r;		//中心から角までの長さ
	int colflag=0;	//当たり判定フラグ
	int count=0;

	r=sqrt(pow(box.h,2.0)+pow(box.w,2.0));	//長さ=√(x^2+y^2)
	angle=acos((box.h/2)/r);					//角度=arccos(x/r)
	angle=(angle/PI)*180.0;						//角度をラジアン→度数変換

	while(!ScreenFlip()&&!ProcessMessage()&&!ClearDrawScreen()){

		GetMousePoint(&mouse.x, &mouse.y);
		count++;

		box.angle=count%360;

		box.x1=(int)(cos(rad(180+box.angle+angle))*r)+box.x0;
		box.y1=(int)(sin(rad(180+box.angle+angle))*r)+box.y0;	//左上の位置計算
		box.x2=(int)(cos(rad(box.angle-angle))*r)+box.x0;
		box.y2=(int)(sin(rad(box.angle-angle))*r)+box.y0;		//右上の位置計算
		box.x3=(int)(cos(rad(box.angle+angle))*r)+box.x0;
		box.y3=(int)(sin(rad(box.angle+angle))*r)+box.y0;		//右下の位置計算
		box.x4=(int)(cos(rad(180+box.angle-angle))*r)+box.x0;
		box.y4=(int)(sin(rad(180+box.angle-angle))*r)+box.y0;	//左下の位置計算

		//マウスが当たってたら
		if( mouse.x>box.x1&&mouse.x<box.x2&&mouse.x>box.x4&&mouse.x<box.x3
		   &&mouse.y>box.y1&&mouse.y<box.y4&&mouse.y>box.y2&&mouse.y<box.y3 )
			colflag=1;

		//マウスが外れてたら
		else
			colflag=0;

		//描画
		SetDrawBlendMode(DX_BLENDMODE_ALPHA, 100);
		DrawQuadrangle(box.x1, box.y1, box.x2, box.y2, box.x3, box.y3, box.x4, box.y4, RED, TRUE);
		SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
		DrawQuadrangle(box.x1, box.y1, box.x2, box.y2, box.x3, box.y3, box.x4, box.y4, RED, FALSE);

		DrawFormatString( 0,  0, WHT, "colflag:%d",colflag);
		DrawFormatString( 0, H- 20, WHT, "Mouse(%3d,%3d)" ,mouse.x, mouse.y);

	}
	DxLib_End();
	return 0;
}

//度数→ラジアン変換
double rad(double angle){
	if(angle!=0)
		return PI/(180/angle);

	return 0;
}
矩形の回転は上手くいったのですがカーソルとの当たり判定が上手く動作しません。
条件文がおかしいんだとは思いますが一体どう直せばいいのか分からないのでアドバイスをいただきたいです。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 回転する矩形とカーソルの当たり判定について

#2

投稿記事 by みけCAT » 12年前

矩形とカーソルの位置を逆回転し、普通の座標に変換してから当たり判定をすればいいと思います。
サンプルを作成中です。

【追記】
逆回転するのはカーソルの位置だけでよさそうです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 回転する矩形とカーソルの当たり判定について

#3

投稿記事 by みけCAT » 12年前

サンプルができました。本体はisBoxAndMouseHit関数です。当たっていればtrueを、当たっていなければfalseを返します。
また、矛盾していた描画に関係するコードも書き換えさせていただきました。

コード:

#include "DxLib.h"
#include <math.h>
 
#define RED GetColor(255,0,0)
#define WHT GetColor(255,255,255)
#define W   640
#define H   480
#define PI  3.141592653589793238
 
typedef struct{
    int x, y;
}Mouse;
 
typedef struct{
    int x0, y0; //中心座標
    int  h,  w; //縦横
    int x1, y1; //左上座標
    int x2, y2; //右上座標
    int x3, y3; //右下座標
    int x4, y4; //左下座標
    int angle;  //矩形の傾き
}Box;
 
double rad(double angle);   //度数→ラジアン変換
 
bool isBoxAndMouseHit(const Box& box,const Mouse& mouse) {
	const double EPS=1e-7;
	double tempMouseX,tempMouseY;
	double newMouseX,newMouseY;
	tempMouseX=mouse.x-box.x0;
	tempMouseY=mouse.y-box.y0;
	//もとのコードの動作から、Boxの変数angleは時計回りの回転を表すと仮定
	newMouseX=cos(rad(box.angle))*tempMouseX+sin(rad(box.angle))*tempMouseY+box.x0;
	newMouseY=-sin(rad(box.angle))*tempMouseX+cos(rad(box.angle))*tempMouseY+box.y0;
#if 1
	// Boxの変数w,hがそれぞれangle==0のときの横の長さの半分と縦の長さの半分を表す場合
	return box.x0-box.w<newMouseX+EPS && newMouseX<box.x0+box.w+EPS &&
		box.y0-box.h<newMouseY+EPS && newMouseY<box.y0+box.h+EPS;
#else
	// Boxの変数w,hがそれぞれangle==0のときの横の長さと縦の長さを表す場合
	return box.x0-box.w/2.0<newMouseX+EPS && newMouseX<box.x0+box.w/2.0+EPS &&
		box.y0-box.h/2.0<newMouseY+EPS && newMouseY<box.y0+box.h/2.0+EPS;
#endif
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int){
    ChangeWindowMode(TRUE);
    SetDrawScreen(DX_SCREEN_BACK);
    DxLib_Init();
 
    Mouse mouse;
    Box box={W/2, H/2, 150, 50};
    double angle;   //中心から角までの角度
    double r;       //中心から角までの長さ
    int colflag=0;  //当たり判定フラグ
    int count=0;
 
    r=sqrt(pow(box.h,2.0)+pow(box.w,2.0));  //長さ=√(x^2+y^2)
//    angle=acos((box.h/2)/r);                    //角度=arccos(x/r)
    angle=acos(box.w/r);                    //角度=arccos(x/r)
    angle=(angle/PI)*180.0;                     //角度をラジアン→度数変換
 
    while(!ScreenFlip()&&!ProcessMessage()&&!ClearDrawScreen()){
 
        GetMousePoint(&mouse.x, &mouse.y);
        count++;
 
        box.angle=count%360;
 
        box.x1=(int)(cos(rad(180+box.angle+angle))*r)+box.x0;
        box.y1=(int)(sin(rad(180+box.angle+angle))*r)+box.y0;   //左上の位置計算
        box.x2=(int)(cos(rad(box.angle-angle))*r)+box.x0;
        box.y2=(int)(sin(rad(box.angle-angle))*r)+box.y0;       //右上の位置計算
        box.x3=(int)(cos(rad(box.angle+angle))*r)+box.x0;
        box.y3=(int)(sin(rad(box.angle+angle))*r)+box.y0;       //右下の位置計算
        box.x4=(int)(cos(rad(180+box.angle-angle))*r)+box.x0;
        box.y4=(int)(sin(rad(180+box.angle-angle))*r)+box.y0;   //左下の位置計算
 
        //マウスが当たってたら
//        if( mouse.x>box.x1&&mouse.x<box.x2&&mouse.x>box.x4&&mouse.x<box.x3
//           &&mouse.y>box.y1&&mouse.y<box.y4&&mouse.y>box.y2&&mouse.y<box.y3 )
        if(isBoxAndMouseHit(box,mouse))
            colflag=1;
 
        //マウスが外れてたら
        else
            colflag=0;
 
        //描画
        SetDrawBlendMode(DX_BLENDMODE_ALPHA, 100);
        DrawQuadrangle(box.x1, box.y1, box.x2, box.y2, box.x3, box.y3, box.x4, box.y4, RED, TRUE);
        SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
        DrawQuadrangle(box.x1, box.y1, box.x2, box.y2, box.x3, box.y3, box.x4, box.y4, RED, FALSE);
 
        DrawFormatString( 0,  0, WHT, "colflag:%d",colflag);
        DrawFormatString( 0, H- 20, WHT, "Mouse(%3d,%3d)" ,mouse.x, mouse.y);
 
    }
    DxLib_End();
    return 0;
}
 
//度数→ラジアン変換
double rad(double angle){
    if(angle!=0)
        return PI/(180/angle);
 
    return 0;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

プリン太

Re: 回転する矩形とカーソルの当たり判定について

#4

投稿記事 by プリン太 » 12年前

みけCAT さんが書きました:サンプルができました。本体はisBoxAndMouseHit関数です。当たっていればtrueを、当たっていなければfalseを返します。
また、矛盾していた描画に関係するコードも書き換えさせていただきました。
サンプルまで書いていただきありがとうございます!
カーソルの位置を逆回転し、回転前の矩形と当たり判定をするというのは
http://www.club.konan-u.ac.jp/~KSWL/tec ... _point.pdf
ここを参考に自分でも試していたのですが、なかなかうまく行かなかったので助かりました
これで解決とさせていただきます
みけCATさんありがとうございました!

閉鎖

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