JavaScriptは素晴らしい言語だ。
けれども限界もある。特にクラス定義にはちょっとクセがある。これが気持ち悪いという人も多い。
enchant.jsのClass.createを使うとかなり軽減されるけど、やっぱりちょっと変だ。
でも日本には素晴らしい言語がある。
言うまでもなくRubyだ。
enchant.jsはとても快適だけど、Rubyから使えたらもっと楽しいんじゃないか。
そんなことをふと考えてみた。
ブラウザでRubyを使う方法として、JSRubyやHotRubyというものがあるらしい。もちろんJavaで実装されたJRubyを使ってアプレットとして実現する方法もあるけど、これはスマートフォンでは使えない。
どちらもプロトタイプ実装の域を出ていないみたいだけど、JSRubyの方はRubyインタプリタをJavaScriptで実現しようとしたみたいで、HotRubyはRuby1.9から登場したYARVというRuby仮想マシンのみをJavaScriptで実現し、Rubyからのコンパイルはサーバで行う方式だ。
JSRubyはまだ実装が不十分でクラスの定義などができなくてRubyの良さが活きない。
そこで今回はHotRubyを使ってenchant.jsを無理矢理動かせないか実験してみた。
まず、HotRubyをサーバにインストールする。
HotRubyのためにRuby 1.9.0をインストールしなくてはならない。1.9.0でないとダメだ。VM: InstructionSequenceが使えなくなってしまっている。
これがYARVコンパイラをRubyから呼び出す重要なクラスなのだ。
あとはお決まりのやり方で、WebサーバにHotRubyをインストールするだけ。
さて、次は実際のRubyコードとのつなぎ込みだ。
これが実はけっこう難しい。
HotRubyの場合、Rubyコードを一旦サーバに送り、コンパイルしてYARVの中間コードを受け取る。
今回はまだ実験の段階なので、enchant.jsの基本的な初期化はJavaScript側でやることにしてみた。
window.onload=function(){
game = new Game(320,320);
game.preload("andy.gif"); //アンドロイドの画像をロード
game.onload = function(){
andy = new Sprite(16,16); //とりあえずアンドロイドのスプライトを作ってみる
andy.image = game.assets["andy.gif"];
andy.setXY = function(x,y){this.x=x;this.y=y;} //Rubyから呼び出しやすいようにsetterを作る
game.rootScene.addChild(andy);
ruby = new HotRuby(); // HotRubyを初期化
ruby.runFromScriptTag('http://shi3z.yier.in/compileRuby.cgi'); //サーバに設置したYARVコンパイラを呼ぶ
setTimeout(function(){ //コンパイルが終わった頃に実行される
game.rootScene.addEventListener('enterframe',function(){
// コンパイルした中間コードのオブジェクトを直接呼び出してみる
ruby.invokeMethod(ruby.topSF.localVars[2], "enterFrame",
[], ruby.topSF, "VM_CALL_ARGS_SPLAT_BIT" , false);
});
},1000);
}
game.start();
}
この実験コードを実行するとき、実際のRubyコードは以下のようになっている。
class Andy
def initialize
@x = 100
end
def enterFrame
@x = @x+1
$native.andy.setXY @x,100;
end
end
andy = Andy.new
</script>
これを実行すると、ひとまずこんな画面になるところまでは行った。
アンドロイドのアイコンが、時間経過に従って右へ移動する。
JavaScript側のgame.rootScene.addEventListener(‘enter frame’….)の中から、Ruby側のandyオブジェクトのenterFrameメソッドが呼び出されているのだ。
ちなみにこのHotRubyは、Rubyの仮想マシンを理解する上でも非常に面白い。
Safariのコンソールでrubyを表示させると、YARVのデータが内部でどんな構造になっているかビジュアル的に理解できる。
たとえば、作成したクラスは全てruby.classesに格納される。
それぞれのクラスをさらに調べると、親クラスを内部に保存している。
ただ、ネイティブアクセスのための$nativeというグローバル変数を経由してJavaScript側のオブジェクトにアクセスができる。
けれどもenchant.jsの魅力はコールバックによるイベントモデルだ。
コールバックをちゃんとやろうとすると、HotRuby.jsに手を加えないと難しそうだ。
Ruby側で「このオブジェクトのこのメソッドをこのイベントに割り当ててくれ」という指定をして、それをきちんとJavaScript側からキックする仕組みを作る必要がある。
ただ、これができるように改造すれば、Rubyでenchant.jsを使うのは比較的簡単そうだ。
誰か挑戦しないかな・・・
Related posts:
Post a Comment