Opalでゲームを作るには(opal-phaser)
この記事はOpal Advent Calendar 2016とRuby Game Developing Advent Calendar 2016の21日目の記事です。
OpalはRubyスクリプトをJavaScriptに変換してくれる処理系です。ということは、Opalを使えばRubyを使ってブラウザで動くゲームが作れるはずです。
opal-phaser
opal-phaserはPhaserというブラウザゲーム用ライブラリをOpalから使えるようにしたものです。今回はこれを触ってみたいと思います。
サンプルを動かしてみる
PhaserのサンプルをOpalに移植したものがあるみたいなので、とりあえず動かしてみましょう。READMEに書いてある通り、git cloneしてbundle installします。
$ git clone https://github.com/orbitalimpact/opal-phaser-examples
$ cd opal-phaser-examples
$ bundle install
そのあと、適当なサンプルのディレクトリに移動してbundle exec rackupし、http://localhost:9292/ を開きます。
$ cd examples/basics/click_on_image/
$ bundle exec rackup
実行結果です。自分が何をしようとしていたのか一瞬分からなくなりましたが、opal-phaserのサンプルを動かしていたのでした。画像をクリックするとクリックした回数が画面に表示されます。とりあえず動いているようで良かったです。
他のサンプルも俄然、気になってきましたが、ここから先は自分の目で確かめてほしい。サブディレクトリがたくさんありますが、config.ruで検索すればサンプルだけ列挙できます。
% find . -name config.ru
./examples/animation/animation_events/config.ru
./examples/animation/change_frame/config.ru
./examples/animation/change_texture_on_click/config.ru
./examples/animation/destroy_animation/config.ru
./examples/animation/dynamic_animation/config.ru
./examples/animation/group_creation/config.ru
./examples/animation/load_texture/config.ru
./examples/animation/looped_animation/config.ru
./examples/animation/multiple_anims/config.ru
./examples/basics/click_on_an_image/config.ru
./examples/basics/image_follow_input/config.ru
./examples/basics/load_an_animation/config.ru
./examples/basics/load_an_image/config.ru
./examples/basics/move_an_image/config.ru
./examples/basics/render_text/config.ru
./examples/basics/tween_an_image/config.ru
./examples/bitmap_data/alpha_mask/config.ru
./examples/sprites/dynamic-crop/config.ru
また、phaser.js本体のExampleはもっとたくさんあるようです。
サンプルを読む
先ほどのbasics/click_on_image/のソースを見てみましょう。まず、index.htmlです。
<head>
<title>Click On An Image</title>
<script src="//cdn.jsdelivr.net/phaser/2.4.4/phaser.js"></script>
<script src="/assets/main.js"></script>
</head>
phaser.jsをCDNから読み込んでいます。/assets/main.jsは、同ディレクトリのmain.rbがOpalによってコンパイルされるので、それを読み込んでいます。bodyタグの方も見てみましょう。
<span id="title">click on an image</span>
<script>
Opal.load("main");
</script>
<div id="example"></div>
このscriptタグはOpalでコンパイルしたJSを実行開始する部分なので、消してはいけません。それ以外はclick on an imageというメッセージと、divタグが一つあるだけです。このdivタグは画像を表示するために使いそうですね。
main.rb
雰囲気が掴めたところでmain.rbを見てみましょう。これがOpalによってJSに変換されるRubyスクリプトで、このデモの中心部分です。
最初にImageというクラスがあります。こいつがクリックできるアインシュタイン(やっぱりアインシュタインだったのか…)のオブジェクトです。画像ファイルはこのディレクトリではなくて、少し上の階層のassetsというディレクトリにあります。そのあたりの設定はconfig.ruでやっているようです。
class Image
def initialize(game)
@sprite_key = "einstein"
@sprite_url = "assets/pics/ra_einstein.png"
@game = game
end
createメソッドに、クリックイベントを拾う処理が書いてあります。events.onでイベントハンドラを登録できるようですね。
def create
@counter = 0
listener = proc do
@counter += 1
@text.text = "You clicked #{@counter} times!"
end
...
@text = @game.add.text(250, 16, '', { fill: '#ffffff' })
@image.events.on(:down, self, &listener)
end
@gameという変数は、以下のGameクラスのオブジェクトです。ファイルの最後がGame.new
なので、ここがゲームプログラムのエントリポイントになるようですね。parent: "example"という指定は、index.htmlの<div id="example">
を描画領域として使う、という指定でしょう。
class Game
def initialize
game = Phaser::Game.new(width: 800, height: 600, renderer: Phaser::AUTO, parent: "example")
state = MainState.new(game)
game.state.add(:main, state, true)
end
end
MainStateクラスはその下で定義されています。これとかを見ると、「タイトル画面」「プレイ中画面」みたいにシーンごとにStateを定義するみたいです。
class MainState < Phaser::State
def initialize(game)
@game = game
end
def preload
@image = Image.new(@game)
@image.preload
end
def create
@image.create
end
end
おわりに
今回はopal-phaserを紹介しました。プロジェクトとしては2年前からあるようで、今も開発が続けられています。
https://github.com/orbitalimpact/opal-phaser のGamesの項に、もう少しゲームらしいサンプルがあります。(tankgameはどうやって操作するのかよくわからない感じでしたが)
触ってみて良く分からないとかうまく動かないことがあれば、Twitter等で聞いてもらえればお手伝いできるかもしれません。