ランゲーの作り方⑤ 障害物との当たり判定をつける【enchant.js】

第1回:ランゲーの作り方① まずは準備
前回:ランゲーの作り方④ 障害物を出す

前回は障害物を出すようにしたので今回は障害物と自機との当たり判定と当たった時の処理を追加していこうと思います。出来上がりはこんな感じ(‘ω’)ノ

当たり判定について

まず最初に当たり判定について簡単に説明したいと思います(`・ω・´)

私たちが遊ぶテレビゲームというのは画面に画像が表示されて、その画像を操作したりして遊ぶわけなんですけど、これはただ画面に画像が表示されているだけで実際に当たるなんてことは当然ないわけです。なのでプログラムで当たったかどうか判別する処理を書いて、そしてゲームが実行されている間ずっと当たったか当たってないかという判定(当たり判定)をコンピューターがしています。

で、その当たり判定の基本的な判定方法として矩形(四角)の当たり判定と円の当たり判定というのがあります。

どちらを使うかはゲームによるんですが、マリオのようなアクションゲームでは矩形を使います。なぜなら、マリオを想像してもらえば分かりやすいと思うんですがブロックなど四角のものがステージを構成しています。なので矩形の当たり判定を用いた方が正しく判定されやすいわけです。

円の当たり判定はシューティングゲームに使われます。敵の弾など丸いものが多いため円の当たり判定の方が向いているわけです。

もちろん他にも当たり判定の方法はありますが最初に覚えるべき当たり判定はこの2つです(というかこれ以外は数学の知識が無いと対応できないです。私もまだちゃんとできていない(^^;))。

で、今回は一応アクションゲームなので矩形の当たり判定をとりあえず使ってやってみましょう(・∀・)

で、enchant.jsには当たり判定処理が最初から入っていて使うことができます。が、これが画像の大きさ(自機だと128×128)で判定してしまうので余白の部分でも当たってしまい実用的ではありません(;´Д`)

というわけで私が作った当たり判定を使いましょう。

function rectCollision(L1, R1, T1, B1, L2, R2, T2, B2){
    if(L2 <= R1 && L1 <= R2){
        if(T2 <= B1 && T1 <= B2){
            return true;
        }
    }
    return false;
}     

これをプログラムのどこかに追加してください。あ、解説はググってください(^^;)(解説が大変なので。。)

当たり判定の処理を追加

当たり判定の関数をメインループから直接呼んでもいいんですが当たった場合の処理を自機や障害物に書くことになるのでちょっと違うやり方にしてみます。

まず障害物クラスに

collision: function(chara){
    if(chara.collision(this.x, this.x + this.width, this.y, this.y + this.height)){
        //当たった時の処理(今回はないよ)
    }
}

このようにメソッドを追加します。引数はplayerです。そして障害物クラスからPlayrerクラスの当たり判定メソッドそ呼びます。

collision(L, R, T, B){
    if(rectCollision(L, R, T, B, this.x, this.x + this.width, this.y, this.y + this.height)){
        console.log("hit!");
        return true;
    }
    return false;
}

プレイヤークラスにcollisionメソッドを追加します。このなかで当たり判定関数を呼び出して判定します。

そして最初の当たり判定の呼び出しをMainGameScene内のループ処理に書きます。

//背景の移動処理
bg.x -= SCROLL_SPEED;
bg2.x -= SCROLL_SPEED;
if(bg2.x <= 0){
    bg.x = 0;
    bg2.x = GAME_SCREEN_WIDTH;
}
obstacle.move();
player.jump();
obstacle.collision(player);//これ

これで当たった場合にコンソールに「hit!」と表示されます。(F12を押してコンソールってタグのところね)

ここで一つ別件ですが説明しておきたいことがあります。MainGameSceneループ内にいくつか処理を書きましたが実はこれらは各クラスのonenterframe内に書くことができます。じゃあ、なんでわざわざメインループ内に書いたのか?
実はonenterframe内に書くと処理の順番がクラスを作った順番になると思います(確認していないけど(^^;))。だけど、処理によっては「これの次にこれをする」みたいなこともあるので私は基本的にほとんどの処理はメインループ内から呼ぶようにしています(アニメーションとかはあんまり関係ないからonenterframeでもいいとおもう)。

で、話を当たり判定に戻して、障害物・プレイヤークラスの各collisionメソッド内のif文はtrueが帰ってきたら当たっているので当たった処理を書きます。この方がメインループ内で当たり判定をしてから各クラスの処理用メソッドを呼ぶより書きやすいんじゃないかな、と私は思ってます(^^;)

当たる範囲を変更する

enchant.jsの当たり判定は画像の大きさのまま判定してしまうので自作関数で当たり判定をすることにしたのに今の段階では画像の幅でやってて自作関数でやってる意味がないです(^^;)なので当たる範囲を変更します。(当たり判定の状況が分かり辛いのでスクロールスピードを落として確認してね)

今現在はこの画像の黒枠の部分が当たり判定の位置になっているんですがこれを黄色の枠まで狭めます。これで多少は当たり判定がマシになると思います。

