弾とUFO

弾を撃てるようにする

エイリアンから弾を撃てるようにします。
だんだんとプログラムが長くなってきました。
変更点を間違えないように注意しましょう。

<script>
    // プレイヤー
    Crafty.sprite(70,78,"alien2.png",{alien:[0,0]});
    Crafty.e('2D, Canvas, alien, Gravity, Twoway, SpriteAnimation')
        .attr({x:50, y:50})
        .twoway(300)
        .jumper(0)                          // ジャンプさせない
        .reel('walk',300,0,0,2)             // アニメ設定
        .animate('walk', -1)                // アニメ再生
        .origin(35, 0)                      // 中心点のオフセットを指定
        .bind('KeyDown', function(e) {
            if( e.key == Crafty.keys.LEFT_ARROW ){
                this.flip("X");             // 絵をx軸反転させる
            }
            if( e.key == Crafty.keys.RIGHT_ARROW ){
                this.unflip("X");
            }
            if( e.key == Crafty.keys.Z ) {  // 弾を発射
                Crafty.e("2D, Canvas, Color, bullet")       // 弾を作成
                    .attr({x:this.ox, y:this.oy,w:5, h:10})   // alien の座標を代入
                    .color("rgb(255, 0, 0)")
                    .bind("EnterFrame", function() {
                        this.y -= 5;
                        if( this.y < 100 ) {    // この座標を超えると消える
                        //if( this.y < -20 ) {
                            this.destroy();     // 弾を消す
                        }
                    });
            }
        })
        .bind('EnterFrame', function () {
            if( this.x < 0 ) this.x = 0;
            if( this.x > 500 - this.w ) this.x = 500 - this.w;
        })
        .gravity('Floor');
</script>

 

2箇所、追加しています。
zキーが押されたら bullet という名前の四角を作成して、上へ移動させます。

弾を発射するプログラム

実行してzキーを押してみましょう。
下図のように途中で弾が消えます。

座標を見て弾を消す

