円と矩形の当たり判定の処理を軽くなるように修正してみた

※お前ら直帰すんなよ( ・´ー・`)ゲームしてけ!

今作ってるゲームで円と矩形の当たり判定が必要になったのでそれについて自分なりにわかったことを書いておきます(‘ω’)ノ

 

今回参考にさせていただいた記事はこちらでござる

▷▷▷ http://ftvoid.com/blog/post/300

解説を読んでみるとそんなに難しいことではないですね。正直これならすぐにググらずに少し自分で試行錯誤すればよかったな、とちょっと後悔したくらい。だってちょっと悔しいやん(^^;)

とりあえず解説通りに作ってみた

解説通り上下左右を円の半径分大きくとるのと、四隅で円の当たり判定を取るような感じでプログラムを作ると以下のようになりました。

function collision(L, R, T, B, x, y, radius){//L,R,T,Bは矩形キャラの四隅の座標、x,y,radiusは円形キャラの座標と半径
    if(L - radius < x && R + radius > x && T < y && B > y){//矩形の領域判定1
        return true;
    } 
    if(L < x && R > x && T - radius < y && B + radius > y){//矩形の領域判定2
        return true;
    }
    if((L - x) * (L - x) + (T - y) * (T - y) < radius * radius){//左上の当たり判定
        return true;
    }
    if((R - x) * (R - x) + (T - y) * (T - y) < radius * radius){//右上の当たり判定
        return true;
    }
    if((L - x) * (L - x) + (B - y) * (B - y) < radius * radius){//左下の当たり判定
        return true;
    }
    if((R - x) * (R - x) + (B - y) * (B - y) < radius * radius){//右下の当たり判定
        return true;
    }
    return false;
}

上から順番に重なってたら当たったということでtrueを返すようになってます。

 

なぁーんだ簡単じゃーん(*´ω`)

 

と楽勝だったな、なんて思ってたんですけど、よく見てください。

これあんまり良くないですよね?

無駄な処理をしている?

ちょっとして気づいたんですよ。

 

これ、当たらない時って全部判定してるの?

 

それって無駄じゃない?

基本的に画面内の小さなキャラ同士が当たる確率なんて当たらない確率と比べたら圧倒的に低いですよね?

なのに当たらない時に全部の判定するなんて無駄過ぎる。

無駄は嫌いなんだよ。無駄だから。無駄無駄無駄無駄。。

当たらないことを判定する

どこが無駄だったのかを考えてみると当たることを判定するようにしたから、当たらない場合に全部の当たる判定を確認しなくちゃいけないんだろうとなりました。

だったら当たらない判定をしたらいいんじゃね?(・∀・)

ということで作り直したのがこちら

function collision(L, R, T, B, x, y, radius){
    if(L - radius > x || R + radius < x || T - radius > y || B + radius < y){//矩形の領域判定1
        return false;
    } 
    if(L > x && T > y && !((L - x) * (L - x) + (T - y) * (T - y) < radius * radius)){//左上の当たり判定
        return false;
    }
    if(R < x && T > y && !((R - x) * (R - x) + (T - y) * (T - y) < radius * radius)){//右上の当たり判定
        return false;
    }
    if(L > x && B < y && !((L - x) * (L - x) + (B - y) * (B - y) < radius * radius)){//左下の当たり判定
        return false;
    }
    if(R < x && B < y && !((R - x) * (R - x) + (B - y) * (B - y) < radius * radius)){//右下の当たり判定
        return false;
    }
    return true;//すべての条件が外れたときに当たっている
}

全部の条件に合わなかったときに当たっていることになります。

簡単な解説

当たらない条件を考えるとまず下図の黄色の部分が一番範囲が広く、キャラ同士当たらない場合(グレーのがキャラね)ほとんどこの条件ではじくことができます。無駄がない。

後は赤い部分の判定です。各頂点に半径を足した(または引いた)分より外側だった場合で、円の当たり判定でも重なってなければ当たっていないといえるはずです。

まとめ

どっちも判定回数が多いですが通常のゲームではキャラ同士が当たっていない確立の方が高いと思うので当たらない条件で処理を書いた方が処理が軽くて良いんやないかな、と思います。

こんな感じで、何か調べて作ったりしてもなにかしら自分で気づいてより軽く速くなるような工夫って必要になったりします。今回の私のプログラムもまだまだ改善点があるかもしれません。

なにかしら「ん?」って感じたらちょっと探ってみたりするとプログラムが上達するのかもしれませんね(´∀`)

どのゲームで遊ぶ?

クッソしょうもないあほげー。ある温泉街で殺人事件がおきた。どうやら犯人はこの中にいるようだ。
哀れな魂を愛に導くゲーム。壁に当たるまでまっすぐにしか進めません。全10ステージ。
マリオ風横スクロールアクションゲーム。地下から制限時間内に脱出しろ!
スマホ専用対戦ピンポンゲーム。タッチだけのイライラ操作が逆に楽しい?

コメント欄

※コメントはまだありません※

コメントを残す

メールアドレスが公開されることはありません。

ゲームタグ一覧

ゲーム開発書籍(amazon)

HTML5 ゲーム開発の教科書 スマホゲーム制作のための基礎講座
ゲームを作りながら楽しく学べるHTML5+CSS+JavaScriptプログラミング[改訂版] (Future Coders(NextPublishing))
改訂2版 はじめて学ぶ enchant.jsゲーム開発