アセットのロード
これまでは絵を使うタイミングで読み込んでいましたが、数が少なかったのでほぼ問題ありませんでした。
しかし、今回は9枚あります。(これでも少ない方です)
ですからプリローダーを使って、ファイルの読み込みが完了してから次の処理へ進むようにしました。

assetsObj に登録した画像ファイルを読み込んでから、タイトルシーンへ移ります。
アセットリストの作り方です。
必要な情報は、1つ1つファイルを読み込んでいたときと同じです。
ファイル名と幅と高さ、それから絵を使うときの名前です。

ちなみに、ロード状況や失敗を知りたいときには、次のように function を増やします。
eにはロードしたファイル数、合計数、進行%、ファイル名が入ってます。
ゲームではよくあるロード画面など、この情報で作れますね。
Crafty.load( assetsObj,
function() { // ファイルロード後に実行
Crafty.scene("title");
},
function(e) { // ロード状況を知りたいとき
console.log(e);
},
function(e) { // ロードできなかった場合の対処
console.log(e);
}
);
タイトルシーン
タイトルシーンを見てみましょう。
3枚の絵を表示しています。
アセットから Sky Sea Title を座標指定して表示しています。
なお、先に実行したものが下に表示されます。
Crafty.scene("title", function() {
Crafty.e('Sky, 2D, Canvas').attr({x:0, y:0});
Crafty.e('Sea, 2D, Canvas').attr({x:0, y:85});
Crafty.e('Title, 2D, Canvas').attr({x:40, y:160});
});
海と空の絵を画面幅まで引き伸ばします。
w:600を追加しましょう。
Crafty.scene("title", function() {
Crafty.e('Sky, 2D, Canvas').attr({x:0, y:0, w:600});
Crafty.e('Sea, 2D, Canvas').attr({x:0, y:85, w:600});
Crafty.e('Title, 2D, Canvas').attr({x:40, y:160});
});

z キーでスタートの表示とキーの受け付けを作ります。
もう説明は不要ですよね。
Crafty.scene("title", function() {
Crafty.e('Sky, 2D, Canvas').attr({x:0, y:0, w:600});
Crafty.e('Sea, 2D, Canvas').attr({x:0, y:85, w:600});
Crafty.e('Title, 2D, Canvas').attr({x:40, y:160});
Crafty.e('2D, DOM, Text')
.attr({x:200, y:280, w:400, cnt:0})
.text("Z キーでスタート").textColor('#ff7f00')
.bind('KeyDown', function(e) {
if( e.key == Crafty.keys.Z ) {
Crafty.scene("main"); // ゲームメイン処理へ
}
})
.bind('EnterFrame', function () {
this.cnt++;
if( this.cnt %90 < 60 ){
this.textColor('#ff7f00');
} else {
this.textColor('#333333');
}
})
.textFont({size:'24px'});
});

メインシーンには何もないため、zキーを押すとまっ白になります。
メインシーン
まずは、海と空とプレイヤーを表示します。
Crafty.scene("main", function() {
Crafty.e('Sky, 2D, Canvas').attr({x:0, y:0, w:600});
Crafty.e('Player, 2D, Canvas, Twoway')
.attr({x:250, y:45})
.bind('EnterFrame', function () {
if( this.x < 0 ) this.x = 0;
if( this.x > 600-this.w ) this.x = 600 - this.w;
})
.twoway(100, 0); // 移動速度, jump速度
Crafty.e('Sea, 2D, Canvas')
.attr({x:0, y:85, w:600});
});
Twowayで左右の操作を可能にしています。
twoway(100, 0)の2番目はjump力です。0にすることで左右の動きのみに限定します。