というわけで、当たる範囲を保存する変数を作ります。

Playerクラスのinitializeメソッド内に以下のような変数を作成します。

this.hitArea = [40, 90, 20, 128];

この配列は左端・右端・上端・下端の位置を順に入れてます。それぞれの位置は自機のx座標y座標からの位置にしています。数値はだいたいできめましたけど(^^;)

で、当たり判定のところを

if(rectCollision(L, R, T, B, this.x + this.hitArea[0], this.x + this.hitArea[1], this.y + this.hitArea[2], this.y + this.hitArea[3])){

のように修正します。

障害物も同様に修正します。

this.hitArea = [10, 54, 10, 54];
if(chara.collision(this.x + this.hitArea[0], this.x + this.hitArea[1], this.y + this.hitArea[2], this.y + this.hitArea[3])){

これで当たり判定の範囲が良くなったと思います。ただ、当たり判定はゲームにとってはとても大事な部分なのでゲームができてきたら実際にプレーしながら修正していく必要があると思います。

また、今回は当たり判定の範囲が一つしかないですが、キャラの状態によっては(ジャンプ中、しゃがむなど)で切り替える必要も出てきます。本格的にゲームを作ろうとなってくるとかなり大変な作業になってくる部分だと思います(;´Д`)

当たった後の処理

当たり判定はつけたものの当たっても自機は平然と走り続けてます(^^;)当たったらどうにかなってもらわないとゲームにならないので当たったときの処理を作っていきましょう。

ではプログラムを追加していくわけですが、今回はいっぱいあります(^^;)

まずは生きてるか死んでるかのフラグをPlayerクラスに作ります。

this.isDead = false;

でPlayerクラスの当たり判定部分を変更します。

if(this.isDead){//すでに当てってたら抜ける
    return;
}
if(rectCollision(L, R, T, B, this.x + this.hitArea[0], this.x + this.hitArea[1], this.y + this.hitArea[2], this.y + this.hitArea[3])){
    this.isDead = true;//やられた!
    this.vy = -10;//ちょっと跳ねるような演出を入れたいので
    this.frame = 24;//やられた用の画像に変更
    return true;
}

もうすでに当たっていた場合は当たり判定の必要がないのでreturnで抜けます。まだ当たっていない状態で当たったらフラグをtrueにして画像の切り替えなどをします。

そしてonenterframeにやられたときの処理を追加します。

onenterframe: function(){
    if(this.isDead){
        this.y += this.vy++;
        if(this.y > GAME_SCREEN_HEIGHT){
            var gameover = new GameoverScene(this);//ゲームオーバーシーンへ
        }
        return;
    }
    if(this.isJump){//ジャンプ中なら
    //・・・・

ジャンプと同じような処理で画面下に落下させます。画面外に出たらゲームオーバーシーンに切り替えます。それ以降の処理は必要ないのでreturnで抜けます。

jumpメソッド内もすでに当たっていた場合は抜けるようにしておきます(操作させない)

jump: function(){
    if(this.isDead){
        return;
    }

これで自機が障害物にあたったら泣きながらぴょんと飛び上がって落ちていくようになります。

ランゲー講座終了

当たり判定の処理もついて一応ゲームという感じに出来上がりました(*´ω`)ここまでのプログラムはこちらで確認できます→プログラムを見る

で、丁度区切りもいいのでランゲー講座はこれで終わりにしようかと思います。

本当はもうちょっと色々つけたりしたかったんですけど、そうなると色々変更箇所が出てきて説明が大変になってくるのでここで切り上げることにしました(;´・ω・)

なのでここから先はご自分で考えて修正したり付け足したりしてみてください(‘ω’)ノ

最後に改めてもう一度言わせていただきたいんですが、今回のこの講座は「素人開発者の私の個人的な開発スタイル」です。私なりのやり方に過ぎないです。なので私のやり方を鵜呑みにせず自分なりにいろいろ考えて「こうした方がもっと良くない?」というのを探していってください。きっとあるはずです(自分でそんなこと言うのもなんですけどね(;^ω^))

というわけで、ランゲー講座はここまで。お疲れさまでした(‘ω’)ノ

同カテゴリー記事

当サイトのオリジナルゲーム(ランダム表示)

アホなシューティングゲーム「世紀末サラダ伝 完結編」のサムネイル
おすすめ度
あほげー。聖帝シーザーとの一騎打ち。愛の力で巨悪を打ち砕け!
シュールなカジュアルゲーム「vs.蚊」のサムネイル
おすすめ度
部屋に侵入してきた蚊と戦うカジュアルゲームです。現実同様好き放題飛び回る蚊をうまく叩い...
パズルゲーム「ルービックパズルのサムネイル」
おすすめ度
平面なルービックキューブみたいなゲーム。スライドさせて模様を完成させます。
タイミング射的
おすすめ度
障害物に当たらないようにタイミングを狙って弾を撃つゲーム。

記事の感想・コメント

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

コメントを残す

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

ゲームジャンルタグ

新着技術ブログ記事

新着開発日記