当たり判定のプログラム例 円と長方形

円と長方形との重なりを判定するプログラム例。DX ライブラリを使用。長方形は x 軸または y 軸に平行であるものとします。

プログラムの概要

矢印キーで白い円Aを動かします。画面中央に置かれた青い長方形Bに重ねると、Bの色が赤くなります。

ソースコード

//-----------------------------------------------------------
// main.cpp
//-----------------------------------------------------------

#include "DxLib.h"
#include "rect.h"
#include "circle.h"
#include <tchar.h>

int WINAPI WinMain( 
  HINSTANCE hInstance, 
  HINSTANCE hPrevInstance, 
  LPSTR lpCmdLine, int nCmdShow )
{
  ChangeWindowMode( TRUE );  // フルスクリーンで起動しない
  SetGraphMode( 640, 480, 16 );  // 画面:640x480、カラー:16bit
  if( DxLib_Init() == -1 ) { return -1; }  // DXライブラリ初期化
  SetDrawScreen( DX_SCREEN_BACK );  // 描画先画面を裏画面にセット

  // 図形の作成
  CCircle circle_A( _T("A") ); circle_A.set( 160, 160, 60 );
  CRect rect_B( _T("B") ); rect_B.set( 270, 160, 100, 160 );

  // 色コードの取得
  int col_red   = GetColor( 255 ,   0 ,   0 );
  int col_blue  = GetColor(  64 , 128 , 255 );
  int col_white = GetColor( 255 , 255 , 255 );

  while( ProcessMessage() == 0 &&
         CheckHitKey( KEY_INPUT_ESCAPE ) == 0 )
  {
    ClearDrawScreen();  // 画面クリア

    // 円Aを矢印キーで動かす
    if( CheckHitKey( KEY_INPUT_UP ) ) { circle_A.moveUp(); }
    if( CheckHitKey( KEY_INPUT_DOWN ) ) { circle_A.moveDown(); }
    if( CheckHitKey( KEY_INPUT_LEFT ) ) { circle_A.moveLeft(); }
    if( CheckHitKey( KEY_INPUT_RIGHT ) ) { circle_A.moveRight(); }

    // 円Aと長方形Bとが交差した場合
    if( circle_A.isIntersected( rect_B ) ) { 
      rect_B.draw( col_red );    // 長方形Bを赤で描画
    }
    // 交差しなかった場合
    else {
      rect_B.draw( col_blue );   // 長方形Bを青で描画
    }
    circle_A.draw( col_white );  // 円Aを白で描画

    // 図形の情報を表示
    circle_A.displayInfo( 4, 4, col_white );
    rect_B.displayInfo( 4, 24, col_white );

    ScreenFlip();  // 裏画面の内容を表画面に反映させる
  }

  DxLib_End();  // DXライブラリ使用の終了処理

  return 0;     // ソフトの終了
}
//-----------------------------------------------------------
// rect.h
//-----------------------------------------------------------

#ifndef __RECT_H__
#define __RECT_H__

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

// 長方形を表すクラス
class CRect
{
  TCHAR name[20];  // 名前
  int lx;  // 左上 x 座標
  int ly;  // 左上 y 座標
  int wd;  // 幅
  int ht;  // 高さ
public:
  CRect( LPCTSTR str );  // コンストラクタ
  void set( int x, int y, int w, int h );  // 値をセットする
  int get_lx() const;  // lx の値を返す
  int get_ly() const;  // ly の値を返す
  int get_wd() const;  // wd の値を返す
  int get_ht() const;  // ht の値を返す
  // 情報の表示
  void displayInfo( int x, int y, int colorCode ) const; 
  void draw( int colorCode ) const;  // 描画
};

#endif
//-----------------------------------------------------------
// rect.cpp
//-----------------------------------------------------------

#include "rect.h"

// コンストラクタ
CRect::CRect( LPCTSTR str ) 
{
  _tcscpy_s( name, sizeof(name)/sizeof(TCHAR), str );
  lx = ly = wd = ht = 0;
}

// 値をセットする
void CRect::set( int x, int y, int w, int h ) 
{
  lx = x; ly = y; wd = w; ht = h;
}  

int CRect::get_lx() const { return lx; }  // lx の値を返す
int CRect::get_ly() const { return ly; }  // ly の値を返す
int CRect::get_wd() const { return wd; }  // wd の値を返す
int CRect::get_ht() const { return ht; }  // ht の値を返す

// 情報の表示
void CRect::displayInfo( int x, int y, int colorCode ) const 
{
  DrawFormatString( x, y, colorCode, 
  _T("%s: (lx, ly) = (%3d, %3d), wd = %3d, ht = %3d"), 
  name, lx, ly, wd, ht );
}

// 描画
void CRect::draw( int colorCode ) const 
{
  DrawBox( lx, ly, lx + wd, ly + ht, colorCode, TRUE );
}
//-----------------------------------------------------------
// circle.h
//-----------------------------------------------------------

#ifndef __CIRCLE_H__
#define __CIRCLE_H__

#include "DxLib.h"
#include "rect.h"
#include <tchar.h>

