#DXRuby機能リクエスト
DXRuby Advent Calendar 2014、4日目は「しのかろ」が記事をお送りします。
今回はDXRubyへの機能リクエストです。機能リクエストを記事としたのはTwitterでは文字数の制限がありますし、掲示板では複数の話題を同時に扱いづらいためです。
##前日の記事について
前日の記事はmieki256さんの「DXRubyとスプライトエディタ」でした。スライドショーによるプレゼンテーションなど記事としての充実度も素晴らしいものでした。内容はボーン式の2Dアニメーションの実装です。
私が製作しているゲームエンジンはADV形式を前提としていました。ですから表情差分などは本当の差分とせず全身入り画像で処理する方向です。理由としてはキャラクターの立ち絵の場合、この方がイラストレーターが作業しやすくデーター納品も簡単だからです。
しかし、記事にあったボーン式アニメーションを見て「これもあり」と考え直しました。これならばパーツデータの使い回しが可能ですし、アニメーター側の作業で演出を入れることができます。
動作が遅いとありましたが、もし高速化するならばパターン・データーを並べた1枚絵を作り、そこからHLSLで切り出して配置指示を引数で与え、表示する方法になるでしょう。C++で書かれたゲームでも高速化するならばこうします。実装をオブジェクトで隠蔽すればアニメーター側の負担も変わりません。
フレーム数と実時間の誤差についても言及されていました。IntegerクラスかTimeクラスを継承したFrameTimeクラスを作成する必要があるかもしれません。プログラム処理は人間世界で使われている単位のサポートが弱いと思います。人間同士の間ではインチはインチ、メーターはメーターです!
##DXRubyに何をリクエストするのか?
Rubyはオープン・クラスですから、Ruby側で実装できる機能は自分で書いてしまえばいいのです。それに、Rubyでは遅い、という状況もなくなりつつあります。一方、Rubyでは決して書くことのできない機能は拡張ライブラリー作成者にリクエストするしかありません。
たとえば、拡張ライブラリーが確保したメモリー領域の情報が必要なもの、DirectXの機能を呼び出すもの、拡張ライブラリーのオブジェクト側のコード内で一括処理する以外の手段がないもの、などです。
###DXRuby::Windowモジュール
####to_imageメソッド、またはto_render_targetメソッド
スクリーンショットをImageオブジェクトまたはRenderTargetオブジェクトとして取得するメソッドです。
Window.get_screen_shot
メソッドはありますが、これはファイルとして保存されます。もしImageオブジェクトとしてウィンドウの内容が取得できるのであれば、そのImageオブジェクトをプログラムから再利用できます。
再利用の仕方? ゲームのためのライブラリーなのですからゲームの演出に使えばいいんです。ほら、ボス・ステージの背景に巨大スクリーンがあってプレーヤーとの戦いが映されている、アレですよ!
####created?メソッド
ウィンドウが生成されたどうかを確認するメソッドです。ゲームエンジンを自作していてメインループを書くときに必要になります。ループメソッドが呼び出されたときにウィンドウ生成を飛ばすか、含めるかの分岐に使います。
close
, closed?
メソッドも欲しかったのですが、こちらはmirichiの日記:Window.loopを複数置くによるとDXRuby1.4.2で追加されるようです。
####ウィンドウのアイコン化
ゲームのデバッグ中にアイコン化できると便利です。
あと、アイコン化しているかどうかの状態取得メソッドもセットになります。
ゲーム完成版の観点からは必要ないかもしれない……。
####ティアリング防止
ティアリングとは画面表示時に描画が見えてしまう現象のことです。人間には画面がちらついているように感じられます。
大きいサイズの画像を使用するとティアリングがあるようです。ティアリング発生を確定させるところまでテストできてはいません。
フレーム更新のたびに画面の内容がリセットされるのでダブルバッファーが標準実装と思い込んでいましたが、実際はどうなんでしょうか。
もし可能であればダブルバッファー標準実装を希望します。
####before_call, after_call
利用側がコンテナーを用意し、それをbefore_call=
, after_call=
メソッドでセットする。Window側は与えられたコンテナーのeach
メソッドを呼び出しブロック内で取得したオブジェクトのcall
メソッドを呼び出す。という実装はどうでしょうか?
###DXRuby::Imageクラス
####ピクセル全体に対するイテレーター
Image#[x, y]
メソッドを使えば、指定した位置のピクセル情報が取得できます。これで、画像を調査するコードを書いたことがあります。このメソッドを用意していることに感謝しています。
と、なると当然、画像を左上から右下まで順に読み取るeach
メソッド(さらに現在のx, y座標がブロックに与えられるとなおよし)に期待したくなります。なぜなら、このままだと同じことをするのに二重ループを書くことになりますから。
しかし、リクエストしたeach
メソッドと同等の機能をRubyで書くことはできます。そこで、気なるのはC拡張側で画像を走査したほうが速いのか? という事です。1ピクセルごとにRuby側のコード(与えたブロック)が呼び出されることには変わりはありません。実行速度が変わらないのであればRuby側で実装してもいいような気もします。
####ピクセル領域指定イテレーター
ピクセル全体を走査できるeachがあるなら、指定した四角領域を走査するeach
があるのでは? というものです。
もっとも、これは不要ですね。なぜなら、元になるImageから関心のある四角領域をImage#copy_rect
で取り出せばよいのです。そうした方がシンプルで理解しやすいでしょう。
####領域指定による新Imageオブジェクトを生成するメソッド
Image#copy_rect
は自分自身に相手の一部分をコピーするメソッドです。
リクエストしているのは自分自身の一部を新しいImageオブジェクトとして取り出すメソッドです。
これもRuby側で実装しようと思えば可能でした。DXRubyのImageクラスはとても良くできているものですね。
####bgcolor, bgcolor=メソッドで背景色を指定する
というリクエストを考えたのですが、これがないのには理由があるんです。
WindowとRenderTargetには同名のメソッドがあります。なぜならフレーム更新ごとに画像データが消去されるからです。このため、消去時の塗りつぶし色が必要なのです。
Imageオブジェクトはフレームが更新されても画像データは消えません。ですから塗りつぶし色の保持など必要ないのです。
もしも画像前面を塗りつぶしたければfill
メソッドを使用します。それから、マスク抜きされた画像に背景色を付けたければ、背景色で塗りつぶした同サイズの画像の上に対象の画像を転写すれば完成します。
DXRuby::Imageには隙がなさそうです。
###DXRuby::RenderTargetクラス
####フレーム更新ごとに消去されないようにしたい
つまりビデオ・メモリー側に画像を送っておいて素材として使いまわしたい、ということです。
この辺りはDirectXの知識が不足していて、不適切な事を言っているかもしれません。
RendeTargetオブジェクトのサーフェイスがビデオ・メモリー側に物理的に保持されているかどうかも私には分かっていません。
###DXRuby::Spriteクラス
####target=にImageオブジェクトを指定可能にする
現在はSprite#target=
にImageオブジェクトを与えても、描画の時点でエラーとなります。
できそうな気がする、という程度のリクエストです。
####drawメソッドが逆方向に機能している
draw
メソッドはWindow, Image, RenderTarget, Spriteの4つにあります。最初の3つのdraw
メソッドは自分自身へ描画する機能ですが、Spriteのdraw
メソッドは自分自身を描画する機能です。つまり描画する対象が違っています。
これはダックタイピングするときに問題となります。
###DXRuby::Fontクラス
Fontに関してはリクエストではなく賞賛です。
一つあげるならばDXRuby1.4.1で追加されたFont.defaultです。これは、定数にはできない定数のようなもの、の実装としても優れています。Fontオブジェクトを必要とする引数項目に不十分なサポート(例:引数にnilを与えた場合は固定されたフォントといった挙動)を入れない点でもよいですね。
もしリクエストがあるとするならば今以上にFont情報を取得したいというのがあります。
日本語の表示はシナリオライターさんのこだわり所です。ゲームエンジンを作る側としてもサポートできる範囲で作りこみたいと考えます。日本語のレイアウトはアルファベットより難しく多くのパラメーターを必要とします。
もっともこれをDXRubyが行うべきかは考えるところです。RubyGemを探してTTFの情報を取得するGemを使ったほうがいいかもしれません。
とはいえDXRuby::Fontは多くのフォント情報とパラメーター設定項目があります。draw_font_exのオプションも充実しています。既存のゲームが要求する範囲はすべてクリアーしているでしょう。
###DXRuby::Soundクラス
####読み込みが遅い
これはDirectXが原因なんでしょうか?
そう考えたのは、C++で作成されたゲームでもステージ開始前のローディング時間が長いからです。
今のままではBGMは他の音楽再生ライブラリーをつかうとしても、SEの読み込みのためゲームの流れが中断することになります。ローディング時間が長いとゲームのデバッグにも支障がでます。
可能であればWAV読み込みの高速化をお願いします。
###Rubyスレッド対応
これはDXRuby1.5.1devでは対応していますね(mirichiの日記:メッセージループの別スレッド化)。
さて、スレッドに対応するとRuby標準添付のTkライブラリーが動くようになります。そうすればゲームのエディットにGUIが使えるようになりますね。それが目的です。
どうか安定板でのスレッド対応をお願いします。
##おわり
以上、しのかろによるDXRuby機能リクエストでした。
DXRubyは高度にRuby化されている拡張ライブラリーです。具体的にいえば、完全にGCに対応しており、データや機能はクラスやモジュールとして設計されています。その上、2Dのコンセプトという範囲でOSに密着したDirectXを可能な限り使用する仕組みです。
サーフェイスの開放タイミングなんかはプロトタイプ作成の時点では決定なんかできません。そして完成した後もです。最初からGCに対応しているDXRubyは、とても優れたライブラリーの範疇に入ると考えています。
明日はDXRubyの生みの親、mirichiさんによる「マイナーな機能を取り上げて解説するコーナー」です。お楽しみに!