(ゲームイメージ)

別窓表示

当たり判定を操作する

前のセクションで武器をリンゴから剣に変えた時、リンゴと敵との衝突処理をまるまる無効にしてしまいました。これではせっかく剣の攻撃が当たっても消えてくれません。

今回は、ちょっと他の例をみながら進めてみます。

まずは判定を作ってみる

今回の参考ソースはこれ↓で進めてみたいと思います。この例の場合、動くのは敵ではなくプレイキャラクターですが、大きな違いはないでしょうから流用可能でしょう。

  • 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();で宣言されていて、処理上、その後呼び出される処理ですのでエラーにはなりません。

画面の情報として状態管理する場合も書いていましたが、それを生かすなら下記のような書き方になるでしょうか。 考えの順序としては

  1. game.rootScene.on('enterframe', function(){}); の中の部分で、「プレイキャラクターと敵1が衝突しているかどうかを1件ずつチェックしたい
    • 具体的にこの敵1件はplayerと比較する
    • チェック結果、衝突していれば敵キャラクターを消し、スコアを増加させる
  2. そのためには、敵オブジェクト生成時に、それを扱う順番を持った箱(配列)を用意する必要がある

というようなところでしょうか。実装面では

  1. playerと同列に敵を取り扱う配列を宣言しておこう
  2. 宣言したら、配列の後ろ生成オブジェクトを追加して持って置くようにしよう
  3. 敵配列を一件ずつループして衝突チェックを実装しょう

というような事を書いてみれば良さそうです。

画面の情報として状態管理する場合)

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足す
    }
}

こんな感じでしょうか。

できあがりはゲームイメージを参考にしてみてください。