サイログ。

~雑多な記事置き場~

DXRubyの人の日記を読んでBitmapの扱いを修正

さて、最近、id:mirichiさんのDXRubyというライブラリが非常に気になっています。

Wikiは↓
http://sourceforge.jp/projects/dxruby/wiki/FrontPage

RubyDirectXを操作して、高速に動作させるライブラリ、実は「やりたいやりたい」と言っていてできなかったのがDirectXRubyとの連携。しばらくみないうちにかなりすごくなってました・・・OTL DXRuby上で動くMiyakoを作りたくなってきた(オイ)

さて、そのid:mirichiさんの日記で、各ライブラリの画像の扱いについて語っておられます。いろいろ参考になりました。ありがとうございます。

http://d.hatena.ne.jp/mirichi/20090415

そのとき、以下の文章を読んでいて、ふと思ったことが2つありました。以下引用。

MiyakoのSpriteオブジェクトは、画像情報を持つスプライト機能クラスで、画面に表示されるモノ1つについて、オブジェクトが1つ必要になる。

Ruby/SDLはVRAMにデータをベタに転送するイメージで、StarRubyはそれをラッピングして簡単にした感じだ。

DXRubyは、内部実装と概念は全然違うだろうが、使い方としてはStarRubyが一番近い。

(「mirichiの日記」より)

1つ目

文面と直接関係ないのですが、Miyakoでの画像管理は、Spriteオブジェクト一つにつき、画像(SDL::Surface)オブジェクトを一つ持っています。
実装上はそうなっているのですが、僕が考えていた仕様と違うことに気づきました。

僕が考えていた仕様では、Sprite.newメソッドの引数に:bitmap=>で示したオブジェクトを渡すと、そのオブジェクトそのものを持つように考えていました。ところが、上記の文面を読んだ後、ふと思ってSprite.newのソースを見てみたら、内部でSDL::Surface#display_format_alphaが呼ばれているので、内部では、元の画像の複製を持っていることになります。

たくさんのスプライトを用意するゲームやったら、メモリがもったいなさ過ぎる。対策せんと・・・。

というわけで、display_format_alphaの呼び出しを、Sprite.newではなくてBitmap.createもしくはBitmap.loadに変更いたしました。
Sprite#newで複製しなくなったので、スプライトを生成するときに、同じ画像を共用できるようになります。

サンプルスクリプトを載せておきます。現状の2.1ではまだ機能いたしません(今後アップするバージョンで対応)。
画像が2つ出てきますが、bitmapは共用していますので、どちらかのスプライトに手を加えると、両方のスプライトに影響が出てきます。

require 'Miyako/miyako'

bitmap = Miyako::Bitmap.load("hoge")

spr1 = Miyako::Sprite.new(:bitmap=>bitmap)
spr2 = Miyako::Sprite.new(:bitmap=>bitmap)
spr1.left!.top!
spr2.right!.bottom!

loop do
  Miyako::Input.update
  
  break if Miyako::Input.pushed_any?(:spc)
  
  Miyako::Screen.clear
  
  spr1.render
  spr2.render
  
  Miyako::Screen.render
end

Miyako::Drawing.line(spr1, [0,0,*spr1.size], [0,0,0])

loop do
  Miyako::Input.update
  
  break if Miyako::Input.pushed_any?(:spc)
  
  Miyako::Screen.clear
  
  spr1.render
  spr2.render
  
  Miyako::Screen.render
end

これに加えて、これまで非公開だったBitmap.createとBitmap.loadを公開メソッドといたしました。

2つ目

あと、2つめは細かい話なのですが、仕様上の話で、

Miyako2.0以降では、「Spriteオブジェクト1つ≠画像に表示されるもの1つ」です

Miyako2.0以降の描画は、Miyako1.xとStarRubyとの中間の使い方になっています(move!メソッドなどで位置を変えて、引数なしのrenderで描画)。
ただし、基本的には画面更新1回ごとにrenderメソッドを1回呼び出すだけですので、
僕も、リンク先で紹介されているWikiをいじっているのですが、まだMiyako1.x時代の内容が多いので(というか、誤解を与えてるな)修正しないといけないな・・・。

ついでに、サンプルを載せておきます。画像が円状に並びます。

require 'Miyako/miyako'

spr1 = Miyako::Sprite.new(:file=>"hoge")
spr1.centering!

r  = 100
times = 20
radians = Array.new(times){|i| i.to_f * 2.0 * Math::PI / times.to_f }

loop do
  Miyako::Input.update
  
  break if Miyako::Input.quit_or_escape?
  
  Miyako::Screen.clear
  
  radians.each{|rad| spr1.move!(r * Math.cos(rad), r * Math.sin(rad)){ spr1.render; nil } }
  
  Miyako::Screen.render
end