2018/02/17(土) [n年前の日記]
#1 [dxruby] DXOpalでタイルマップBGを描画
_DXOpal
で、どうにかタイルマップBGを描画することができた。
_DXOpal fake draw_tile test
マップデータは、 _Tiled マップエディタ 1.0.3 で作成して、json形式でエクスポートして用意した。
Rubyソース内にマップデータをずらずらと書いた場合は、初期化でめちゃくちゃ時間がかかったけど、jsonを読む形にしたら圧倒的に速く初期化が終わるようになった。
しかし…。予想はしていたけど、めちゃくちゃ描画が遅い。
640x480のウインドウサイズで、16x16ドットのタイルチップを使ったBGを、4枚表示してる状態だけど…。DXRuby なら 60FPS で動くけれど、DXOpal では10FPSも出ない。ちなみに自分の環境は、CPU : Core i5-2500 (3.3GHz、4コア)、ビデオカード : NVIDIA GeForce GTX 750 Ti。
考えてみたら、空白部分は描画してないとはいえ、最多では ((640 / 16) + 1) * ((480 / 16) + 1) * 4 = 5084個もタイルチップを描画するのだから、そりゃ遅いよな…。しかし、試しにBGを2枚に減らしてみても、それでも遅くて。タイルチップのサイズを16x16にしてるあたりで、どうしても枚数・個数が増えてしまうわけで…。
以下、ハマった点をメモ。
_DXOpal fake draw_tile test
マップデータは、 _Tiled マップエディタ 1.0.3 で作成して、json形式でエクスポートして用意した。
Rubyソース内にマップデータをずらずらと書いた場合は、初期化でめちゃくちゃ時間がかかったけど、jsonを読む形にしたら圧倒的に速く初期化が終わるようになった。
しかし…。予想はしていたけど、めちゃくちゃ描画が遅い。
640x480のウインドウサイズで、16x16ドットのタイルチップを使ったBGを、4枚表示してる状態だけど…。DXRuby なら 60FPS で動くけれど、DXOpal では10FPSも出ない。ちなみに自分の環境は、CPU : Core i5-2500 (3.3GHz、4コア)、ビデオカード : NVIDIA GeForce GTX 750 Ti。
考えてみたら、空白部分は描画してないとはいえ、最多では ((640 / 16) + 1) * ((480 / 16) + 1) * 4 = 5084個もタイルチップを描画するのだから、そりゃ遅いよな…。しかし、試しにBGを2枚に減らしてみても、それでも遅くて。タイルチップのサイズを16x16にしてるあたりで、どうしても枚数・個数が増えてしまうわけで…。
以下、ハマった点をメモ。
◎ 外部ファイルの読み込みができない。 :
DXRuby上ではスンナリ動いたのに、DXOpalではエラーが出て首を捻ってたけど。どうやら、DXOpal は外部テキストファイルを簡単に読み込めないようで。
例えば、ローカルで動かしてる Ruby上なら、以下のような形でテキストファイルが読み込めるけど。
DXOpal は、できない。考えてみれば、ブラウザ + JavaScript で動かしているのだから、サーバ上のファイルは読み込めても、HDDに入ってるローカルファイルを読み込めちゃったらマズいよなと。
なので、以下のような書き方をして、外部テキストファイルを読み込んでみたり。
_DXOpal file read test
何をしているかというと…。Native() を使ってJavaScriptの関数を直接呼んでどうにかしてる、という…。 _dxopal/dxopal.rb の require_remote() を参考にして、たぶんこうかな、と。JavaScript、全然分かんないけど…。
加えて、以下の記事が大変参考になりました。ありがたや。
_OpalでJavaScriptのAPIラッパーを作る - Qiita
_OpalのNativeはどのように実装されているのか - Qiita
「%x{ 〜 } って何だろう?」と首を捻ってたけど、その中に JavaScript を直接書けるのですな…。
例えば、ローカルで動かしてる Ruby上なら、以下のような形でテキストファイルが読み込めるけど。
text = File.open("data.txt") {|f| f.read }
DXOpal は、できない。考えてみれば、ブラウザ + JavaScript で動かしているのだから、サーバ上のファイルは読み込めても、HDDに入ってるローカルファイルを読み込めちゃったらマズいよなと。
なので、以下のような書き方をして、外部テキストファイルを読み込んでみたり。
_DXOpal file read test
url = 'data.txt' req = Native(`new XMLHttpRequest()`) req.overrideMimeType("text/plain") req.open("GET", url, false) req.send text_data = req.responseText
何をしているかというと…。Native() を使ってJavaScriptの関数を直接呼んでどうにかしてる、という…。 _dxopal/dxopal.rb の require_remote() を参考にして、たぶんこうかな、と。JavaScript、全然分かんないけど…。
加えて、以下の記事が大変参考になりました。ありがたや。
_OpalでJavaScriptのAPIラッパーを作る - Qiita
_OpalのNativeはどのように実装されているのか - Qiita
「%x{ 〜 } って何だろう?」と首を捻ってたけど、その中に JavaScript を直接書けるのですな…。
◎ jsonのparseができない。 :
Opal は jsonライブラリも用意されてるらしいので、外部テキストファイルが読み込めたら後は楽勝だろう、と思ったら、「JSONが初期化できねえ」と怒られ続けて。
結局、以下のような書き方に。
_DXOpal json parse test
これまた、Native() を使って JavaScriptの JSON.parse() を直接呼び出しているという…。いいのかコレで。まあ、動いてるから、いいか…。
結局、以下のような書き方に。
_DXOpal json parse test
url = 'data.json' req = Native(`new XMLHttpRequest()`) req.overrideMimeType("text/plain") req.open("GET", url, false) req.send text_data = req.responseText data = Native(`JSON.parse(text_data)`)
これまた、Native() を使って JavaScriptの JSON.parse() を直接呼び出しているという…。いいのかコレで。まあ、動いてるから、いいか…。
◎ DXRuby版。 :
せっかくだから、一応、DXRuby版もメモ。まあ、DXRuby の場合、Window.draw_tile() を使えばタイルマップBG描画はできてしまうのだけど。
_disp_map_load_json.rb
Tiled データ(.png / .tmx)と、エクスポートした json は、zipにして以下に置いときます。License : CC0 / Public Domain ってことで。
_bg_atari_test.zip
_disp_map_load_json.rb
# Tiledからエクスポートしたjsonを読み込んでDXRubyで描画する # require 'dxopal' # include DXOpal require 'dxruby' require 'json' # Image.register(:bgchip, 'images/bg_attari.png') # DXOpal def json_to_hash_dxopal(url) req = Native(`new XMLHttpRequest()`) req.overrideMimeType("text/plain") req.open("GET", url, false) req.send text_data = req.responseText return Native(`JSON.parse(text_data)`) end # DXRuby def json_to_hash_dxruby(url) json_text = File.open(url) {|f| f.read } return JSON.load(json_text) end def get_map_data_from_json(json_file) # res = json_to_hash_dxopal(json_file) res = json_to_hash_dxruby(json_file) d = {} d[:tilewidth] = res["tilewidth"] d[:tileheight] = res["tileheight"] d[:width] = res["width"] d[:height] = res["height"] layers = {} res["layers"].each do |layer| name = layer["name"] w = layer["width"] h = layer["height"] org_data = layer["data"] layers[name] = Array.new(h){ Array.new(w) } h.times do |y| w.times do |x| code = org_data[y * w + x] - 1 layers[name][y][x] = (code < 0)? nil : code end end end d[:layers] = layers return d end def draw_tile(x, y, map_array, imgs, start_x, start_y, x_cnt, y_cnt) ofs_x = x ofs_y = y tile_w = imgs[0].width tile_h = imgs[0].height bg_h = map_array.length bg_w = map_array[0].length start_x = start_x % (tile_w * bg_w) start_y = start_y % (tile_h * bg_h) x_mod = (start_x % tile_w).to_i y_mod = (start_y % tile_h).to_i x_index = (start_x / tile_w).to_i y_index = (start_y / tile_h).to_i y_cnt.times do |y| x_cnt.times do |x| ix = (x_index + x).to_i % bg_w iy = (y_index + y).to_i % bg_h code = map_array[iy][ix] next if code.nil? px = ofs_x + (x * tile_w) - x_mod py = ofs_y + (y * tile_h) - y_mod Window.draw(px, py, imgs[code]) end end end def game_main(img) imgs = img.slice_tiles(img.width / 16, img.height / 16) # mapdata = get_map_data_from_json("mapdata/bg_atari_test.json") mapdata = get_map_data_from_json("bg_atari_test.json") x_cnt = Window.width / mapdata[:tilewidth] + 1 y_cnt = Window.height / mapdata[:tileheight] + 1 bg_x, bg_y = 0, 0 ofs_x, ofs_y = 0, 0 Window.bgcolor = [32, 64, 128] Window.loop do break if Input.keyPush?(K_ESCAPE) if false a = 8 bg_x -= a if Input.keyDown?(K_LEFT) bg_x += a if Input.keyDown?(K_RIGHT) bg_y -= a if Input.keyDown?(K_UP) bg_y += a if Input.keyDown?(K_DOWN) else bg_x += 3 bg_y += 1 end layer_names = ["layer3", "layer2", "layer1", "layer0"] spd = 0.25 layer_names.each do |name| x = bg_x * spd y = bg_y * spd map_data = mapdata[:layers][name] # Window.draw_tile(ofs_x, ofs_y, map_data, imgs, x, y, x_cnt, y_cnt) draw_tile(ofs_x, ofs_y, map_data, imgs, x, y, x_cnt, y_cnt) spd += 0.25 end Window.draw_font(2, 2, "#{Window.real_fps} FPS", Font.default) Window.draw_font(2, 32, "bg x,y = #{bg_x}, #{bg_y}", Font.default) end end # Window.load_resources do img = Image.load("bg_attari.png") # img = Image[:bgchip] game_main(img) # end
Tiled データ(.png / .tmx)と、エクスポートした json は、zipにして以下に置いときます。License : CC0 / Public Domain ってことで。
_bg_atari_test.zip
[ ツッコむ ]
以上、1 日分です。