勢いこんで最近ゲームライブラリにお熱です。

enchant.jsは最近さらにモンスター化しているようです。

http://wise9.jp/archives/6928

トゥーンシェーディングとか涙ものですね。
最早最強の名前をほしいままにしているといって過言ではありません。
gl.enchant.jsとかやばいです。
そして一億総プログラマの計画もあるそうです。本当にすごいですね。
尊敬です。
実は応援してます。


しかし相変わらず一発ゲームのミドルウェアになっているようです。
ajax的な手軽な関数とかはないんですよね。(勉強不足なだけ?)
memory.enchant.jsじゃなくて、
twitterアカウントや9leapに依存しない、save的なメソッドがあってもいいと思うんですがね。
一発ゲームじゃないゲームは9leapでしか公開できないってのは、どうなのかと。
そんなメソッドくらい簡単なのに付けないのは、おそらくターゲットがそういうものを気にしないで
ゲームを作りたい人ということになるんでしょうね。

といっても、今やデファクトスタンダードです。
本もすごい売れ行きらしいです。

そんなenchant.jsのすごさに惚れ惚れしつつ、自分は、自作でコツコツと、ゲームライブラリを作りました。
(車輪の再開発乙w)

名前は、

sol.jsです。


といってもまだダウンロードは出来ません。
だってまだほとんどコアしか作ってないから。
前作の拙作であるsunflower.jsと違い、jQuery等の基底ライブラリに依存してません。
まぁ、これは最近では当然ですね。

しかしとうとうコアの製作が終わりましたよ。
Mapとか、Imageとか、preloadとか、Spriteとかまだまだこれから作るんですけど。

もともと僕はミドルウェアを作るのが目的ではなく、ゲームを作るのが目的。
もう、はやる気持ちを抑えきれなかったので、コアだけで、記念にゲームをつくって見ました。

  • FREEZE-

http://test.ipsleoz.com/sol_game1/index.html

落ちてくるボールをタッチして(凍結)フリーズさせるだけのゲームです。
まだレベルアップ時にスコアがついていかないとかあります。
(iphonefirefox,safariで出来ます。
Internet Exploreでは出来ません。仕様です。
または、HTML5, ECMAscript 262 ver5 以上の実装が必要 です。)

やってみるとわかりますが、マウスではきついものがありますね。
(ついでにレベルアップによるレベル別実装もまだ。レベル1難しすぎw
それは今夜実装したい。)

僕はミドルウェア専門じゃないんで、こっから、あくまでゲームを作るぜ!

ちなみに、FREEZの実装は今数えたら150行程度でした。
データ系の実装がまだなんで、200行以内では収まるんじゃないかと。

enchant.jsに比べると、シーン系の実装を自分でやっている分長いかもしれませんね。

ぶっちゃけenchant.jsと何が違うのか、僕自身がenchant.jsに精通しているわけではないんで、よくわかりませんが、

○要素のCSSをstyleで直接名前指定出来ます(CSSの"-"を"_"に変えるだけでおんなじ名前が直接使用可能)
○シーンをsurfaceとして定義していて、入れ替えたり、同時に表示させたり等が明快です。(同時に動かすことも可能)
○ある子要素がその親要素にデータを通知することが簡単。(親要素が子要素をループで回す必要はない)
○"addEventListner"という長い、間違いやすい文字列を書きまくる必要がない(onPushとかで関数を渡せばよい。他にはonFrameとかonReleaseとか)
○"scene"という間違いやすい文字列を書きまくる必要がない
○"sol"しか名前空間使ってないので、色んなクラス名を覚える必要がない、独自実装とかぶらない、ライブラリの実装なのか、独自実装なのか明快。
(実際には、object.prototypeにeachというメソッドも追加されています。ご注意)
○"sol.base"を基底にする全てのエレメントは、子を持つことができ、階層を構築することが出来ます、上をloopすると下も全てloopすることが出来ます。また、上をhideすると下も全てhideされ、上をremoveすると下も全てremoveします。下からは上に情報を通知することが出来ます。
○ゲームループ自体を自力実装可能。

とかですかね。

あとはsol.classとかがenchant.class.createとかなり類似していますが、実態はinitializeを呼ばないとダメだったりしていて、親クラスのコンストラクタを呼ぶのではないんで、これってオブジェクト指向的にどうなのという感じがしないでもなく、この実装ってどうなのーという気がしますが、見えていないところいろんなことが行われすぎているのが好きじゃないんで、
これはこれでいいかなと。
そもそも継承が深くなりすぎると、もたらすものは混沌ですし。

まぁ、論よりコードですよね。
というわけで、ソース。


