ソースコード
game.js 内のソースコードです。
Crafty.init(600,450, document.getElementById('game'));
const assetsObj = {
"sprites": { // スプライトとして読み込み
"sky.png": {
"tile":20, "tileh":90, "map":{ "Sky":[0,0] }
},
"sea.png": {
"tile":20, "tileh":365, "map":{ "Sea":[0,0] }
},
"titlename.png": {
"tile":525, "tileh":104, "map":{ "Title":[0,0] }
},
"gameover.png": {
"tile":506, "tileh":102, "map":{ "Gameover":[0,0] }
},
"player.png": {
"tile":115, "tileh":41, "map":{ "Player":[0,0] }
},
"submarine.png": {
"tile":72, "tileh":27, "map":{ "Enemy":[0,0],"Explosion":[1,0] }
},
"bomb1.png": {
"tile":17, "tileh":7, "map":{ "Bomb1":[0,0] }
},
"bomb2.png": {
"tile":16, "tileh":16, "map":{ "Bomb2":[0,0] }
},
"flame.png": {
"tile":24, "tileh":47, "map":{ "Flame":[0,0] }
}
}
};
Crafty.load( assetsObj,
function() { // ファイルロード後に実行
Crafty.scene("title");
}
);
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'});
});
let bomb1_cnt; // プレイヤー爆弾カウンター
let stock_cnt; // 爆弾のストック
let score;
let gameover; // ゲームオーバー(プレイヤーのやられフラグ兼用)
Crafty.scene("main", function() {
let enemyCnt = Crafty.frame() +100; // +100:敵の発生タイミング
bomb1_cnt = 0;
stock_cnt = 0;
score = 0;
gameover = 0; // 0ならプレイヤーはやられていない
Crafty.e('Sky, 2D, Canvas').attr({x:0, y:0, w:600});
Crafty.e('Player, 2D, Canvas, Twoway, Collision')
.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;
if( gameover > 0 ){ // 撃沈演出
this.y += 0.3;
if( this.y > 85 ) this.destroy();
}
})
.bind('KeyDown', function(e) {
if( e.key == Crafty.keys.Z && gameover == 0 ) {
setPlayerBomb(this.x+this.w/2,this.y+30); // プレイヤー爆弾
}
})
.onHit('Flame', function (hitDatas) { // 火柱に当たったら
if( gameover == 0 ){
gameover = 1;
this.disableControl(); // 入力イベント応答しないように
this.vx = 0; // 移動を停止
Crafty.e("Delay").delay(disp_gameover, 1500, 0);
}
})
.twoway(100, 0); // 移動速度, jump速度
Crafty.e('Sea, 2D, Canvas')
.bind("EnterFrame", function(){
if( Crafty.frame() > enemyCnt ){
enemyCnt += Crafty.math.randomInt(30, 150); // 敵の発生間隔
setEnemy();
}
stockBomb();
})
.attr({x:0, y:85, w:600});
// スコア
Crafty.e("Score, DOM, 2D, Text")
.attr({ x:10, y:3, w:280, h:20 })
.textFont({size:'20px', weight:'bold'})
.textColor('#222222')
.text("SCORE: 0");
});
// ゲームオーバーの表示
function disp_gameover(){
Crafty.e('Gameover, 2D, Canvas, Tween')
.attr({x:45, y:160, z:100, h:1})
.tween({h:102}, 800, "easeOutQuad");
Crafty.e("Delay").delay(function() { // 指定秒後に実行する
Crafty.e('2D, DOM, Text').attr({x:200, y:280, w:300, z:100, cnt:0})
.text("Zキーを押してください").textColor('#ff7f00')
.textFont({size:'18px'})
.bind('KeyDown', function(e) {
if( e.key == Crafty.keys.Z ) {
Crafty.scene("title"); // タイトルへ
}
})
.bind('EnterFrame', function () {
this.cnt++;
if( this.cnt %80 < 50 ){
this.textColor('#ff7f00');
} else {
this.textColor('#333333');
}
});
}, 2000, 0); // delayの時間はここで設定(単位はミリ秒)
}
// 爆弾のストック表示
function stockBomb(){
let cnt = bomb1_cnt + stock_cnt;
while( cnt < 5 ){
Crafty.e('Bomb1, Stock, 2D, Canvas')
.attr({x:260+stock_cnt*20, y:10, rotation:90, no:stock_cnt});
stock_cnt++;
cnt++;
}
}
// プレイヤー爆弾
function setPlayerBomb(ix,iy){
if( bomb1_cnt >= 5 ) return;
bomb1_cnt++;
Crafty("Stock").each(function () { // ストック表示を1つ消す
if( this.no == stock_cnt-1 ){
stock_cnt--;
this.destroy();
}
});
Crafty.e('Bomb1, 2D, Canvas, Collision')
.attr({x:ix, y:iy})
.origin("center")
.onHit('Enemy', function (hitDatas) { // 敵に当たったら
for( let i=0, l=hitDatas.length; i<l; i++ ){
let obj = hitDatas[i].obj; // 当たった相手
Crafty.e('Explosion, 2D, Canvas') // 爆発演出
.attr({x:obj.x, y:obj.y, cnt:20})
.bind("EnterFrame", function(){
this.cnt--;
if( this.cnt%4 <2 ){
this.flip("X");
} else {
this.unflip("X");
}
if( this.cnt == 0){
this.destroy();
}
});
obj.destroy(); // 当たったobjを消す
score += 100;
Crafty("Score").text("SCORE: "+score);
}
bomb1_cnt--;
this.destroy();
})
.bind("EnterFrame", function(){
this.y += 1;
this.rotation += 2;
if( this.y > 450 ){
bomb1_cnt--;
this.destroy();
}
});
}
// 敵の爆弾
function setEnemyBomb(ix,iy){
Crafty.e('Bomb2, 2D, Canvas')
.attr({x:ix, y:iy})
.bind("EnterFrame", function(){
this.y -= 0.6;
if( this.y < 85 ){ // 海面まで来たか
this.destroy();
// 火柱
Crafty.e('Flame, 2D, Canvas')
.attr({x:this.x-5, y:this.y-44})
.timeout(function(){this.destroy();},300);
}
});
}
// 敵の発生
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(){
if( Crafty.math.randomInt(1,1000) < 8 && gameover == 0 ){ // 敵爆弾の発生率
setEnemyBomb(this.x,this.y);
}
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");
}
}