Ruby 向けゲーム GUI フレームワーク "quincite" の紹介

この記事は[ゲームエンジン・ライブラリ・ツールの開発 Advent Calendar 2016](http://qiita.com/advent-calendar/2016/gameengine) の 6 日目の記事です。

# quincite

- [aoitaku/quincite - github](https://github.com/aoitaku/quincite)

クインサイトと読みます。ゲームで手軽に GUI を記述することを目的にしています。

quincite 自体は GUI コンポーネントのツリー構造を構築するだけで、描画とかはしません。実際に GUI のコンポーネントを画面に表示するためには、たとえば [DXRuby](http://dxruby.osdn.jp/) や [Gosu](https://www.libgosu.org/) を使って、それぞれ描画処理を実装する必要があります。

DXRuby 用の実装には [dxruby_sprite_ui](https://github.com/aoitaku/dxruby_sprite_ui) があって、Gosu 用の実装には [gestalt_ui](https://github.com/aoitaku/gestalt_ui) というものが予定されています。Gosu 版のほうはまだ試作段階で gem 化できていませんが、ゆくゆくは gem にして bundler でインストールできるようになる予定です。

# どうして Ruby ？

ぼくにとって書いてて楽しいのが Ruby だったというのが一番の理由です。  
それはそれとして、ちょっと思いついたアイデアをすぐに動かして試せる環境がほしいと思ったことはありませんか。ぼくはあります。  
紙の上にゲーム画面を書いて、この画面でこうやったら次はこうなって、みたいなの考えるのはとても楽しいです。  
さて、このアイデアをもとにさくっとプロトタイプを作りたいと考えます。  
Ruby だと思いついたことをすぐにコードに起こせます。思いつきドリブンでゲーム作るのにもってこいの言語だと思っています。

# ゲームの GUI を作るのはめちゃ大変

ゲームの GUI というのは、思ってるよりかなり労力を要求されます。タイトル画面ひとつ作るだけでもけっこうな手間です。  
そのへんよろしくやってくれるライブラリが、Ruby にはありません。そもそも Ruby でゲームを作るということがニッチなのでそれはしょうがない。  
でも、さくっとゲーム書きたいのに、GUI ベースのゲーム作るのが大変なのでは困ります。

そういう自分の中での要請が背景にあって、quincite が作られました。

# quincite の使い方

[quincite の wiki](https://github.com/aoitaku/quincite/wiki) から抜粋すると、

```ruby
require 'quincite'
include Quincite

class Node
  include UI::Component
  def initialize(id)
    init_component
    self.id = id
  end
end

class Nodeset < Node
  include UI::Container
  def initialize
    super
    init_container
  end
end

ui = UI.build(UI::Nodeset) do
  Node {
    x 0
    y 0
  }
end
ui.layout
```

こういうコードで、シンプルなコンポーネントツリーを構築できます。  
`Quincite::UI::Component` モジュールをインクルードしたらそれが quincite のコンポーネントになって、さらに `Quincite::UI::Container` モジュールをインクルードしたら子コンポーネントを持つことができるようになります（コンテナとコンポーネントを同時にインクルードすることを想定しています）。

`UI.build` メソッドに渡したブロックをビルダー DSL と呼んでいて、このブロックの中でコンポーネントツリーを宣言的に記述できるようになっています。例のコードでは `Node` を `(0, 0)` に配置するだけになっています。

これはコンポーネントツリーを構築するだけしかしないので、実際にゲーム画面に出すには任意のライブラリを使った描画メソッドを実装する必要があります。

# DXRuby で quincite を使う

Ruby でゲームを作るためのライブラリに DXRuby というものがあるのでこれを使って quincite の GUI を実際に画面に出すのをやってみます。

quincite 上に DXRuby 用のコンポーネント定義を書くサンプルでもよいのですが、DXRuby にはすでに dxruby_sprite_ui というライブラリがあるので、これを使います。

# dxruby_sprite_ui

描画やクリック判定に `DXRuby::Sprite` を使っているので dxruby_sprite_uiという名前になっています。`DXRuby` モジュールの下に追加されるので DXRuby から使うときはそのまま `SpriteUI` と書けば使えます。


クリックすると内容が変わるボタンのデモです。

```ruby
require 'dxruby'
require 'dxruby_sprite_ui'

SpriteUI.equip :MouseEventHandler

ui = SpriteUI::build {
  TextButton {
    text 'Hello, world!'
    hello = true
    onclick -> target {
      target.text = hello ? 'Goodbye, world...' : 'Hello again, world!'
      hello = !hello
      ui.layout
    }
  }
}
ui.layout

mouse_event_dispatcher = SpriteUI::MouseEventDispatcher.new(ui)

Window.loop do
  mouse_event_dispatcher.update
  mouse_event_dispatcher.dispatch
  ui.draw
end
```

こんな感じで、DSL でコンポーネントツリーを作って、イベントハンドラを書くだけで、クリックで何かする GUI が作れます。簡単。

# quincite がやっていること

描画やクリック判定以外のことはだいたい quincite がやっています。  
たとえばクリックイベントの発火は dxruby_sprite_ui で実装していますが、イベントの伝達とイベントハンドラの呼び出しは quincite 側で実装されています。  
上の例にない機能だと自動レイアウトがあって、コンポーネントを絶対座標で指定しなくても他のコンポーネントとの位置関係からよろしく自動配置できるようになっています。  
ちょっとサンプルのコードが大きいのでリンクだけ貼っておきます。

- [example/layout](https://github.com/aoitaku/dxruby_sprite_ui/blob/master/example/layout.rb)

# 課題

- リンク先のコードを見てもらえればわかりますが `margin` や `padding` を都度指定しないといけなくてぜんぜん DRY ではないので同じようなスタイルを使いまわせるようにしたいということを考えています。
- リファレンスがないので使い方がぜんぜんわからないことに定評があります。
- ビルダー DSL はでかくなりがちなので外部ファイルに吐き出せるようにしたい気持ちが大きい。
- ビルダー DSL のエラーがわかりにくいのでなんとかしたい気持ちが大きい。
- 動的にコンポーネントを生やす仕組みが弱いので同じような要素の繰り返しなどは力技でコードを書く必要があります。
- キーイベント処理はいまのところ対応できていません。

まだまだ若いライブラリなのでこれからだと思っています。

# dxruby_sprite_ui を使ったゲームのサンプル

「野メイド」という育成 SLG っぽいデモゲームを作ったのでそちらをご覧ください。

- [野メイドを作った話](http://blog.aotak.me/post/135507049836/)
- [野メイドを改造した話](http://blog.aotak.me/post/135711033867/)

# おわりに

Ruby でゲームを作るための GUI ライブラリを紹介させていただきました。いまのところ使っているのが自分だけしかいないという状況なんですが、今後リファレンスとサンプルコードを充実させていこうと思っているのでどんどん使ってみてほしいと思う次第です。