敵の発生
敵を発生させます。
同時に移動もさせます。
仕組みを分かりやすくするため、左から右への移動のみにします。
Crafty.scene("main", function() {
let enemyCnt = Crafty.frame() +100; // +100:敵の発生タイミング
Crafty.e('Sky, 2D, Canvas').attr({x:0, y:0, w:600});
Crafty.e('Player, 2D, Canvas, Twoway')
.attr({x:250, y:45})
.bind('EnterFrame', function () {
if( this.x < 0 ) this.x = 0;
if( this.x > 600-this.w ) this.x = 600 - this.w;
})
.twoway(100, 0); // 移動速度, jump速度
Crafty.e('Sea, 2D, Canvas')
.bind("EnterFrame", function(){
if( Crafty.frame() > enemyCnt ){
enemyCnt += Crafty.math.randomInt(30, 150); // 敵の発生間隔
setEnemy();
}
})
.attr({x:0, y:85, w:600});
});
// 敵の発生
function setEnemy(){
const ypos = Crafty.math.randomInt(120, 415);
const speed = Crafty.math.randomNumber(0.5,1.5);
Crafty.e('Enemy, 2D, Canvas')
.attr({x:-70, y:ypos, spd:speed})
.bind("EnterFrame", function(){
this.x += this.spd;
if( this.x > 600 ){
this.destroy(); // 画面外へ出たら消滅させる
}
});
}
実行させると次のようになります。

発生タイミングには Crafty.frame() を使いました。
変数enemyCntを作るとき、初期値に初めの発生タイミングを代入しています。
let enemyCnt = Crafty.frame() +100; // +100:敵の発生タイミング
海の毎フレーム処理.bind(“EnterFrame”, function(){に敵を発生させる仕組みを入れます。
プレイヤーの EnterFrame 内に入れても良かったのですが、適当なobjにくっ付けるやり方を覚えてもらうためにこうしました。
Crafty.e('Sea, 2D, Canvas')
.bind("EnterFrame", function(){
if( Crafty.frame() > enemyCnt ){
enemyCnt += Crafty.math.randomInt(30, 150); // 敵の発生間隔
setEnemy();
}
})
.attr({x:0, y:85, w:600});
乱数は 30 から 150 の整数値を作っています。
enemyCnt には常に次の発生タイミングが入ります。
その値をフレームカウンタが超えたとき、発生処理を行います。
setEnemy() で敵を作ります。
y座標と速度は乱数にしています。
function setEnemy(){
const ypos = Crafty.math.randomInt(120, 415);
const speed = Crafty.math.randomNumber(0.5,1.5);
Crafty.e('Enemy, 2D, Canvas')
.attr({x:-70, y:ypos, spd:speed})
.bind("EnterFrame", function(){
this.x += this.spd;
if( this.x > 600 ){
this.destroy(); // 画面外へ出たら消滅させる
}
});
}
x座標の -70 は画面外から登場させるためです。
毎フレーム処理では、速度 spd だけ移動するようにします。
移動後、画面外(右端)へ出たかチェックして消滅処理も行います。
右から左への移動
潜水艦を右端からも出現させましょう。
右左の切り替え用 sw、x座標 xpos、向き dir を変数として作りました。
それから、敵オブジェクトを変数 ce に入れて絵の向きを変えるときに使っています。
// 敵の発生
function setEnemy(){
const ypos = Crafty.math.randomInt(120, 415);
const speed = Crafty.math.randomNumber(0.5,1.5);
let sw, xpos;
if( Crafty.math.randomInt(0, 1) == 1 ){
sw = 1;
xpos = -70;
} else {
sw = -1;
xpos = 600;
}
const ce = Crafty.e('Enemy, 2D, Canvas')
.attr({x:xpos, y:ypos, dir:sw, spd:speed})
.bind("EnterFrame", function(){
this.x += this.dir * this.spd;
if( (this.dir == 1 && this.x > 600) || (this.dir == -1 && this.x < -70) ){
this.destroy();
}
});
if( sw == -1 ){
ce.flip("X");
}
}
実行すると、右からも出現するようになりました。

変数swのデータは、結局は向き情報です。
dir という名前にしても良かったのですが、Enemy オブジェクト内の変数と区別するために sw としました。