Javascriptゲームエンジンのまとめと自作

HTML5Javascriptは、次世代ブラウザの中心的技術となった。

それは、iphoneがフラッシュのサポートをうち切ったことで、ますます明確になった。

フラッシュ以外でゲームを作成する方法はいくつかある。


実際のゲーム開発におけるコストを考えたとき、開発しやすさや、更新しやすさを考えたとき、Javascript+HTML5+CSS3の開発はObjective-Cに勝る場合がある。

そして、ブラウザの性能やiphoneを始めとするスマートフォンの速度も大幅に向上してきている。

ひょっとしたら最後に笑うのは標準化されつつある
Javascript+HTML5+CSS3
かもしれない。

そこで、JavascriptHTML5とCSS3によるゲーム開発ライブラリを調べてみた。

JavascriptHTML5、CSS3によるゲームの開発

現在いくつものライブラリが出てきている。

どれもsprite機能を持ち、Map機能も持ち、ゲームループを実装した本格的なものだ。

enchant.js

ARCといういかにもかっこいい名前の大学生チームが作成した、Javascriptでゲームを作るライブラリ。
UEIがバックについてそのサポートを行なっているらしい。

  • UEIによるenchant.js

http://wise9.jp/archives/1666

  • 作者本人によるプレゼン

http://enchant.heroku.com/

  • 公式サイト

http://enchantjs.com/ja/

このライブラリでのゲーム開発は、例えば以下のようになる
( 公式サイトのサンプルより抜粋)

enchant();

window.onload=function(){
    var game = new Game( 230 , 320 );
    gamefps = 24;
    game.preload('chara1.gif');
    game.onload = function(){
        var bear = new sprite( 32 , 32 );
        bear.x = 9;
        bear.y = 9;
        bear.image = game.assets('chara1.gif');

        bear.addEventListener( 'enterframe' , 
                               function(e){
                                   if( game.input.right ){
                                       bear.x += 2;
                                   }
                                   if( game.input.left ){
                                       bear.x -=2;
                                   }
                                   if( game.input.up ){
                                       bear.y -=2;
                                   }
                                   if( game.inputdown ){
                                       bear.y +=2;
                                   }
                               });
        game.rootScene.addChild( bear );
        
        var pad = new Pad();
        pad.x = 0;
        pad.y = 224;
        game.rootScene.addChild(pad);
        game.rootScene.backgroundColor = '#ffffff';
    };
    game.start();
};

なるほど、美しい。

ちょっとpadの意味が一見して分からないが、再生してみると、画面左下に自動的にpadの画像が出た。

どうやら使えるイメージ、マップ、ドット絵を同梱しているらしい。
イデアを即座にゲームにする事に重点を置いたゲームライブラリであると思う。

enterframeにバインドしているのは、各フレームが始まる時に、この関数を呼び出すためだ。

ちなみに、他のライブラリも見てみよう。

GameQuery

jQueryをゲームように拡張したライブラリだ。

  • 公式サイト

http://gamequery.onaluf.org/

http://gamequery.onaluf.org/tutorials/1/step1.php

記法がjQueryの記法であるので、非常にDOM的にかける。
しかし、直感的に、オブジェクティブ指向的に記述できるのはenchant.jsの方かもしれない。

crafty

ソース例:(Demoのソース)

