エイリアンの移動範囲を限定する
いまエイリアンを操作して画面外へ出すと、戻ってくることができません。
画面の外には地面がないので落下しているのです。
画面の外へ出ないように変更します。
<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) // アニメ再生
.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");
}
})
.bind('EnterFrame', function () {
if( this.x < 0 ) this.x = 0;
if( this.x > 500 - this.w ) this.x = 500 - this.w;
})
.gravity('Floor');
</script>
追加したのは下の方の4行です。

これも以前にやりましたね。
これで画面の左右から出なくなります。
ところでなぜ this.w を引いているか覚えてますか?
これは描画の基点が左上にあるからです。
幅を計算に入れないと、画面の外へ出てしまうのです。

隕石の当たり判定
エイリアンと隕石の当たり判定を入れます。
ついに当たり判定です。ワクワクしますね。(私だけ?)
変更点が2箇所に分かれたので、全プログラムを載せます。
<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:5, y:50}) // 左端は安全エリア
.twoway(300)
.jumper(0) // ジャンプさせない
.reel('walk',300,0,0,2) // アニメ設定
.animate('walk', -1) // アニメ再生
.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");
}
})
.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:350, w:500, h:10})
.color('#a0522d');
// 隕石の絵を用意
Crafty.sprite(45,40,"meteor.png",{meteor:[0,0]});
// 隕石の発生
Crafty.bind("EnterFrame", function(){
if (Crafty.frame() % 20 == 0) obj_drop();
});
// 隕石を落とす
function obj_drop(){
Crafty.e("meteor, 2D, Canvas, Gravity, Collision")
.attr({x:Crafty.math.randomInt(80, 500-55), y:-50})
.checkHits("alien")
.bind("HitOn", function (hitData) {
Crafty.pause(); // すべてを止める
})
.bind('EnterFrame', function () {
this.y += 10;
if( this.y > 500 ){
this.destroy();
}
});
}
</script>
1つ目の変更点です。
エイリアンの初期座標を 50 から 5 に変更しました。
隕石に当たらないエリアを作る必要があったので、ここにしました。

2つ目の変更点です。
エイリアン alien との当たり判定を入れます。
とりあえず、当たったときシステムを止めます。

Crafty.e(“meteor, 2D, Canvas, Gravity, Collision”)
オプションに Collision を入れて当たり判定をします。
.checkHits(“alien”)
当たり判定の相手を指定します。
.bind(“HitOn”, function(hitData){
当たったときの処理を無名関数で作ります。
Crafty.pause();
すべての処理を止めます。
あとでここに本当の処理を入れていきます。
.attr({x:Crafty.math.randomInt(80, 500-55), y:-50})
乱数を80から445までとして、隕石の発生範囲を狭めています。
つまりx座標80より左側は安全エリアになります。
いい加減な当たり判定
いま使っている当たり判定はわりといい加減です。
何度か実行してみれば分かりますが、当たっていなくても処理が止まります。
どうしてでしょうか。
その理由は四角同士で当たり判定をしているからです。
プログラムを一部、下のように変更してください。
分かる人だけでいいです。分からない人は説明だけ読みましょう。
<script>
// エイリアンの当たり判定
Crafty.e('2D, Canvas, alien, Gravity, Twoway, SpriteAnimation, Collision, WiredHitBox')
// 隕石の当たり判定
Crafty.e("meteor, 2D, Canvas, Gravity, Collision, WiredHitBox")
</script>
WiredHitBox を入れることで赤い四角が表示されます。
この四角は当たり判定をする範囲を表示します。
実行してみると次のようになります。

赤い四角同士が重なっています。つまり当たっています。
しかし、絵だけを見るとすき間があいてます。
なんか「ダメな仕組みだな」と思うかもしれません。
でも初心者のときは、これでいいんです。
もし厳密な当たり判定をしようとしたら、専用のツールが必要になったり
絵を沢山表示したら動きが遅くなったりすることもあります。
なので我慢しましょう。
というか、この仕組みだけでも工夫すれば
かなりの精度の当たり判定をすることも可能です。
そんなにむずかしいことではないので、いつか説明したいと思います。
この話はここまでです。
プログラムを変更した人は元に戻しましょう。
ダメージを表示する
隕石が当たってもすぐに終わらない、つまり、ダメージ制のゲームにします。
次のように変更しましょう。
<script>
// 変数
let damage = 0;
// 隕石を落とす
function obj_drop(){
Crafty.e("meteor, 2D, Canvas, Gravity, Collision")
.attr({x:Crafty.math.randomInt(80, 500-55), y:-50})
.checkHits("alien")
.bind("HitOn", function (hitData) {
//Crafty.pause(); // すべてを止める
damage += 10;
Crafty("Damage").text("DAMAGE: "+damage); // ダメージ表示更新
})
.bind('EnterFrame', function () {
this.y += 10;
if( this.y > 500 ){
this.destroy();
}
});
}
// ダメージの表示
Crafty.e("Damage, DOM, 2D, Text")
.attr({ x:20, y:20, w:180, h:20 })
.textFont({size:'20px', weight:'bold'})
.text("DAMAGE: 0");
</script>
実行したら、隕石に当たってみましょう。
ダメージの表示が10ずつ加算されたらOKです。

追加・変更した点を見ていきます。
やり方としては以前やったスコアと同じです。

let damage = 0;
ダメージの変数です。ここに加算していきます。
//Crafty.pause();
すべてを止める処理をコメントにします。
消してもいいです。私はテストで処理を止めたいときなどに使ったりするので、コメントにしていつでも使えるようにしています。
damage += 10;
Crafty(“Damage”).text(“DAMAGE: “+damage);
変数 damage に 10 加算して、テキスト表示しています。
それから、Damage はテキストを取り扱うための名前であり、
text() の中は表示する文字列を指定しています。
damage という単語が沢山ありますが混乱しないように。

Crafty.e(“Damage, DOM, 2D, Text”)
ダメージ表示をするためのテキストを作成しています。
この行以下の設定で、表示位置やサイズを指定しています。