mruby-minigameの紹介
注意!
2016年現在、この記事の内容は古く、間違いが含まれます。
- 最新のmruby-minigameのAPIと違う。
- Image#hold_drawingの説明が間違っている。 いわゆる、スプライトバッチの機能なので「描画順が担保されない」は間違い。
- mrubyのVisual Studioツールチェインのデフォルトはデバッグビルドではなくなっている。
- 現在のAllegro5のWindowsバイナリの入手方法はNuGet経由になっている。
この投稿は mruby Advent Calendar 2013 5日目の記事です。
mruby-minigameは2Dゲームプログラミングのためのmruby拡張モジュールです。
アイデアが思い浮んだ時に パッと動くところまで実装できるようなフレームワーク/ライブラリを目指しています。
この記事ではmruby-minigameのビルドと簡単に使い方の説明をします。
Allegro 5のインストール
mruby-minigameはallegro 5というゲームライブラリをつかっているので まず先にallegro 5をインストールする必要があります。
Ubuntuの場合はsudo apt-get install liballegro5.0 liballegro5-dev
でOKです。
Windowsの場合はhttps://www.allegro.cc/files か http://targonski.nazwa.pl/thedmd/allegro から 使用するコンパイラ(mingwかMSVC)向けのバイナリをダウンロードしてください。
vs2013を使っている場合は http://targonski.nazwa.pl/thedmd/allegro の5.0.10にMSVC12向けのがあります。
Mac OS Xは実行環境がないので何とも言えないのですが、 Homebrewのhomebrew-versionsというリポジトリにallegro 5があります。 headオプションでgit版も選べるようですが、現時点のデフォルトはなぜか ひとつ古いバージョン(5.0.9)のようです。
iOSやAndroid、Raspberry Piで使う場合は開発版をソースからビルドする必要があります。
より一般的なビルド情報はallegro 5の各プラットフォームのREADMEとAllegro 5のWikiを参照してください。
ビルド
mrubyのbuild_config.rbのビルド設定ブロックに mruby-minigameのgithubリポジトリを追加してください。
conf.gem :github => 'bggd/mruby-minigame'
Windowsではさらにダウンロードしたallegro 5の includeとlibフォルダへのパスを設定してください。
conf.cc.include_paths << 'allegro 5 のincludeフォルダ'
conf.linker.library_paths << 'allegro 5 のlibフォルダ'
Linux以外のOSの場合はリンカにライブラリを設定してください。 (次のサンプルはLinux向けのものです)
conf.linker.libraries << %w(allegro allegro_main allegro_color allegro_image allegro_primitives allegro_font allegro_ttf allegro_audio allegro_acodec)
OS XならもしかしたらこれでOKかもしれませんがWindowsでは 例えば、allegro_color-5.0.10-mdのように ライブラリのバージョンやビルド構成を元にポストフィックスを 指定しなればなりません。 書くのが面倒な時は、allegro 5の各モジュールとアドオンが ひとつになったmonolithを指定するのがおすすめです。
conf.linker.libraries << %w(allegro-5.0.10-monolith-md)
Windowsの場合はmrubyのbinフォルダにallegro 5のDLLを置くのを忘れずに。
mrubyのVisual Studioでのビルドはデフォルトでデバッグビルド(/Od + /RTC1)になっているので 遅いです。最適化などを有効化しましょう。
mruby-minigameの機能と使い方
今のところ、このようなモジュール構成です。 詳細はWikiのAPIの項目 を参照してください。
- Minigame::Color - 色の指定。RGBとHSVの表色系に対応
- Minigame::Display - 画面の生成、背面描画・更新
- Minigame::Image - 画像の読み込み、描画
- Minigame::Graphics - 図形の描画。線と矩形、円に対応
- Minigame::Font - TTFフォントの読み込み、描画
- Minigame::Gameloop - ゲームループ関連
- Minigame::Mouse - マウスの座標とボタンの状態の取得
- Minigame::Key - キーボードの状態取得
- Minigame::Audio
- Minigame::Music - 音声のストリーム再生
-
Minigame::Sound - 効果音の再生
- Minigame::Event - Gameloopの実装につかっているので基本的には非推奨
今回はゲームループとキーボードとマウスの入力、Imageクラスの扱い方等を かいつまんで紹介します。
ゲームループ
ビデオゲームはプレイヤーからの入力や時間変化とともに ゲームの世界をどんどん変化させる必要があり、 その一連のサイクルをゲームループと呼びます。
とりあえず雰囲気をわかってもらうために 以下のサンプルコードをみてください。
include Minigame
Display.create(640, 480)
Gameloop.draw do
Gameloop.quit if Key.down(Key::ESCAPE)
Display.clear
end
Gameloop.run
Display.createで640x480の画面を作り、 Gameloop.drawへ渡したブロックがGameloop.runから毎フレーム呼び出されます。 ブロック内はエスケープキーが押されたらゲームループを終了し、 そうでないなら画面をクリアし続けるという内容です。
Gameloop.drawはゲームループ中の描画のタイミングで呼び出されますが 他にもプレイヤーからの入力があった時に呼ばれるkey_pressedやmouse_pressed などがあります。
注意点としては、ブロックを渡しているのでreturnしたい場面ではnextを使います。
キーボードとマウス
キーボードとマウスの状態はGameloopモジュールと Key、Mouseモジュールから取得できます。 まずGameloopモジュールのほうから説明します。
Gameloopにはキーが押された時に呼ばれるkey_pressedと キーが離された時のkey_releasedがあります。
ブロックの引数にKeyの定数が渡されます。定数一覧
Gameloop.key_pressed do |key|
if key == Key::ESCAPE
Gameloop.quit
end
end
mouse_pressedとmouse_releasedではマウスのボタンが下がった時と 上がった時にそれぞれ呼び出されます。
ブロックの引数にはマウスの座標と、状態に変化のあったボタンが渡されます。 ボタンは:left, :middle, :rightのいずれかのシンボルです。
Gameloop.mouse_pressed do |x, y, button|
if button == :left
p [x, y]
end
end
次にKey、Mouseモジュールを説明します。
Keyにはキーが押されているか確認するKey.down。 そのフレーム時に押されたか確認するKey.pressed、離されたか確認するKey.released があります。
Mouseには現在の座標を得るMouse.xとMouse.yのモジュール変数があり、 Keyと同様にMouse.downとMouse.pressed、Mouse.releasedがあります。
Image
画像の読み込みや表示をするのがImageクラスです。
さっそくサンプルコードをみてください。
include Minigame
Display.create(640, 480)
img = Image.load("hero.png")
Gameloop.draw do
Display.clear
img.draw(Mouse.x, Mouse.y)
end
Gameloop.run
Image.loadで指定した画像を読み込み、 毎フレームImage#drawでマウスの座標に画像を表示します。
Image.loadは画像を読み込めなかった時はnilを返します。 mruby-minigameではFontやMusicクラスも同様に読み込めなかった時はnilを返す方針です(例外の方がいいかな?)。
Image#drawはオプションで以下のキーワード引数を受け付けます。
- angle - 回転を0〜360度で指定 (デフォルトは0)
- color - 色合いをColorオブジェクトで指定 (Color.rgb())
- scale - X軸とY軸の拡大率を配列で指定 ([1.0, 1.0])
- anchor - 各軸のアンカーを指定 ([0.0, 0.0])
- pivot - 各軸のピボットを指定 ([0.5, 0.5])
- flip - 各軸の反転の有無を指定 ([false, false])
アンカーは画像をどの位置を起点に表示するかを示します。 Image#draw(x, y)では画像の左端を起点に描画しますが Image#draw(x, y, anchor:[0.5, 0.5])では画像の中央を起点に表示します。
ピボットはどの位置を起点に回転をするか示します。 Flash向けのゲームエンジン、Starling Frameworkの Wikiの 画像がわかりやすいので引用します。
アンカーとピボットは[0.0, 0.0]が左上[0.5, 0.5]が真ん中、[1.0, 1.0]が右下になります。
Image.newで新規に画像を生成することも可能です。
例えば、白い32x32サイズの画像を生成するには:
img = Image.new(32, 32)
赤い画像を生成するには:
img = Image.new(32, 32, Color.rgb(255, 0, 0))
これをそのまま矩形の描画として使うこともできますが、 Image.targetに画像を渡すとそのうえに描画をすることもできます。
img = Image.new(32, 32)
Image.target(img) do
# img画像の上に描画をできる
Graphics.circle(img.w/2, img.h/2, 16, color:Color.rgb(0, 0, 255))
end
Image#sub_imageは元の画像のメモリを共有したまま、その画像全体または 一部を表示するオブジェクトを生成します。
img = Image.load("tile_sheet.png")
block_tile = img.sub_image(64, 64, 32, 32)
元の画像がGCされると二度と表示できないので注意してください。
Image.hold_drawingで同じ画像を効率良く描画することができます。
include Minigame
Display.create(640, 480)
img = Image.load("hero.png")
positions = Array.new(100) { [rand(Display.w), rand(Display.h)] }
Gameloop.draw do
Display.clear
Image.hold_drawing(true)
positions.each { |pos|
img.draw(pos[0], pos[1])
}
Image.hold_drawing(false)
end
Gameloop.run
hold_drawingで囲っている間は描画順などが担保されないので注意が必要です。
これはallegro 5の機能をそのまま使っているのですが、 同じ画像の座標や色、回転等の情報をキャッシュして内部的な(OpenGL/Direct3Dの)DrawCallを減らすものです。たぶん。
音量
mruby-minigameの音声モジュールは主にBGM向けのMusicクラスと 効果音向けのSoundクラスにわけられます。
Audio.volumeをマスターボリュームとしてMusic.volume, Sound.volumeと その各インスタンスが音量の影響を受けます。
- Music.volume - Music#volume / - Music#volume Audio.volume - \ - Sound.volume - Sound#volume - Sound#volume
音量は0から100で表します。 Audio.volumeを100から50にした場合、全体の音量が下がります。 BGMの音量だけ下げたい時はMusic.volumeの値を下げます。
経過時間と休止
Minigame.get_timeで経過時間を取得します。
Minigame.restに指定した秒数のあいだ休止します。
1秒は1.0です。
終わりに
ざっと紹介しましたが、よりくわしい情報はWikiを参照してください。 exampleも増やしていく予定です。
コアな部分はバックエンドにつかっている allegro 5の薄いラッパー程度で、より高機能な部分は mruby-minigame-extとして追加できたらいいなと思います。
あったらいいなリスト:
- 素材の非同期読み込み
- 衝突判定
- Pygame風のSpriteとGroup(継承によるゲームオブジェクトの表現とその管理)
- IMGUI
- シーン管理
やる気駆動開発なのでいつ実装できるかまったくわからないのと 技術力的にきびしい部分(特に衝突判定)もあるので mruby-minigameと連携できそうなライブラリ作ったぜという方は ぜひissue等で報告してもらえればWikiにリンクを追加したいです。