if( this.y < 100 ) {
この条件で弾を消す命令 this.destroy() を実行しています。
作成したオブジェクトを消す処理を、しっかり見てもらうために入れました。

確認したらこの行を消して、下の行のコメントを外します。
if( this.y < -20 ) {

これで画面の上まで弾が移動します。

 

 

origin の効果

先ほど追加した origin をコメントにしてみて下さい。
コメントにするとは、実行されない行にするということです。
次のようにします。

// .origin(35, 0) // 中心点のオフセットを指定

originをコメントにする

これでこの行は無視されます。
origin の働きは、基点にオフセットの値を足しています。
これを無効にすると基点がそのまま弾のセット座標になるため、下図のようにエイリアンの左上から発射されます。
(赤い枠はエイリアンの実際の描画サイズ)

originをコメントにする

origin(35, 0) とはつまり、x座標に35、y座標に0を足して中心点を変更しています。

確認が終わったら、origin のコメントを外して有効にしましょう。

 

 

エイリアンの座標を受けとる方法

エイリアンが弾を撃っているように見せるため座標が必要です。
エイリアンの座標を受け取っているのは次のところです。

エイリアンの座標を渡しているところ

this.ox、this.oy にはオフセットで変更した座標が入ってます。
this.x、this.y との違いは下図のようになってます。

this.xとthis.oxの違い

実は今回のように座標を変えたいだけなら、計算でもOKです。
origin を使わないで、次のようにしても動きます。

.attr({x:this.x+35, y:this.y,w:5, h:10})

origin なんていらないじゃん
と思うかもしれませんが、絵を回転させたい時には必要です。
絵の中心で回転したいなら origin で中心点を変更しなければいけません。

 

 

UFOを表示する

UFO を表示します。
下のプログラムを入力しましょう。
プレイヤーのプログラム、地面のプログラム、その下に追加します。

<script>
    // UFO
    Crafty.sprite(168,76,"UFO.png",{UFO:[0,0]});
    Crafty.e('2D, Canvas, UFO')
        .bind("EnterFrame", function(){
            this.x += 5;
            if( this.x > 500 ) this.x = -200;
        })
        .attr({x:200, y:50}); 
</script>

500 とは画面のサイズです。
つまり、右側の画面の外まで移動したら x に -200 を代入しています。
-200 としているのは、UFOの幅を考え絵が隠れるようにするためです。

 

実行してみると、左からUFOが出現し右へ移動します。
これを繰り返します。

左からUFOが出現し右へ移動する

 

 

UFOに当たり判定を入れる

弾と当たったかを調べるため、UFOに当たり判定を入れます。
それからUFOが大きすぎたので半分のサイズに変更します。

<script>
    // UFO
    Crafty.sprite(168,76,"UFO.png",{UFO:[0,0]});
    Crafty.e('2D, Canvas, UFO, Collision')
        .bind("EnterFrame", function(){
            this.x += 5;
            if( this.x > 500 ) this.x = -200;
        })
        .attr({x:200, y:50, w:84, h:38})    // 1/2 に縮小する
        .onHit('bullet', function () {      // 弾に当たったら
            console.log("hit");             // 弾が消えていない為、何度もヒットする
        });
</script>

 

とりあえずコンソールを見ながら実行してみましょう。
そしてzキーを押して弾を撃ってください。
この時コンソールにzzzと表示されたら、ゲーム画面をクリックしてからテストしましょう。

コンソールを見ると、撃った弾よりもヒットした回数が多くなります。

コンソールを見ると何度もヒットしている

これはUFOに当たった弾を消していないため、すれ違うまで何度も当たっていたのです。

変更したプログラムを見てみましょう。

UFOはbulletとの当たり判定をしている

.attr({x:200, y:50, w:84, h:38})

表示位置だけでなく、wとhを指定することでサイズも変更できます。
絵の大きさが w:168 h:76 なのでちょうど半分のサイズです。

Crafty.e(‘2D, Canvas, UFO, Collision’)

Collision を入れることで当たり判定を行います。

.onHit(‘bullet’, function () {

当たり判定の相手を指定して、当たった時の処理を登録します。
つまり function の中が実行されます。

 

 

当たった弾を消す

UFOに当たった弾を消します。
これで1発の弾は、1回のみ当たります。

UFOの.onHitのところを変更します。

<script>
    // UFO
    Crafty.sprite(168,76,"UFO.png",{UFO:[0,0]});
    Crafty.e('2D, Canvas, UFO, Collision')
        .bind("EnterFrame", function(){
        this.x += 5;
            if( this.x > 500 ) this.x = -200;
        })
        .attr({x:200, y:50, w:84, h:38})    // 1/2 に縮小する
        .onHit('bullet', function (hitDatas) {  // 弾に当たったら
            for( let i=0, l=hitDatas.length; i<l; i++ ){
                console.log("hit");
                hitDatas[i].obj.destroy();      // 当たったobjを消す
            }
        });
</script>

 

変更点を見てみましょう。

当たった弾を消す処理

hitDatas[i].obj.destroy()

destroy() を使って消しています。
ここでいう obj とは、UFO に当たった弾 bullet です。

.onHit(‘bullet’, function (hitDatas)

function のカッコ内に hitDatas を入れました。
こうすることで当たった時の情報を活用できます。

for( let i=0, l=hitDatas.length; i<l; i++ )

なぜ for を使うのかな?
と思う人いますよね。理由は、複数の弾が同時に当たる可能性があるからです。
これで当たったものはすべて削除します。

実行したらコンソールを確認しながらプレイします。
UFOに当たった数が正しいか、弾が消えるかをみましょう。

 

 

ここまでのプログラム

<script>
    Crafty.init(500,400, document.getElementById('game'));
    Crafty.background('#f0fff0');
    // プレイヤー
    Crafty.sprite(70,78,"alien2.png",{alien:[0,0]});
    Crafty.e('2D, Canvas, alien, Gravity, Twoway, SpriteAnimation')
        .attr({x:50, y:50})
        .twoway(300)
        .jumper(0)                          // ジャンプさせない
        .reel('walk',300,0,0,2)             // アニメ設定
        .animate('walk', -1)                // アニメ再生
        .origin(35, 0)                      // 中心点のオフセットを指定
        .bind('KeyDown', function(e) {
            if( e.key == Crafty.keys.LEFT_ARROW ){
                this.flip("X");             // 絵をx軸反転させる
            }
            if( e.key == Crafty.keys.RIGHT_ARROW ){
                this.unflip("X");
            }
            if( e.key == Crafty.keys.Z ) {  // 弾を発射
                Crafty.e("2D, Canvas, Color, bullet")       // 弾を作成
                    .attr({x:this.ox, y:this.oy,w:5, h:10})   // alien の座標を代入
                    .color("rgb(255, 0, 0)")
                    .bind("EnterFrame", function() {
                        this.y -= 5;
                        if( this.y < -20 ) {
                            this.destroy();     // 弾を消す
                        }
                    });
            }
        })
        .bind('EnterFrame', function () {
            if( this.x < 0 ) this.x = 0;
            if( this.x > 500 - this.w ) this.x = 500 - this.w;
        })
        .gravity('Floor');
    // 地面
    Crafty.e('Floor, 2D, Canvas, Color')
        .attr({x:0, y:370, w:500, h:30})
        .color('#a0522d');
    // UFO
    Crafty.sprite(168,76,"UFO.png",{UFO:[0,0]});
    Crafty.e('2D, Canvas, UFO, Collision')
        .bind("EnterFrame", function(){
            this.x += 5;
            if( this.x > 500 ) this.x = -200;
        })
        .attr({x:200, y:50, w:84, h:38})    // 1/2 に縮小する
        .onHit('bullet', function (hitDatas) {  // 弾に当たったら
            for( let i=0, l=hitDatas.length; i<l; i++ ){
                console.log("hit");
                hitDatas[i].obj.destroy();      // 当たったobjを消す
            }
        });
</script>

 

 

『UFOに弾を撃ち込め』

ゲームを作ってみよう

  1. また始めよう
  2. プレイヤーの操作
  3. 弾とUFO
  4. ヒットとハイスコア