平面(2D)における当たり判定〜超手抜き版 part3〜


目次に戻る


現在超手抜き版2D当たり判定プログラム(hitcheck1.zip)(要Builder5のDLL)のソースプログラムの解説を行っています。今日初めてみた。という方はプログラミングの小枝のページで過去の記事を読んでおいた方が良いと思います。
では、実際に当たり判定を行っている部分を見てみましょう。
当たり判定を行っている部分 (Charactor.cpp 34行目あたり)
void TCharactor::move( void )
{
    TRect next = FRect; // 移動後の位置

    next.Left += FVary;
    next.Right += FVary;

    // 重なるかチェック
    vector<TCharactor*> over = FParent->getOverlappedCharactors( next );

    if( over.size() > 1 ){ // 重なっている
       FVary = -FVary; // 反転
       return;
    }

    FRect = next;
}

このメソッド move はその名が示すとおりキャラクタに移動させる為のメソッドです。処理の流れを軽く説明します。
  1. 最初に移動後の位置を計算します。この段階では移動後の座標を出しただけで、実際にキャラクタは移動していません。
  2. 自分の親(フィールドクラス)に「移動後の位置は他のキャラクタと重ならない?」と問い合わせをします。
  3. 重なっている場合は方向転換し、重なっていなければキャラクタの座標を更新します。
かなり単純な処理なのですぐ理解できるかと思います。
悩むとしたら「移動後の位置は他のキャラクタと重ならない?」と問い合わせる部分だと思います。
理解に苦しむ可能性大の部分
// 重なるかチェック
vector<TCharactor*> over = FParent->getOverlappedCharactors( next );
vector<TCharactor*>」はC++の標準ライブラリに入っている可変長配列です。わからない人にとっては、なんだこりゃ!な存在だと思いますが、とりあえずは右側の「FParent->getOverlappedCharactors(next);」を解説します。
getOverlappedCharactors(TRect &rect ) TFieldクラスが管理しているキャラクタの中で引数rectが指す矩形と重なるキャラクタを可変長配列にいれて返す。 (Field.cpp の32行目あたり)
vector<TCharactor*> TField::getOverlappedCharactors( TRect &rect )
{
   vector<TCharactor*> result;

   for( list<TCharactor*>::iterator it = FItems.begin() ; it!=FItems.end() ; it++ ){
       if( CheckOverlap( (*it)->getRect() , rect ) ){ // 重ね合わさっているか
           // 重なっている
           result.push_back( *it );
       }
   }

   if( rect.Left < 0 || rect.Right >= FRect.Right ){
       // 壁にぶつかった
       result.push_back( NULL );
   }

   return result;
}

C++標準ライブラリに含まれるSTL(Standard Template Library)を駆使しているのでわかりにくいと思いますがそれさえ除けば至ってシンプルな流れになっています。
  1. 可変長配列を戻り値 result として宣言&初期化を行う。
  2. 自分(フィールド)が管理する全てのキャラクタに対して以下の処理をする。
    1. 引数としてうけとった rect と重なっているか調べる。
    2. 重なっているのなら、戻り値にこのキャラクタデータを追加
  3. 壁にぶつかったか調べる。
  4. 壁にぶつかっているのならば、NULLというデータを戻り値に追加する。
 
二つの矩形(TRect)が重なるかどうかの判定は 関数CheckOverlap() で行っています。
CheckOverlap関数 二つの矩形(TRect)が重なるかどうかの判定する (Function.cpp の 14行目あたり)
bool CheckOverlap( TRect &rect1 , TRect &rect2 )
{
    if( rect1.Right < rect2.Left || rect2.Right < rect1.Left ||
            rect1.Bottom < rect2.Top || rect2.Bottom < rect1.Top ){
        return false; // 重なっていない
    }
    return true; // 重なっている
}
 
どうでしょうか。かなり手抜きですが、当たり判定の処理として参考になれば幸いです。
ソースの途中ででてきたC++標準ライブラリ内のSTLのvector等についてはいずれ解説していきたいと思います。


目次に戻る