(ゲームイメージ)
当たり判定を操作する
前のセクションで武器をリンゴから剣に変えた時、リンゴと敵との衝突処理をまるまる無効にしてしまいました。これではせっかく剣の攻撃が当たっても消えてくれません。
今回は、ちょっと他の例をみながら進めてみます。
まずは判定を作ってみる
今回の参考ソースはこれ↓で進めてみたいと思います。この例の場合、動くのは敵ではなくプレイキャラクターですが、大きな違いはないでしょうから流用可能でしょう。
-
http://code.9leap.net/codes/show/1006
//フルーツのためのクラス Fruits = Class.create(Sprite, // Spriteクラスを継承 { initialize: function(frame) { //初期化する Sprite.call(this, 16, 16); //Spriteオブジェクトを初期化 this.image = game.assets['icon0.gif']; // ランダムな場所にフルーツを表示する this.x = Math.random() * 320; // Math.random()を使うと0から1未満の this.y = Math.random() * 320; // ランダムな少数が得られるのでそれで座標をつくる this.frame = frame; game.rootScene.addChild(this); }, onenterframe: function() { if (this.within(bear)) { // 自分自身(フルーツ)を画面から消す game.rootScene.removeChild(this); score++; //スコアを1足す } } });
ここのonenterframeを参考にしてみます。onenterframe中の処理は、衝突した時に自分自身が消えるのと、スコアをあげる処理です。今回、衝突時に消えるのは敵キャラクターですので、ここに衝突処理を追加してみます。
敵キャラクター自身の状態として管理)
// make new class for enemy
var Enemy = enchant.Class.create(enchant.Sprite, {
initialize: function(){
enchant.Sprite.call(this, 32, 32);
this.image = game.assets['chara6.png']; // set image
// this.moveTo(320, Math.floor(Math.random() * 320)); // set position
this.moveTo(0, Math.floor(Math.random() * 320)); // 変更
this.scaleX = -1;
// this.tl.moveBy(-360, 0, 160); // set movement
this.tl.moveBy(360, 0, 160); // 変更
this.frame = 9; // set image data
game.rootScene.addChild(this); // canvas
},
// 衝突時の処理を追加
onenterframe: function(){
if(this.within(player) ){
game.rootScene.removeChild(this);
score++; //スコアを1足す
}
}
});
これで当たった時に敵が消えます。withinの中がplayerと小文字で、まるでこの時点では定義も宣言もされていない変数に見えます。ですが、これは後のplayer = new Player();で宣言されていて、処理上、その後呼び出される処理ですのでエラーにはなりません。
画面の情報として状態管理する場合も書いていましたが、それを生かすなら下記のような書き方になるでしょうか。 考えの順序としては
- game.rootScene.on('enterframe', function(){}); の中の部分で、「プレイキャラクターと敵1が衝突しているかどうかを1件ずつチェックしたい
- 具体的にこの敵1件はplayerと比較する
- チェック結果、衝突していれば敵キャラクターを消し、スコアを増加させる
- そのためには、敵オブジェクト生成時に、それを扱う順番を持った箱(配列)を用意する必要がある
というようなところでしょうか。実装面では
- playerと同列に敵を取り扱う配列を宣言しておこう
- 宣言したら、配列の後ろ生成オブジェクトを追加して持って置くようにしよう
- 敵配列を一件ずつループして衝突チェックを実装しょう
というような事を書いてみれば良さそうです。
画面の情報として状態管理する場合)
var player = new Player();
var enemies = []; // 後で判定する用に追加。
// generate enemy every 60 frames
game.rootScene.tl.then(function() {
// var enemy = new Enemy();
enemies.push(new Enemy()); // 生成した敵オブジェクトを配列に追加する
}).delay(30).loop();
//
// (中略)
//
var score = 0;
var attacking = 0;
game.rootScene.on('enterframe', function(){
if( player.frame == 16) {
attacking ++;
}
if( attacking == 3 ) {
player.attackend();
attacking = 0;
}
// 敵とプレイキャラクターが当たっているかどうかを1件ずつ確かめる
for(var i = 0; i < enemies.length; i ++){
if(player.within(enemies[i]) ) {
game.rootScene.removeChild(enemies[i]);
score ++; //スコアを1足す
}
}
});
なんにしても動かし方は自由です。まずは色々書いてみることと色々ソースを眺めてみることです。
判定条件を追加する
まだ問題が残ります。今のままでは、攻撃中でなくともプレイキャラクターに当たりさえすえば敵が消えてしまいます。というわけで、敵キャラクターを消す条件を「プレイキャラクターに当たった場合」に「プレイキャラクターが攻撃状態を取っている場合」を追加してみます。
条件同士のつなぎ文句は「かつ」ですね。論理演算子とかいうやつです。
// 衝突時の処理を追加
onenterframe: function(){
if(this.within(player) && player.attackframe >= 0 ){
game.rootScene.removeChild(this);
score++; //スコアを1足す
}
}
// 敵とプレイキャラクターが当たっているかどうかを1件ずつ確かめる
for(var i = 0; i < enemies.length; i ++){
if(player.within(enemies[i]) && attacking > 0 ) {
game.rootScene.removeChild(enemies[i]);
enemies.splice(i--, 1); // 配列の長さも変えておく
score ++; //スコアを1足す
}
}
こんな感じでしょうか。
できあがりはゲームイメージを参考にしてみてください。