当たり判定はゲームをする上で欠かせないもの。
アクションゲームでは的キャラクターと自分のキャラクターが衝突すると
ダメージを受けたりゲームオーバーになりますね。
この時、衝突の有無を判定することを「当たり判定」と呼びます。
当たり判定の実装
まずは、実践ということで、衝突させるプログラムを書いてみましょう。
判定と判定に対する処理がない場合下のようになります
衝突を判定する処理がないので、そのまますれ違っていきますね。
プログラムは次の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// code.9leap.net default template // based on enchant.js v0.7.1 enchant(); Kuma = Class.create(Sprite, { initialize:function(x, y){ this.image = game.assets['chara1.png']; Sprite.call(this, 32, 32); this.x = x; this.y = y; this.tx = this.x; this.ty = this.y; this.frame = 0; game.rootScene.addChild(this); }, onenterframe:function(){ this.y++; } }); window.onload = function(){ game = new Core(320, 320); game.preload('chara1.png'); game.fps = 15; game.onload = function(){ kuma = new Kuma(); }; game.start(); }; |
前回、前々回と実施している内容は同じですね。
クマ(男)とクマ(女)のコンストラクタを作成してゲームに出現させています。
次は実際に判定を入れてクマ(男)がクマ(女)とぶつかったときに止まるようにします。
intersect関数
キャラクタの衝突はintersect関数で実現することができます。
衝突=キャラクターの画像が重なっているとき
として判断します。ここで注意するべきことは、画像フレームのサイズがその
画像のサイズとなるので、色が乗っていない透明な部分も「衝突」の範囲と見なされます。
先ほどのすれ違うプログラムを改修して衝突の判定を入れたものが
次のプログラムです。
ちょっとわかりにくいのですが、クマ(女)とクマ(男)が接触する際に
少し停止しますね。
この接触については違和感を感じると思います。接触する前から
クマ(男)が停止してしまうのです。
これは画像(スプライト)が32×32で指定されているのに対してクマの画像の
横幅が32未満のためです。画像のない部分は透明になっているので
少し手前から停止することになります。
これでは、ゲームバランスに支障がでてしまいます。
なるべく見える画像と衝突検出可能な範囲は揃えるべきです。
そのため、実際の画像サイズに合わせた透明なダミースプライトを作成して
ダミースプライトに判定をさせる手法もあります。
実際のサンプルです。
ダミースプライトによる判定追加
ソース次の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
// code.9leap.net default template // based on enchant.js v0.7.1 enchant(); Kuma_man = Class.create(Sprite, { initialize:function(x, y){ Sprite.call(this, 32, 32); this.image = game.assets['chara1.png']; this.x = x; this.y = y; this.frame = 0; game.rootScene.addChild(this); }, onenterframe:function(){ //if(this.intersect(kuma_girl)){ if(kuma_man_Ds.intersect(kuma_girl_Ds)){ this.x == this.x; }else{ this.x++; } } }); Kuma_girl = Class.create(Sprite, { initialize:function(x, y){ Sprite.call(this, 32, 32); this.image = game.assets['chara1.png']; this.x = x; this.y = y; this.scaleX = -1; this.frame = 10; this.dummy_sprite = new Sprite(10, 26); this.dummp_sprite game.rootScene.addChild(this); }, onenterframe:function(){ this.x--; } }); Dummy_sprite = Class.create(Sprite, { initialize:function(x,y,obj){ Sprite.call(this,17,27); this.x = x; this.y = y; this.originSplite = obj; game.rootScene.addChild(this); this.moveTo(this.originSplite.x + this.originSplite.width / 2 - this.width / 2, this.originSplite.y + this.originSplite.height - this.height); //色付け this.backgroundColor = 'blue'; }, onenterframe:function(){ this.moveTo(this.originSplite.x + this.originSplite.width / 2 - this.width / 2, this.originSplite.y + this.originSplite.height - this.height); } }); window.onload = function(){ game = new Core(320, 320); game.preload('chara1.png'); game.fps = 15; game.onload = function(){ kuma_man = new Kuma_man(0,144); kuma_man_Ds = new Dummy_sprite(0,144,kuma_man); kuma_girl = new Kuma_girl(288,144); kuma_girl_Ds = new Dummy_sprite(288,14,kuma_girl); }; game.start(); }; |
ダミーのスプライトを作成するDummy_spriteコンストラクタを追加して
クマの画像とほぼ同じ大きさのスプライトを作成し、そのスプライトが
クマの動きに追従するようにしています。
within関数
他の衝突を判定する方法としてwithin関数を利用することができます。
先ほどのintersect関数との違いはwidthinはキャラクタの中心からの距離が指定した距離より小さい場合は「衝突」とみなします。
今回の場合はクマ(男)とクマ(女)のちゅ新距離がクマの幅の半分
なのでクマ男とクマ女の中心距離が16px以内になった場合に衝突(true)とみなします。中心からの距離による判定になるので、円の範囲で衝突を検知します。
プログラムは次の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
// code.9leap.net default template // based on enchant.js v0.7.1 enchant(); Kuma_man = Class.create(Sprite, { initialize:function(x, y){ Sprite.call(this, 32, 32); this.image = game.assets['chara1.png']; this.x = x; this.y = y; this.frame = 0; game.rootScene.addChild(this); }, onenterframe:function(){ //======================== //当たり判定と当たった場合の処理 //======================== if(this.within(kuma_girl,this.width/2)){ console.log(this.width/2); this.x == this.x; }else{ this.x++; } //======================= // 当たり判定ここまで //======================= } }); Kuma_girl = Class.create(Sprite, { initialize:function(x, y){ Sprite.call(this, 32, 32); this.image = game.assets['chara1.png']; this.x = x; this.y = y; this.scaleX = -1; this.frame = 10; game.rootScene.addChild(this); }, onenterframe:function(){ this.x--; } }); window.onload = function(){ game = new Core(320, 320); game.preload('chara1.png'); game.fps = 15; game.onload = function(){ kuma_man = new Kuma_man(0,144); kuma_girl = new Kuma_girl(288,144); }; game.start(); }; |
20から26行目の部分が当たり判定の処理を実施している部分です。
if文の条件にあるwithinというのが「衝突」を判定しています。
衝突したと判断されたときはif文内の処理が実施されます。
if文の中をわかりやすくかくと次のようになります。
1 |
クマ(男).widthin(クマ(女), 32/2) |
1 2 3 4 5 6 7 8 9 10 11 12 |
//======================== //当たり判定と当たった場合の処理 //======================== if(this.within(kuma_girl,this.width/2)){ console.log(this.width/2); this.x == this.x; }else{ this.x++; } //======================= // 当たり判定ここまで //======================= |
条件が一致する場合(衝突)はif文内の処理が行われるので
クマ(男)のx座標を現在値に入れるのでその場で停止します。
クマ(女)は停止しないので通過していきます。
そして接触がなくなるとelse文に入りクマ(男)も動き出すという処理になります。
それではクマ(女)にも当たり判定を入れてみましょう。
判定追加(クマ女)
クマ同士が接触すると無事止まるようになりましたね。
ソースは次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
// code.9leap.net default template // based on enchant.js v0.7.1 enchant(); Kuma_man = Class.create(Sprite, { initialize:function(x, y){ Sprite.call(this, 32, 32); this.image = game.assets['chara1.png']; this.x = x; this.y = y; this.frame = 0; game.rootScene.addChild(this); }, onenterframe:function(){ if(this.within(kuma_girl,this.width/2)){ console.log(this.width/2); this.x == this.x; }else{ this.x++; } } }); Kuma_girl = Class.create(Sprite, { initialize:function(x, y){ Sprite.call(this, 32, 32); this.image = game.assets['chara1.png']; this.x = x; this.y = y; this.scaleX = -1; this.frame = 10; game.rootScene.addChild(this); }, onenterframe:function(){ if(this.within(kuma_man,this.width/2)){ console.log(this.width/2); this.x == this.x; }else{ this.x--; } } }); window.onload = function(){ game = new Core(320, 320); game.preload('chara1.png'); game.fps = 15; game.onload = function(){ kuma_man = new Kuma_man(0,144); kuma_girl = new Kuma_girl(288,144); }; game.start(); }; |
次のプログラムを修正してクマとドクロがぶつかったときにゲームオーバーにしてください。
課題雛形サンプルダミースプライトを使った衝突判定について、サンプルを書き換えて
クマ(女)もクマ(男)と接触した場合にストップするようにしてください。