JavaScriptでゲーム作成 - その1

仕事でちらっとJavaScriptを使ったので、興味がわいて来て現在勉強中です。

JavaScriptはプロトタイプベースのオブジェクト指向言語ということで、Javaなどの普通のオブジェクト指向言語とは毛色の違うものです。
また、手続き型言語と同じような書き方の関数でありながら、実はオブジェクトっていうような、今まで使ってきた言語と違う仕様に、苦戦しつつも、なんとか理解出来てきたように思います。

どれだけ理解出来たかを試すなら、実際にコーディングしてみるしかない→ゲームを作ろう!ということで、簡単なゲームを作ってみました。

作ったのは一番簡単なシューティングゲームであるインベーダーです。
[実行]ボタンを押すとスタートします。


カーソルキーで移動、Zキーでショットです。
(動かない場合は画面を一回クリックしてください。)


にとよんさんのところの記事を読んでいたので、はてなダイアリー上でJavaScriptを動かせるってことは知っていたのですが、今回作ったゲームみたいなのをどうやって動かせばいいのかわからず、色々試したんですけど結局、動かなくて、

もうダメ元で

document.write('<body bgcolor="#000000" text="#ffffff"
                                     onKeyDown="input(event)">');
document.write('<script type="text/javascript"src="invader.js"></script>');

というように外部ファイル読み込みタグとBodyタグをdocument.writeで出力してみたら、無事に動きました。ちゃんとキー入力も受け付けてくれています。


この方法を使えば、ブラウザ上で手軽に遊んでもらえるゲームを作ることが出来ますねー。今度はもっと本格的なゲームを…って、これ普通にFlashで出来ちゃうことですよね……。

JavaScriptはゲームを作りづらいですし、今時Flashが動作しないブラウザなんてものもないですから、JavaScriptで作られたゲーム、というのは需要がなさそうです。

何か残念だなぁ。


大した処理は行っていませんが、ソースコードの全文を以下に載せておきます。
(何かおかしな書き方などしてあったらツッコミをお願いします!)
長めなので、続きを読む記法を使ってみます↓

var SC_WIDTH  = 400;
var SC_HEIGHT = 400;

var PATH = "images/";

function Base(){}
Base.prototype = {
    isHit : function(obj) {
        if((this.x < obj.x + obj.width) && (this.x + this.width > obj.x) && (this.y < obj.y + obj.height) && (this.y + this.height > obj.y))
            return true;
        return false;
    },
    update: function() {
        document.getElementById(this.id).style.left = this.x;
        document.getElementById(this.id).style.top  = this.y;
        document.getElementById(this.id).style.visibility = (this.visible ? 'visible':'hidden');
    },
    setPos: function(x,y) {
        this.x = x;
        this.y = y;
    },
    out: function() {
        this.visible = false;
        document.getElementById(this.id).style.visibility = 'hidden';
    },
    draw  : function() {
        document.write( '<img src="'+this.path+'" ID="'+this.id+'" STYLE="position:absolute;top:'+this.y+';left:'+this.x+';visibility:'+(this.visible?'visible':'hidden')+'">' );
    }
}

var Player = function() {
    this.id = "player";
    this.path = PATH+"plane.gif";
    this.width = 25;
    this.height = 18;
    this.x = SC_WIDTH / 2 - this.width / 2;
    this.y = 300;
    this.speed = 8;
    this.visible = true;
}
Player.prototype = new Base();
Player.prototype.move = function(event) {
    switch(event.keyCode) {
        case 37:this.x += -this.speed; break;
        case 38:this.y += -this.speed; break;
        case 39:this.x += this.speed;  break;
        case 40:this.y += this.speed;  break;
        case 90:return true;
    }
    this.update();
    return false;
}

var Bullet = function(id) {
    this.x = 0;
    this.y = 0;
    this.id = "bullet"+id;
    this.path = PATH+"stary.gif";
    this.width  = 8;
    this.height = 8;
    this.visible = false;
    this.shotRad = 0;
    this.speed = 5;
}
Bullet.prototype = new Base();
Bullet.prototype.shot = function(x,y,rad) {
    if( this.visible ) return false;
    this.x = x;
    this.y = y;
    this.shotRad = rad;
    this.visible = true;
    return true;
}
Bullet.prototype.move = function(){
    if( !this.visible ) return;
    this.x += Math.cos(this.shotRad) * this.speed;
    this.y += Math.sin(this.shotRad) * this.speed;
    if( this.y < -20 ){
        this.visible = false;
    }
    this.update();
}

var Enemy = function(id,i) {
    this.id = "enemy"+id;
    this.path = PATH+"inve"+i+".gif";
    this.width = 24;
    this.height = 17
    this.x = SC_WIDTH / 2 - this.width / 2;
    this.y = 300;
    this.speed = 0.5;
    this.score = i*10;
    this.visible = true;
}
Enemy.prototype = new Base();
Enemy.prototype.move = function() {
    if( !this.visible ) return 3
    this.x += this.speed;
    if(this.x < 0){
        this.x = 0;
        return 1;
    }
    if(this.x+this.width > SC_WIDTH){
        this.x = SC_WIDTH - this.width;
        return 2;
    }
    this.update();
    return 0;
}
Enemy.prototype.turn = function() {
    this.speed = -this.speed;
}
Enemy.prototype.forward = function() {
    this.y += this.height/2;
}

var Score = function() {
    this.score = 0;
    this.add = function(num){
        this.score += num;
        document.getElementById("score").innerHTML = "SCORE:"+this.score;
    }
    this.draw = function() {
        document.write( '<div id="score">SCORE:'+this.score+'</div>' );
    }
}

var player = new Player();

var bullets = new Array(3*4);
for (var i = 0; i < bullets.length; ++i){
    bullets[i] = new Bullet(i);
}

var ENEMYS_X = 12;
var ENEMYS_Y = 4;
var enemys = new Array(ENEMYS_X*ENEMYS_Y);
var kind = new Array(3,3,2,1);
for(var i = 0; i < ENEMYS_Y; ++i){
    for(var j = 0; j < ENEMYS_X; ++j){
        var k = i*ENEMYS_X+j;
        enemys[k] = new Enemy(k,kind[i]);
        enemys[k].setPos(20+j*30,50+i*20);
    }
}

var score = new Score();

function input(event){
    if( player.move(event) ){
        for (var i in bullets){
            var center = player.x + player.width / 2 - bullets[i].width / 2;
            if( bullets[i].shot(center, player.y,-Math.PI/2) )
                break;
        }
    }
}

var timerID = setInterval(update,16*3);
function update() {
    for (var i in bullets){
        bullets[i].move();
    }
    for (var i in enemys){
        switch( enemys[i].move() ){
            case 2:
                for (var j in enemys){
                    enemys[j].forward();
                }
            case 1:
                for (var j in enemys){
                    enemys[j].turn();
                }
            break;
            case 0:
                for (var j in bullets){
                    if( !bullets[j].visible ) continue;
                    if( bullets[j].isHit(enemys[i]) ){
                        enemys[i].out();
                        bullets[j].out();
                        score.add(enemys[i].score);
                    }
                }
            break;
        }
    }
}

for (var i in bullets){
    bullets[i].draw();
}
for (var i in enemys){
    enemys[i].draw();
}
player.draw();
score.draw();