Skip to content

たった99行でシューティングゲームを作る方法

こんにちは。shi3zです。
実は週刊アスキー、月刊BestGearに続き、enchant.jsの連載が始まりました。
しかもフリーペーパーで。

その名も「トラ技ジュニア」

電気関係の技術者なら絶対に読んでるという伝説的技術情報誌「トランジスタ技術」創刊して実に47年という超名門誌。通称「トラ技」の、初の少年向けフリーペーパーです。隔月で発行される予定。

全国の高校や高等専門学校、専修学校などに無償配布されているほか、全国の書店で発売されている「トランジスタ技術」本誌にもオマケでついてきます。 

今日はリョウヘイがトラ技ジュニアに連載中の「100行で挑戦!ゲームプログラミング道場」から、わずか99行で作るシューティングゲームを紹介するよ!

ゲーム開発ってこんなに簡単なんだ!ということが伝わればいいな

まずはこんなゲームが作れるよ、という紹介。すごくシンプルなシューティングだよ

最初のゲームを開発するとき、どんなものがいい?と聞くとみんなたいていは縦スクロールのシューティングを作りたがる。縦スクロールのシューティングというのは、料理でいえばハムエッグ定食みたいなもので、必要なものがぜーんぶ揃ってると言えるだろう。

自分のキャラを動かし、敵を動かし、弾を撃って、当たったら敵が死ぬ。
ゲームに必要な要素がほとんど全部揃ってるよね?

さて、では実際のコードはどんなふうになってるかな?

enchant(); 
var Player = enchant.Class.create(enchant.Sprite, { //プレイヤー(自機)の定義
    initialize: function(x, y){
        enchant.Sprite.call(this, 16, 16); //自機をスプライトとして定義する
        this.image = game.assets['graphic.png']; //画像を読み込む
        this.x = x; this.y = y; this.frame = 0;//↓以下はマウスクリックで移動する処理
        game.rootScene.addEventListener('touchstart', function(e){ player.y = e.y; game.touched = true; });
        game.rootScene.addEventListener('touchend', function(e){ player.y = e.y; game.touched = false; });
        game.rootScene.addEventListener('touchmove', function(e){ player.y = e.y; });
        this.addEventListener('enterframe', function(){
            if(game.touched && game.frame % 3 == 0){ var s = new PlayerShoot(this.x, this.y); }
        });
        game.rootScene.addChild(this);
    }
});
var Enemy = enchant.Class.create(enchant.Sprite, {//敵キャラの定義
    initialize: function(x, y, omega){
        enchant.Sprite.call(this, 16, 16);
        this.image = game.assets['graphic.png'];
        this.x = x; this.y = y; this.frame = 3; this.time = 0;
        this.omega = omega; this.direction = 0; this.moveSpeed = 3;
        this.move = function(){
            this.direction += Math.PI / 180 * this.omega;
            this.x -= this.moveSpeed * Math.cos(this.direction); //三角関数でゆらゆら動きながら攻撃してくる
            this.y += this.moveSpeed * Math.sin(this.direction)
        };
        this.addEventListener('enterframe', function(){ //敵キャラの動きを設定する
            this.move();
            if(this.y > 320 || this.x > 320 || this.x < -this.width || this.y < -this.height){
                this.remove(); //画面外に出てしまったら自爆する
            }else if(this.time++ % 10 == 0){
                var s = new EnemyShoot(this.x, this.y); //10フレームに一回弾を撃つ
            }
        });
        game.rootScene.addChild(this);
    },
    remove: function(){
        game.rootScene.removeChild(this);
        delete enemies[this.key]; delete this;
    }
});
var Shoot = enchant.Class.create(enchant.Sprite, { //弾を定義
    initialize: function(x, y, direction){
        enchant.Sprite.call(this, 16, 16);
        this.image = game.assets['graphic.png'];
        this.x = x; this.y = y; this.frame = 1; 
        this.direction = direction; this.moveSpeed = 10;
        this.addEventListener('enterframe', function(){ //弾を毎フレーム動かす
            this.x += this.moveSpeed * Math.cos(this.direction);
            this.y += this.moveSpeed * Math.sin(this.direction);
            if(this.y > 320 || this.x > 320 || this.x < -this.width || this.y < -this.height){
                this.remove();
            }
        });
        game.rootScene.addChild(this);
    },
    remove: function(){ game.rootScene.removeChild(this); delete this; }
});
var PlayerShoot = enchant.Class.create(Shoot, { //プレイヤーの弾を定義
    initialize: function(x, y){
        Shoot.call(this, x, y, 0);
        this.addEventListener('enterframe', function(){
            for(var i in enemies){
                if(enemies[i].intersect(this)){ //敵に当たったら、敵を消してスコアを足す
                    this.remove(); enemies[i].remove(); game.score += 100;
                }
            }
        });
    }
});
var EnemyShoot = enchant.Class.create(Shoot, { //敵の弾を定義
    initialize: function(x, y){
        Shoot.call(this, x, y, Math.PI);
        this.addEventListener('enterframe', function(){//プレイヤーに当たったら即ゲームオーバーさせる
            if(player.within(this, 8)){ game.end(game.score, "SCORE: " + game.score) }
        });
    }
});
window.onload = function() {
    game = new Game(320, 320); //ゲームの初期化
    game.fps = 24; game.score = 0; game.touched = false; game.preload('graphic.png');
    game.onload = function() {
        player = new Player(0, 152);//プレイヤーを作成する
        enemies = [];
        game.rootScene.backgroundColor = 'black';
        game.rootScene.addEventListener('enterframe', function(){//↓ランダムなタイミングで敵を出現させる
            if(rand(1000) < game.frame / 20 * Math.sin(game.frame / 100) + game.frame / 20 + 50){
                var y = rand(320);//敵の出現位置はランダム
                var omega = y < 160 ? 1 : -1;
                var enemy = new Enemy(320, y, omega);
                enemy.key = game.frame; enemies[game.frame] = enemy;
            }
            scoreLabel.score = game.score;
        });
        scoreLabel = new ScoreLabel(8, 8);
        game.rootScene.addChild(scoreLabel);
    }
    game.start();
}

こんな感じで非常にコンパクトにまとまっている上に、ちゃんとオブジェクト指向の継承まで使っているという徹底ぶり。

まだちょっと冗長なところはあるけどね。
括弧がけっこう邪魔なので、CoffeeScriptを使うともっと短くなるかもしれない。

こういう、「短いコードでいかにゲームを作るか」っていうのもひとつのテーマとしては面白いよね。
本誌にはさらに詳しい解説が掲載されているぞ!


こんどから本屋さんに行ったら「トランジスタ技術」も探してみよう。

文・shi3z
このエントリーをはてなブックマークに追加
はてなブックマーク - たった99行でシューティングゲームを作る方法
Post to Google Buzz
Share on GREE

Related posts:

  1. enchant.js + node.jsで作る非同期型ネットゲームのプロトタイプ
  2. Ruby on enchant.js / RubyでHTML5ゲームを作ってみる
  3. 続・Ruby×enchant.jsへの挑戦 / イベントドリブンモデルの実現
  4. Rubyでenchant.jsを使える可能性(実験編)
  5. enchant.jsのサウンド機能で、ゲームをさらにカッコよく!

Facebook comments:

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*