DXRubyWSを使ったマップエディタ
シンプルなもので使い勝手はよくないが。
開発中のDXRubyWSのサンプルとして作ってみたところ。
https://github.com/mirichi/DXRubyWS
サンプルSTGがひとつのウィンドウの中に描画されていて、そのマップ情報を別のウィンドウで書き換えることができる。これはコード的にはクラス単位で分離させてはいるが、単一のVMインスタンスで動かしているから自由にアクセスできるという話で、逆にどれかがエラーでコケたら全部まるごとコケるというなんだかWindows3.1のような問題も発生する。
DXRubyWSで作ったウィンドウは毎フレームupdateが呼ばれるが、それを使わずシステムから呼ばれるマウスイベントや、そこから発生するシグナルに対する処理だけ書くことで、Window.loopで作るアクションゲームっぽくないイベントドリブンのコードを書くことができる。
このサンプルはSTGサンプルに組み込んだのでメインはSTGコードになっていて、描画先をウィンドウのクライアント領域に差し替えているだけである。マップ編集関連は新たにウィンドウのクラスを作って定義してあるから、ゲームとは切り離したコードでエディタ部分を構築できる。
コードはこんな感じに。
# ウィンドウシステム用クラス定義 module WS # ゲームのメインウィンドウ class GameWindow < WSWindow def draw self.client.image.draw(-$myship.x/5,0,$rt) super end end # マップ編集ウィンドウ class MapEditWindow < WSWindow def initialize(*args) super @mapdata = Map.class_variable_get(:@@map) @images = Map.class_variable_get(:@@images) @position = 0 # 描画の基点 # スクロールバー sb = WSScrollBar.new(508, 0, 16, 700-16) client.add_control(sb, :sb) sb.total = 30 # 全体サイズが30 sb.unit_quantity = 1 # ボタンを押したときに1動く sb.screen_length = client.height.quo(32) # 表示される範囲 sb.add_handler(:slide) {|obj, pos| @position = pos} # マップの画像 wsimage = WSImage.new(0, 0, 512, 480) wsimage.image = RenderTarget.new(512, 480) client.add_control(wsimage, :wsimage) wsimage.add_handler(:resize) do wsimage.image.resize(wsimage.width, wsimage.height) sb.screen_length = client.height.quo(32) end # オートレイアウト layout(:hbox) do add wsimage, true, true add sb, false, true end # クリック時の編集 wsimage.add_handler(:mouse_down) do |obj, tx, ty| @lbutton = true @mapdata[(ty + @position * 32) / 32][tx / 32] = WS.desktop.mappartswindow.select_number end wsimage.add_handler(:mouse_up) do @lbutton = false end wsimage.add_handler(:mouse_move) do |obj, tx, ty| @mapdata[(ty + @position * 32) / 32][tx / 32] = WS.desktop.mappartswindow.select_number if @lbutton end end def draw # マップ描画 client.wsimage.image.draw_tile(0, 0, @mapdata, @images, 0, @position*32, 16, 30) # 描画枠の描画 x1 = $myship.x / 5 x2 = x1 + 360-1 y1 = ($map.y + $map.count ) % 960 - @position * 32 y2 = ($map.y + $map.count + 480) % 960 - @position * 32 client.wsimage.image.draw_line(x1, y1, x2, y1, C_YELLOW) client.wsimage.image.draw_line(x1, y2, x2, y2, C_YELLOW) if y1 < y2 client.wsimage.image.draw_line(x1, y1, x1, y2, C_YELLOW) client.wsimage.image.draw_line(x2, y1, x2, y2, C_YELLOW) else client.wsimage.image.draw_line(x1, 0, x1, y2, C_YELLOW) client.wsimage.image.draw_line(x2, 0, x2, y2, C_YELLOW) client.wsimage.image.draw_line(x1, y1, x1, 960-1, C_YELLOW) client.wsimage.image.draw_line(x2, y1, x2, 960-1, C_YELLOW) end super end end # マップパーツウィンドウ class MapPartsWindow < WSWindow attr_reader :select_number def initialize(*args) super @images = Map.class_variable_get(:@@images) client.extend Clickable client.add_handler(:click) do |obj, tx, ty| @select_number = (tx / 32 + ty / 32 * (self.client.width / 32)) end @selected_image = Image.new(32,32).box(0,0,31,31,C_WHITE) @select_number = 0 end def draw # パーツ描画 x = y = 0 @images.each do |o| client.image.draw(x, y, o) x += 32 if x > self.client.width-32 x = 0 y += 32 end end # セレクトボックス描画 client.image.draw(@select_number % (client.width / 32) * 32, @select_number / (client.width / 32) * 32, @selected_image) super end end end
という定義をサンプルSTGに追加したうえで、
# ウィンドウシステムのWindowオブジェクト WS.desktop.add_control(WS::GameWindow.new(50,100,360,480+16+6, "GameMainWindow"), :gamewindow) WS.desktop.add_control(WS::MapEditWindow.new(420,10,528,700, "MapEditer"), :mapeditwindow) WS.desktop.add_control(WS::MapPartsWindow.new(960,10,294,342, "MapParts"), :mappartswindow)
という感じにウィンドウを生成して、
WS.update
という一文をWindow.loopの中に書けばこのように動く。