マップのスクロール

そういえばDXRubyの掲示板でスクロールのサンプルを作るという話を2度ほどしたうえに放置してたなーと思ってちょっと手をつける。
ついでにマップデータを外部データファイル化して読むようにしておいた。サンプルというにはアレなぐらい簡単なものではあるが、あとで簡単なマップエディタで読み書きできるようにでもしておけばなんとなくそれっぽい雰囲気にはなるだろう。マップエディタをDXRubyWS使って作るとかすると少しインパクトはあるかもしれん。
シンプルなMapクラスとして実装して、描画先はnewの引数で指定する。Map#drawの引数はマップ内の座標で、(newで指定されたもので省略時はWindow).draw_tileを発行するが、その引数としての描画サイズは描画先と画像サイズから自動計算するようにしてみた。実際のところ、画像をいくつ並べるかというのはコードを書く側からするとあまり意味の無い情報で、描画したいピクセル数を渡すようにして、はみ出した部分はカットされるように作ったほうがよかったと思うわけなのだが、豪快な仕様変更になってしまうので修正するのも難しい。draw_tile_exとか言って追加しようかしらん。どのへんがexなのかはナゾだが。それかレシーバ内にいっぱいに描画するようにしちゃうか。そっちのほうがいいか?
とりあえずできたのはここまで。
コードはこれ

require 'dxruby'

# マップ
class Map
  attr_accessor :mapdata

  # targetは描画先のRenderTarget/Window
  def initialize(filename, mapimage, target=Window)
    @mapimage, @target = mapimage, target
    @mapdata = []
    File.open(filename, "rt") do |fh|
      lines = fh.readlines
      lines.each do |line|
        ary = []
        line.chomp.each_char do |o|
          if o != "x"
            ary << o.to_i
          else
            ary << nil
          end
        end
        @mapdata << ary
      end
    end
  end

  # x/yはマップ内の左上の座標(ピクセル表現)
  # 描画サイズは描画先(initializeのtarget)により自動的に調整される
  def draw(x, y)
    image = @mapimage[0]
    @target.draw_tile(0, 0, @mapdata, @mapimage, x, y,
                      (@target.width + image.width - 1) / image.width,
                      (@target.height + image.height - 1) / image.height)
  end
end

if __FILE__ == $0
  mapimage = []
  mapimage.push(Image.new(32, 32, [100, 100, 200])) # 海
  mapimage.push(Image.new(32, 32, [50, 200, 50]))   # 平地
  mapimage.push(Image.new(32, 32, [50, 200, 50]).   # 木の根元
                          box_fill(13, 0, 18, 28, [200, 50, 50]))
  mapimage.push(Image.new(32, 32, [50, 200, 50]).   # 山
                          triangle_fill(15, 0, 0, 31, 31, 31, [200, 100,100]))
  mapimage.push(Image.new(32, 32).  # 木のあたま。背景は透明色にしておく。
                          box_fill(13, 16, 18, 31, [200, 50, 50]).
                          circle_fill(16, 10, 8, [0, 255, 0]))

  rt = RenderTarget.new(560,400)
  map1 = Map.new("map1.dat", mapimage, rt)
  map2 = Map.new("map2.dat", mapimage, rt)
  x = 0
  y = 0
  Window.loop do
    map1.draw(x, y)
    map2.draw(x, y)
    Window.draw(40, 40, rt)
    x += 1
    y += 1
    break if Input.keyPush?(K_ESCAPE)
  end
end

これがmap1.datで

11111111121111111113311111111111
11111111111111111333331111112111
12111111111111111113333111211111
11111111111111112111333111111121
11111111111111111111113311111111
11111110000000111111111311111111
11111100000000001111111131111111
11111000333000001111112111111311
11120003333200000111111111111311
11120000333220000111111111111311
11220000011220000111111111113111
11220000001220000111111311113111
11222000000000001111111331133111
11112220000000000111111133331111
11111222100000000011111133331111
11211112211000111001111133331111
11111111221111111100111333331111
11111111111111111110111333311111
11111111111222111111013333311111
11111111111112221111303333111111
11111111111111111111303331111111
11121111111111111113303331111111
11111111333331111333033331111121
11111111113333333331233311111222
11111111111113333333331111122222
11111111211111133333311111222222
11111111111111111333111111222221
11111211111111111111111111122211
11111111111111111111112111111111
11111111111121111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111

こっちがmap2.dat

xxxxxxxxxxxxxxxxxxxxxxxxxxxx4xxx
x4xxxxxxxxxxxxxxxxxxxxxxxx4xxxxx
xxxxxxxxxxxxxxxx4xxxxxxxxxxxxx4x
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxx4xxxxxxxxx
xxx4xxxxxxx4xxxxxxxxxxxxxxxxxxxx
xxx4xxxxxxx44xxxxxxxxxxxxxxxxxxx
xx44xxxxxxx44xxxxxxxxxxxxxxxxxxx
xx44xxxxxxx44xxxxxxxxxxxxxxxxxxx
xx444xxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxx444xxxxxxxxxxxxxxxxxxxxxxxxx
xxxxx444xxxxxxxxxxxxxxxxxxxxxxxx
xx4xxxx44xxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxx44xxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxx444xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxx444xxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxx4xxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx4x
xxxxxxxxxxxxxxxxxxxx4xxxxxxxx444
xxxxxxxxxxxxxxxxxxxxxxxxxxx44444
xxxxxxxx4xxxxxxxxxxxxxxxxx444444
xxxxxxxxxxxxxxxxxxxxxxxxxx44444x
xxxxx4xxxxxxxxxxxxxxxxxxxxx444xx
xxxxxxxxxxxxxxxxxxxxxx4xxxxxxxxx
xxxxxxxxxxxx4xxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxx4xxxxxxxxxxxxxxxxxxxxxx