当たり判定を小さくするには?(当たり判定3)

考え方

キャラクタ同士の当たり判定を行うことはできた。しかし、当たり判定に使用する矩形はポリゴンの大きさをそのまま使っているため、見た目(絵的)には衝突していないのに、矩形で衝突してしまうという現象が起こってしまう。

そこで、当たり判定用の矩形を画像の矩形よりも小さくとり、当たり判定用の矩形同士で当たり判定を行うテクニックを紹介する。

当たり判定用の矩形を準備する

当たり判定に使う矩形は、キャラクタの矩形よりも小さく取る。いろいろなプログラムが考えられるが、今回は元の矩形よりいくつ縮めるかを基準にプログラムしてみる。

// グローバル変数
HWND hWnd;                              // ウィンドウハンドル
BOOL g_appActive = FALSE;               // ウィンドウの状態
char szWinName[] = "Exer006";           // ウィンドウクラス用文字列
char szWinTitle[] = "キャラクタの移動と当たり判定"; // ウィンドウクラス用文字列
LPDIRECT3D8 gl_lpD3d = NULL;            // Direct3D8インターフェイス
LPDIRECT3DDEVICE8 gl_lpD3ddev = NULL;   // Direct3DDevice8インターフェイス
D3DPRESENT_PARAMETERS gl_d3dpp;         // ディスプレイパラメータ
LPDIRECT3DTEXTURE8 gl_Texture1;         // テクスチャ・オブジェクト1
LPDIRECT3DTEXTURE8 gl_Texture2;         // テクスチャ・オブジェクト2
BYTE g_FrameNo = START_INIT;            // フレーム選択用
BYTE gl_KeyTbl[256];                    // キーボードの状態を格納
RECT gl_rcMove;                         // 移動可能領域
TLVERTX VertexDataTbl1[4];              // キャラクタ1用頂点情報配列
RECT gl_hitRect1;                       // キャラクタ1用当たり判定矩形情報
TLVERTX VertexDataTbl2[4];              // キャラクタ2用頂点情報配列
RECT gl_hitRect2;                       // キャラクタ2用当たり判定矩形情報
char *gl_szCharFileName1 = "sample1.bmp"; // キャラクタ1用画像ファイル名
char *gl_szCharFileName2 = "sample2.bmp"; // キャラクタ2用画像ファイル名
・
・

//-----------------------------------------------------------------------------
// 関数名 : StartInit()
// 機能概要: スタート画面初期化処理
//-----------------------------------------------------------------------------
void StartInit(void)
{
    HRESULT ret;

    //--------------------------------------------------- 各変数の初期化
    // 移動可能領域の設定
    SetRect(&gl_rcMove, 0, 0, 640, 480);
    // スタート画面で使用するテクスチャの作成
    CreateStartTexture();
    // キャラクタ情報の初期化
    /* キャラクタ1 */
    InitVertex(VertexDataTbl1, 100.0, 100.0, 164.0, 164.0); // 頂点データ
    SetRect(&gl_hitRect1, 10, 15, 10, 15); // 当たり判定矩形
    /* キャラクタ2 */
    InitVertex(VertexDataTbl2, 400.0, 300.0, 496.0, 396.0); // 頂点データ
    SetRect(&gl_hitRect2, 0, 0, 0, 0); // 当たり判定矩形

    //--------------------------------------------------- フレームナンバーセット
    g_FrameNo = START_FRAME;

}

《POINT》

当たり判定用矩形を考慮した当たり判定

当たり判定の矩形を小さくするため、当たり判定用の矩形を用意した。あたり判定を行う場合、その矩形の値を考慮して行わなければならない。よって、当たり判定用の矩形を使った当たり判定を行う関数を作成する。プロトタイプ宣言も行うこと。

//-----------------------------------------------------------------------------
// 関数名 : HitCheck2()
// 機能概要: 当たり判定用矩形を指定してあたり判定を行う
//-----------------------------------------------------------------------------
bool HitCheck2(LPTLVERTEX v1, RECT rc1, LPTLVERTEX v2, RECT rc2)
{
    RECT r1, r2;

    // キャラクタ1の当たり判定用矩形を求める
    r1.left = (int)v1[0].x + rc1.left;
    r1.top = (int)v1[0].y + rc1.top;
    r1.right = (int)v1[2].x - rc1.right;
    r1.bottom = (int)v1[2].y - rc1.bottom;

    // キャラクタ2の当たり判定用矩形を求める
    r2.left = (int)v2[0].x + rc2.left;
    r2.top = (int)v2[0].y + rc2.top;
    r2.right = (int)v2[2].x - rc2.right;
    r2.bottom = (int)v2[2].y - rc2.bottom;

    // 当たり判定
    if ( r1.left <= r2.right && r1.top <= r2.bottom && r1.right >= r2.left && r1.bottom >= r2.top )
        return true;
    else
        return false;

}

《POINT》

使い方

HitCheck2関数を使って当たり判定を行うには、次のように使用する。

//-----------------------------------------------------------------------------
// 関数名 : StartFrame()
// 機能概要: スタート画面処理
//-----------------------------------------------------------------------------
void StartFrame(void)
{
    float mx, my;

    /* 描画処理 */
    // キャラクタ1を描画
    gl_lpD3ddev->SetTexture(0, gl_Texture1);
    gl_lpD3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, VertexDataTbl1, sizeof(TLVERTX));
    // キャラクタ2を描画
    gl_lpD3ddev->SetTexture(0, gl_Texture2);
    gl_lpD3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, VertexDataTbl2, sizeof(TLVERTX));

    /* 移動処理 */
    mx = my = 0.0f;
    if ( gl_KeyTbl[VK_LEFT] & 0x80 )  mx = -2.0f;
    if ( gl_KeyTbl[VK_UP] & 0x80 )    my = -2.0f;
    if ( gl_KeyTbl[VK_RIGHT] & 0x80 ) mx =  2.0f;
    if ( gl_KeyTbl[VK_DOWN] & 0x80 )  my =  2.0f;
    Move(VertexDataTbl1, mx, my);

    /* 指定範囲を超えないようにする */
    MoveCheck(gl_rcMove, VertexDataTbl1);

    /* 当たり判定 */
//  if ( HitCheck(VertexDataTbl1, VertexDataTbl2) )
    if ( HitCheck2(VertexDataTbl1, gl_hitRect1, VertexDataTbl2, gl_hitRect2) )
        InitVertex(VertexDataTbl1, 100.0f, 100.0f, 164.0f, 164.0f, 255);

    // リターンキーが押されたら、ゲーム開始
    if ( gl_KeyTbl[VK_RETURN] & 0x80 ) g_FrameNo = GAME_INIT;

}

《POINT》

※HitCheck2()関数を使用し、当たり判定が小さくなったことを確認する。


BACK(キャラクタ同士の衝突を調べるには?) NEXT(練習問題)