以下、2012.3.7時点でのソース。

/****
 * javascript game.js 
 *  iphone
 *   w : 320
 *   h : 356 or 416(hide address bar)
 */

window.onload = function(){
    
    var SCREEN_WIDTH = 320;
    var SCREEN_HEIGHT = 416;

    var field = new sol.field( SCREEN_WIDTH , SCREEN_HEIGHT , { border:"1px solid #ccc"});

    var start_surface = new sol.surface(SCREEN_WIDTH,SCREEN_HEIGHT);
    var game_surface = new sol.surface(SCREEN_WIDTH,SCREEN_HEIGHT);
    var end_surface = new sol.surface(SCREEN_WIDTH,SCREEN_HEIGHT);
    
    // Menu bar
    var Menubar = sol.class(
        sol.base,
        {style:{border_radius:5,z_index:20,background_color:'black',color:'white',x:0,y:0,width:320,height:30,border:'1px solid #ddd'}});
    var menu_bar = new Menubar();

    var title = new sol.label('FREEZ' , 5 , 5 ) ;
    var score = new sol.label('score:' , 120 , 5 );
    var score_number = new sol.label( '0' , 160 , 5 );
    var now_level = new sol.label('level:1',65 , 5 );
    var push_button = new sol.button( "reload" ,
                                      { background_color:'black', color:'white',x:270,y:0,border_radius:3, padding:5, z_index:100,border:'1px solid #ddd'}, 
                                      function(){
                                          sol.util.reload();
                                      });
    menu_bar.has( push_button );
    menu_bar.has( title );
    menu_bar.has( score );
    menu_bar.has( score_number );
    menu_bar.has( now_level );

    // start surface
    var HR = sol.class(sol.label,{style:{font_size:30}});
    var HR2 = sol.class(sol.label,{style:{font_size:12}});

    var start_title = new HR('FREEZ', 100 , 100 );
    var start_expression = new HR2('全て落ちきる前に凍結せよ',80,140);
    var start_button = new sol.button( "START" , 
                                       { background_color:'#ccc',color:'black',x:110,y:200,border_radius:10,
                                         z_index:100,border:'1px solid black',padding_left:20,padding_right:20,},
                                       function(){
                                           start_surface.hide();
                                           field.changeSurface( "game" );
                                       });
    
    start_surface.prepear( start_title );
    start_surface.prepear( start_expression );
    start_surface.prepear( start_button );


    // game core
    var score = 0;
    var Ball = sol.class( 
        sol.base , 
        {
            style:{
                width:30,height:30,border_radius:20,background_color:"black",x:20,y:40,z_index:10,
            },
            freez:false,
            init:function(){
                this.style.x = sol.util.random( 1, 300 );
                this.style.y = sol.util.random( 10, 12 );
                this.initialize();
                this.dropped = false;
                this.onPush( function(){
                    this.freez = true;
                    score += 10;
                    this.css('background_color','white');
                    this.css('border','1px solid blue');
                    this.parent.freezed++;
                });
            },
            frame:function(){
                if( this.css( 'y' ) < 416 && this.freez == false ){
                    this.move( 0 , 2 );
                }
                if( this.css( 'y' ) >=  416 && this.dropped == false ){
                    this.parent.dropped++;
                    this.dropped = true;
                }
            },
        });

    var Balls = sol.class(
        sol.base,
        {
            style:{
                width:320,height:416,x:0,y:0,
            },
            freezed:0,
            dropped:0,
            frame:function(t){
                if( t % 5 == 0 && this.getRefCount() < 20 ){
                    this.has( new Ball() );
                }
                if( ( this.freezed + this.dropped ) >= 20 ){
                    end_score.setText("score<br />"+score);
                    
                    field.changeSurface( "end" );
                }
            },
        });

    var balls_controller = new Balls();
    game_surface.prepear( balls_controller );

    // end surface
    var end_score = new HR("score<br />" , 125,100 );
    var next_button = new sol.button( "NEXT LEVEL" , 
                                       { background_color:'#ccc',color:'black',x:105,y:200,border_radius:10,
                                         z_index:100,border:'1px solid black',padding_left:20,padding_right:20,},
                                      function(){
                                          sol.util.redirect(location.origin+location.pathname+"?l=2");
                                      });



    end_score.css('z_index',200);
    end_surface.prepear( end_score );
    end_surface.prepear( next_button );
    // ---

    field.has(menu_bar);
    field.addSurface({ "start":start_surface , "game":game_surface , "end":end_surface });
    field.setStartSurface("start");

    sol.loop( function(t){
        menu_bar.loop(t);
        field.loop(t);
    });

    sol.start();
};