window.onload = function() {
	Crafty.init(550, 440);
	
	Crafty.sprite(64, "images/fruit.png", {
		banana: [0,0],
		apple: [1,0],
		watermelon: [2,0],
		orange: [3,0],
		coconut: [4,0],
		lemon: [5,0]
	});
	
	Crafty.background("url('images/bg.png') no-repeat");
	
	var scoreEnt = Crafty.e("2D, DOM, Text").attr({x: 5, y: 5, w: Crafty.viewport.width, h: 50}).text("Score: 0"),
		score = 0;
	
	Crafty.c("fruit", {
		_choice: ["banana", "apple", "watermelon", "orange", "coconut", "lemon"],
		_xspeed: 0,
		_yspeed: 0,
		
		init: function() {
			var index = Crafty.randRange(0, 5),
				fruit = this._choice[index],
				rotation = Crafty.randRange(8, 12),
				direction = Crafty.randRange(0, 1);
				
			this.addComponent(fruit).origin("center");
			this.y = Crafty.viewport.height;
			this._yspeed = Crafty.randRange(15, 18);
			this.z = 1;
			
			if(direction) {
				this.x = 0;
				this._xspeed = Crafty.randRange(3, 5);
			} else {
				this.x = Crafty.viewport.width;
				this._xspeed = -1 * Crafty.randRange(3, 5);
			}
			
			this.bind("enterframe", function() {
				this.rotation += rotation;
				this.y -= this._yspeed;
				this.x += this._xspeed;
				
				if(this._y > Crafty.viewport.height) {
					this.destroy();
					if(!this.hit) {
						score -= (index+1) * 10;
						scoreEnt.text("Score: "+score);
					}
				}
			});
			
			this.bind("mouseover", function() {
				this.sprite(index, 1);
				this.hit = true;
				score += (index+1) * 10;
				scoreEnt.text("Score: "+score);
				
				Crafty.e("2D, DOM, "+fruit).attr({z:0, x: this._x, y: this._y, alpha: 0.2}).sprite(index, 2);
				
				this.unbind("mouseover");
			});
		}
	});
	
	Crafty.e().bind("enterframe", function(e) {
		var sparsity = Crafty.randRange(10, 50);
		if(e.frame % sparsity == 0) {
			Crafty.e("2D, DOM, fruit, Gravity, Mouse").gravity("floor");
		}
	});
};

ソース例をみるかぎり、enchant.jsほど直感的でないにしても、enchant.jsに似ている。

  • 公式サイト

http://craftyjs.com/

その他cocos2Dとかもある。

非常に面白い。

そこで、無謀にも自分でもつくってみようと思った!

自分用ゲーム開発ライブラリの要件
  • ゲームループを自分でかける
  • 表示する各部品ごとに設定をかける
  • 表示する各部品に対して、簡単に操作をかける
  • タッチ(iphone)とクリックを拾える(その位置も簡単に取得できる)

とりあえずここまで出来ました。
berry_gameです。

$( function(){
       
       berry_game.setField( 'scratch' );

       // オブジェクトの作成
       var ball = berry_game.make( "<div>" , {} ,false )
           .setStart( function(ts){ return true; } )
           .setEnd( function(ts){ return this.data.ef == true ; } )
           .setInit( function(ts){ 
                         this.setPos( this.arg.x , this.arg.y );  
                         this.flag = true; 
                         this.data.d = 10 ; 
                         this.moon();

                         var color_list = ["red" , "black" , "orange" , "pink" , "blue" ];

                         this.setBo( color_list[berry_game.random( 0 , 5 )] , 3 , 'solid' );
                         //this.setBg( color_list[berry_game.random( 0 , 5 )] );
                         this.setW(10);
                         this.setH(10);
                         this.data.ef = false;
                         this.show();} )
           .setLoop(function(ts){
                        if( this.explode( this.data.d , 20 ) == false ){
                            this.data.ef = true;
                        }
                    })
           .setDestroy( function(ts){ this.remove(); } );

       // メインループ
       berry_game.loop = function(){
           if( berry_game.flag.push ){
               berry_game.add( ball , {"x":berry_game.point.x , "y":berry_game.point.y } );
           }
       };
       berry_game.start();
   }
 );

様々な処理が面倒なので、内部的なDOM操作はjQueryで行なっています。
setFiledで動作範囲をセットします。
makeで内部動作させるオブジェクトをメイクします。

  • setStartでこのオブジェクトの動作条件を
  • setEndでこのオブジェクトの終了条件を
  • setInitでこのオブジェクトの初期化処理を
  • setDestroyでこのオブジェクトの終了処理を
  • setLoopでこのオブジェクトの動作を設定します。

◎this.dataにこのオブジェクト内固有で使用できる様々なデータを格納しつつ、それぞれの処理を記述します。

そして、berry_game.loopに全体のループ処理を記述します。

この例のソースコードでは、花火ができます。

iphoneでもできるように、タッチでも反応します。
しかし花火をクローンして、複数描画すると処理速度が追いつかないようです。
花火をクローンしないことによってiphoneでも処理できます。

次はスプライト機能をつけ、マップ処理簡単に行えるようにしたいと思います。