【enchant.js】 「最速でクルマを乗りこなすゲーム」の技術的解説
- April 26th, 2011
- Posted in ゲームプログラミング
- Write comment
さきほど公開した「最速でクルマを乗りこなすゲーム」ですが、一応技術的な解説をしておきますよっと。
↑ これね。
ざざっとソースをみていく感じすかね。あ、それからenchant.js、ちょこちょこバージョンアップしているようなので、最新版をダウンロードしておくと吉です。
というわけでソースの解説ですな。ちょこちょこコメントいれつつ紹介していきます。
enchant();
window.onload = function() {
var game = new Game(320, 320);
game.preload('chara4.gif', 'numbers.gif', 'tiles.png', 'title.gif', 'replay.gif');
ここらへんはいいですよね。なお、title.gifとreplay.gifはGIFアニメにしてゲームっぽいものにしています。ゲームはこういう一手間でぐっと印象が違ってきますよね。
game.onload = function() {
var time = 0; // クリアまでの秒数
var currentNumber = 10; // 今おっかけるべきタイルの数値
var carType = 0; // クルマの色
var startButton = []; // クルマを選ぶとき用のボタン
var startX = 100; // クルマの出現位置
var startY = 100;
var titleScene = new Scene(); // タイトル画面
var gameScene = new Scene(); // ゲームのメイン画面
var scoreScene = new Scene(); // プレイ後のスコア画面
まずは初期設定ですね。今回のポイントはenchant.jsのSceneですな。
このSceneですが、レイヤーのようなもので、画面を重ねてその間を行き来することができます(pop, push的に)。
このゲームでは、プレイ前のスタート画面(クルマの色を選べる)、プレイ画面、プレイ後のスコア画面を3つのSceneを作っています。

↑ タイトル画面。

↑ プレイ画面。

↑ スコア画面。
では次のコードをみてみます。
// setup title scene
var titleAnim = new Sprite(320, 100); // "Pick your car to start"のボタンを作ります
titleAnim.image = game.assets['title.gif']; // 画像を指定。
for (i=0; i<4; i++) { // クルマの画像を並べてボタンにします。
startButton[i] = new Sprite(32, 32);
startButton[i].image = game.assets['chara4.gif'];
startButton[i].frame = i; // クルマ画像のFrameを指定。
startButton[i].x = 160 - 64 + (32 * i);
startButton[i].y = 160 - 16;
startButton[i].id = i;
startButton[i].addEventListener('touchstart', function() { // クリックされたときの挙動
carType = this.id; // これがクルマの色になります。
game.pushScene(gameScene); // ゲームのメイン画面(gameScene)を前面に持っていきます。
});
titleScene.addChild(startButton[i]); // ボタン(クルマ)を追加。
}
titleScene.addChild(titleAnim); // これらをtitleSceneに追加。
ここではタイトル画面の部品を配置しています。タイトル画面(titleScene)自体を表示させるのはもうちょっと後になります。
では次にいきましょう。
// setup score scene
var finalScore = new Label('00.00'); // スコア用のラベル(前面)
finalScore.font = "24px 'Arial Black'";
finalScore.color = '#ff0000';
finalScore.x = 40;
finalScore.y = 70;
var bgFinalScore = new Label('00:00'); // スコア用のラベル(背面)
bgFinalScore.font = "24px 'Arial Black'";
bgFinalScore.color = '#cccccc';
bgFinalScore.x = finalScore.x + 1; // 1ずつずらしてドロップシャドウのような効果を出します。
bgFinalScore.y = finalScore.y + 1;
var replayAnim = new Sprite(320, 100); // "Replay?"のボタンを作ります。
replayAnim.y = 130;
replayAnim.image = game.assets['replay.gif'];
replayAnim.addEventListener('touchstart', function() { // リプレイをクリックされたときの挙動。
time = 0; // いろいろリセットしています。
currentNumber = 10;
number.frame = currentNumber;
car.x = startX;
car.y = startY;
car.speed = 2.0;
car.setDegree(-90);
$('#post_to_twitter').remove();
game.popScene(); // 今のScene(scoreScene)を外して背面のScene(gameScene)を表示します。
});
scoreScene.backgroundColor = 'white';
scoreScene.addChild(replayAnim);
scoreScene.addChild(bgFinalScore);
scoreScene.addChild(finalScore);
ここではゲーム後のスコア画面を作っています。スコア用のラベルは前面と背面を作ってドロップシャドウのような表現にしてみました。これも大事な一手間かと。
それからReplayボタンを押したときの挙動も書いています。popSceneを使うことで現在のシーンを外して背面のシーンを表示させることができます。
さて次にいきましょう。
// setup game scene
var label = new Label('00.00');
label.font = "24px 'Arial Black'"; // スコア用のラベル(前面)
label.color = '#ffffff';
label.x = 5;
label.y = 280;
var bgLabel = new Label('00:00'); // スコア用のラベル(背面)
bgLabel.font = "24px 'Arial Black'";
bgLabel.color = '#333333';
bgLabel.x = label.x + 1;
bgLabel.y = label.y + 1;
var bgPattern = new Sprite(320, 320); // 背景画像の設定
bgPattern.image = game.assets['tiles.png'];
var number = new Sprite(16, 16);
number.image = game.assets['numbers.gif'];
number.frame = currentNumber; // 数字のパネルを配置
number.x = Math.random() * (320-16); // 位置はランダムに。
number.y = Math.random() * (320-16);
ここからメイン画面ですね。まずはスコア表示用のラベルを配置し、ランダムな位置に数値パネルを置きます。
// car logic inspired by http://d.hatena.ne.jp/nakamura001/20110423/1303565014 var car = new Sprite(32,32); car.image = game.assets['chara4.gif']; car.x = startX; car.y = startY; car.degree = -90; car.vx = 0; car.vy = 0; car.speed = 2.0; car.setDegree = function(degree) { this.degree = degree; this.rotation = degree + 90; this.vx = Math.cos(degree * Math.PI / 180); this.vy = Math.sin(degree * Math.PI / 180); }; car.setDegree(car.degree); car.addEventListener('enterframe', function() { car.frame = carType; // クルマの色をcarTypeにあわせて設定。 var isMoving = false; if (game.input.up || game.input.down) isMoving = true; if (isMoving && game.input.left) { this.degree -= 4; this.degree = Math.min(this.degree, this.degree+360); this.setDegree(this.degree); } if (isMoving && game.input.right) { this.degree += 4; this.degree = Math.max(this.degree, this.degree-360); this.setDegree(this.degree); } if (game.input.up) { this.x += this.vx * this.speed; this.y += this.vy * this.speed; } if (game.input.down) { this.x -= this.vx * this.speed; this.y -= this.vy * this.speed; } if (this.x+this.width < 0) this.x = game.width; if (this.x > game.width) this.x = -this.width; if (this.y+this.height < 0) this.y = game.height; if (this.y > game.height) this.y = -this.height; if (this.within(number)) { // 数値パネルをとったときの処理。 currentNumber--; // 数値を一つ下げて・・・。 number.x = Math.random() * (320-16); // ランダムな位置に新しいパネルを表示。 number.y = Math.random() * (320-16); number.frame = currentNumber; this.speed += 0.5; // さらにクルマのスピードをあげています。 // console.log('hit'); if (currentNumber < 0) { // ゲームクリア時の処理。 finalScore.text = bgFinalScore.text = 'Your Score: '+(time++/game.fps).toFixed(2); // スコアの表示 game.pushScene(scoreScene); // スコア画面を表示 // 以下、TwitterにPostする部分を追加。 var statusText = '『最速でクルマを乗り回せ!』ゲームのスコアは【'+(time/game.fps).toFixed(2)+'秒】でした! http://www.ideaxidea.com/enchantjs/cars/ #enchantcars'; var postDiv = $('<div id="post_to_twitter"></div>').append( $('<a href="" target="_blank"><span class="css3button">このスコアをTwitterに投稿する?</span></a>') .attr('href', 'http://twitter.com/home?status='+encodeURIComponent(statusText)) ); $('body').append(postDiv); } } // console.log(this.x + ' ' + this.y); }); gameScene.addChild(bgPattern); // もろもろ追加。 gameScene.addChild(number); gameScene.addChild(car); gameScene.addChild(bgLabel); gameScene.addChild(label);
ここらへんが本当のメインですね。クルマを動かすところのロジックは正直「強火ですすめ」さんのところをざっと拝借したのでそちらをご覧ください。
逆に僕が作り込んだのは、数値パネルとの衝突処理と、最終的にクリアしたときの処理です。
最後にツイッターにスコアを登録できる部品を追加していますが、それはjQueryで実現しています。あらかじめcss3buttonクラスのスタイルもCSS(CSS3 Button Generatorを使いました)にて指定しておくと良い感じです(詳しくはindex.htmlを見てください)。
そこまで来たらあとは最後の部分ですな。
// タイマー処理
game.addEventListener('enterframe', function() {
label.text = bgLabel.text = (time++/game.fps).toFixed(2);
});
// タイトル画面を表示
game.pushScene(titleScene);
}
game.start(); // ゲームスタート!
};
ここらへんはいいですよね。
ふぅ、以上ですかね。本当はハイスコアを保持して・・・なんかも考えたのですが今回はやめておきました。というわけでご参考までに。



No comments yet.