// 円を表すクラス
class CCircle
{
  TCHAR name[20];  // 名前
  int mx;  // 中心の x 座標
  int my;  // 中心の y 座標
  int rd;  // 半径
public:
  CCircle( LPCTSTR str );  // コンストラクタ
  void set( int x, int y, int r );  // 値をセットする
  int get_mx() const;  // mx の値を返す
  int get_my() const;  // my の値を返す
  int get_rd() const;  // rd の値を返す
  void moveUp();       // 上へ移動 
  void moveDown();     // 下へ移動
  void moveLeft();     // 左へ移動
  void moveRight();    // 右へ移動
  // 情報の表示
  void displayInfo ( int x, int y, int colorCode ) const; 
  void draw( int colorCode ) const;  // 描画
  // 点が円に含まれているかどうか
  BOOL isContained( int x, int y ) const;
  // 長方形と交差しているかどうかの判定
  BOOL isIntersected( const CRect& b ) const;
};

#endif
//-----------------------------------------------------------
// circle.cpp
//-----------------------------------------------------------

#include "circle.h"

// コンストラクタ
CCircle::CCircle( LPCTSTR str ) 
{
  _tcscpy_s( name, sizeof(name)/sizeof(TCHAR), str ); 
  mx = my = rd = 0;
}  

// 値をセットする
void CCircle::set( int x, int y, int r ) 
{
  mx = x; my = y; rd = r;
}

int CCircle::get_mx() const { return mx; }  // mx の値を返す
int CCircle::get_my() const { return my; }  // my の値を返す
int CCircle::get_rd() const { return rd; }  // rd の値を返す

void CCircle::moveUp() { my--; }     // 上へ移動
void CCircle::moveDown() { my++; }   // 下へ移動
void CCircle::moveLeft() { mx--; }   // 左へ移動
void CCircle::moveRight() { mx++; }  // 右へ移動

// 情報の表示
void CCircle::displayInfo ( int x, int y, int colorCode ) const 
{
  DrawFormatString( x, y, colorCode, 
  _T("%s: (mx, my) = (%3d, %3d), rd = %3d"), 
  name, mx, my, rd );
}

// 描画
void CCircle::draw( int colorCode ) const 
{
  DrawCircle( mx, my, rd, colorCode, TRUE );
}

// 点が円に含まれているかどうか
BOOL CCircle::isContained( int x, int y ) const 
{
  int dx = x - mx;
  int dy = y - my;
  return ( dx*dx + dy*dy < rd*rd );
}  

// 長方形と交差しているかどうかの判定
BOOL CCircle::isIntersected( const CRect& b ) const 
{
  int lx, ly, wd, ht;
  lx = b.get_lx(); ly = b.get_ly();
  wd = b.get_wd(); ht = b.get_ht();
  // 円の中心が長方形から見て上下の位置にある場合
  if( (lx < mx && mx < lx + wd) && 
      (ly - rd < my && my < ly + ht + rd) ) {
    return TRUE;
  }
  // 円の中心が長方形から見て左右の位置にある場合
  if( (lx - rd < mx && mx < lx + wd + rd) &&
      (ly < my && my < ly + ht) ) {
    return TRUE;
  }
  // 円の中心が長方形から見て斜めの位置にある場合
  // 長方形のいずれかの頂点が円に含まれているか?
  if( isContained( lx, ly ) ) { return TRUE; }
  if( isContained( lx + wd, ly ) ) { return TRUE; }
  if( isContained( lx, ly + ht ) ) { return TRUE; }
  if( isContained( lx + wd, ly + ht ) ) { return TRUE; }
  // いずれの条件も満たさない
  return FALSE;
}

関連記事

よしいずの雑記帳:円と長方形との当たり判定
よしいずの雑記帳:DXライブラリを今すぐ使いたい

【theme : プログラミング
【genre : コンピュータ

プロフィール

よしいず

Author:よしいず
MATHEMATICS.PDFというウェブサイトを運営しています。

管理の都合上、トラックバックとコメントはオフにしてあります。ブログ経験者なら分かっていただけると思いますが、スパム(アダルトやその他の宣伝)ばかりなのが現実です。

リンクは自由です。当サイトの記事に対する間違いの指摘・意見・感想などを述べた記事からのリンクは歓迎です。ただし、ブログ記事アップ直後はミスが多く、頻繁に修正します。場合によっては削除する可能性もあります。その際、何も断りもなく修正・削除しますがご了承ください。内容を参考にする場合には投稿後一週間ほど様子を見てからにしてください(笑)。

記事の間違いを指摘するときは、その具体的箇所、理由(仕様に反するなど)・根拠(参考にした文献など)、代替案(同じ結果を得るための正しいやり方)も教えてください。そうしないと、(指摘される側および第三者はその時点では無知の状態なので、)どこが間違いなのか分かりませんし、本当に間違っているのかどうかが判断・検証できません。実際、間違いだと指摘されたことが結局は正しかったというケースもありますので。

このブログのタイトル一覧

リンク
月別アーカイブ
カテゴリ
最新記事
検索フォーム
RSSリンクの表示