今日のlibGDX(20150602):E. 開発記 5 衝突検出【コメント頂いた分追記】

今日のlibGDX目次

http://snoopopo.hatenablog.com/entry/2015/04/27/220545

今日のテーマ:E. 開発記 5 衝突検出

今回はあたり判定の衝突検出部分をやっていきます.

あたり判定…衝突検出をましにする

今までターゲット(的)とボールのあたり判定は、

それぞれのクラスがメンバとして保持している左下の頂点のX,Y座標が一致したときに当たったと判定していました。

その判定のままボールとバーのあたり判定をする場合は、こんなかんじになります。

           if (boll.getX() == ber.getX() && boll.getY() == ber.getY()) {
                boll.setDirectionX(boll.getDirectionX() * -1);
                boll.setDirectionY(boll.getDirectionY() * -1);
            }

これでは全然つかいものにならないので、今回で改善していきます。

ここからはひらしょー本*1の8章の衝突検出部分を参考にやっていきます。

あたり判定という言葉は「衝突検出」と「衝突応答」両方の意味がある…みたいなことが書かれているので、

今回は「衝突検出」の強化です。

画像の幅と高さを取得して上下左右の値を取得する.

com.badlogic.gdx.scenes.scene2d.ui.Image クラスは画像の幅と高さを取得するメソッドを持っていました!便利ですね。

float berWidth = ber.getImage().getWidth();
float bollWidth = boll.getImage().getWidth();

float berLeft = ber.getX();
float berRight = ber.getX() + berWidth;
float bollLeft = boll.getX();
float bollRight = boll.getX() + bollWidth;

float berHeight = ber.getImage().getHeight();
float bollHeight = boll.getImage().getHeight();

float berDown = ber.getY();
float berUp = ber.getY() + berHeight;
float bollDown = boll.getY();
float bollUp = boll.getY() + bollHeight;

べたべたに書くと上のようにして、バーとボールの上下左右の値を取得できます.

ボールとバーの衝突検出

ここのサイトがとても参考になりました。

http://homepage2.nifty.com/natupaji/DxLib/lecture/lecture1_6.html

libGDXは左下が頂点座標で、上にいくほどY座標が+ 右にいくほどX座標が+ となり、

今いま、画像の左下の頂点座標しかボールもバーも持っていないので、

上記の記事の通りにやればできます。

//バーとボールとの衝突検出
float berLeft = ber.getX();
float berRight = ber.getX() + ber.getImage().getWidth();
float bollLeft = boll.getX();
float bollRight = boll.getX() + boll.getImage().getWidth();

if(
    ( berLeft <= bollLeft && bollLeft <= berRight ) //ボールの左をチェック
     ||
    ( berLeft <= bollRight && bollRight <= berRight )     //ボールの右をチェック
){
    float berDown = ber.getY();
    float berUp = ber.getY() + ber.getImage().getHeight();
    float bollDown = boll.getY();
    float bollUp = boll.getY() + boll.getImage().getHeight();

    if(
        ( berDown <= bollDown && bollDown <= berUp) //ボールの下をチェック
         ||
        ( berDown <= bollUp && bollUp <= berUp )  //ボールの上をチェック
    ){
        //ぶつかった
        boll.chengeDirection();
    }
}

おなじようにボールと壁、バーと壁の衝突検出

・ボールと壁

//壁とボールとのコリジョン
if (boll.getX() < 0 || boll.getX() + boll.getImage().getWidth() > WINDOW_WIDTH) {
    boll.chengeDirectionX();
}
if (boll.getY() < 0 || boll.getY() + boll.getImage().getHeight() > WINDOW_HEIGHT) {
    boll.chengeDirectionY();
}

・バーと壁

//プレイヤーバーと壁のコリジョン
if ( ber.getX() + move < 0 || ber.getX() + move + ber.getImage().getWidth() > WINDOW_WIDTH) {
    //壁とぶつかったので、動作を無効
    move = 0;
}

ボールと的の衝突検出

的との衝突検出は、今どきのjava8っぽくstreamAPIを使っていたので、こんな風になりました。

//的とボールとの衝突検出
targetList.stream()
    .filter( target ->
        ( target.getX() <= boll.getX() && boll.getX() <= target.getX() + target.getImage().getWidth() )
        ||
        ( target.getX() <= boll.getX() + boll.getImage().getWidth() && boll.getX() + boll.getImage().getWidth() <= target.getX() + target.getImage().getWidth() )
    )
    .filter( target ->
        ( target.getY() <= boll.getY() && boll.getY() < target.getY() + target.getImage().getHeight() )
        ||
        ( target.getY() <= boll.getY() + boll.getImage().getHeight() && boll.getY() + boll.getImage().getHeight() < target.getY() + target.getImage().getHeight() )
    )
    .forEach(target -> target.disappear());//的の消滅

filterを二回やらなくて、&&でももちろんいいです。

このあと

今回で衝突の検出はやったのですが、衝突の応答処理はやっていないので、たまにめり込んでしまったりします。

その衝突系の調整か、ゲームオーバー処理を追加したり、音を鳴らすなどの調整で2回分。

そのあとは、スマフォで動かすための活動に入るつもりです。 

↓↓↓↓ここから↓↓↓↓追記したところ

衝突検出についていくつかコメントをもらったので試してみる。ありがとうございます!

衝突検出をメソッド化しよう

上記で○○と△△のコリジョン、■■と○○のコリジョン…と言ってたけど、 まとめられるよね、という話を頂いてそうだよなあと。

   private boolean collision( float aRightUp, float aLeftDown, float bRightUp, float bLeftDown ){

        if( ( aLeftDown <= bLeftDown && bLeftDown <= aRightUp ) || ( aLeftDown <= bRightUp && bRightUp <= aRightUp ) ){
            return true;
        }
        return false;
    }

というわけでこんな↑メソッドを作っておきます.

左右と上下をみて判定していたけど、ものによっては左右だけみれば話が終わるものもあったので、片方だけみるメソッドにしています。 呼ぶ側は左右と上下それぞれ呼んでもらう。

Intersectorrクラスのoverlap

libGdxに衝突検出の処理がすでに実装されているそうで、それを使ったほうがいいんじゃというコメントを頂きました。 ありがとうございましたm(_ _)m

というわけでこちらも試してみます。

今は四角いオブジェクトしかないので、四角と四角の衝突検出です。

qiita.com

英語は修行中なので、上の記事を参考にさせていただきました。

Rectangle bollRec = new Rectangle(boll.getX(), boll.getY(), boll.getImage().getWidth(), boll.getImage().getHeight());
Rectangle berRec = new Rectangle(ber.getX(), ber.getY(), ber.getImage().getWidth(), ber.getImage().getHeight());
if (Intersector.overlaps(bollRec, berRec)){
    boll.chengeDirection();
}

com.badlogic.gdx.math.Rectangle オブジェクトどうしの衝突を検出してくれるようなので、今までの作りに合わせるためオブジェクトを新たに生成してしまっていますが…便利ですね!

丸と丸とをみるときにも使えるみたいなので、今後ひらしょー本で得た知識と比較していく材料にしていく。

*1:

ゲームプログラマになる前に覚えておきたい技術

ゲームプログラマになる前に覚えておきたい技術