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 日分です。