2016/01/14(木) [n年前の日記]
#1 [dxruby][dxrubyws] DXRubyWSのウインドウの中で60FPSのゲームを動かしたい
要するに、
_DXRubyWS/sample/rubima.rb
のようなことをしてみたいのです。どういう仕組みで、ウインドウ内にゲーム画面を表示できているのだろう…。
眺めているうちに、なんとなく分かってきた。もしかすると、こういうことかな…。
rubima.rb を改造して、少しだけ短めのサンプルソースにしてみたり。
_game_and_info.rb
他のサンプルはどうなのだろうと思って、 _DXRubyWS/sample/rubima3.rb を眺めてみたら、こちらは GameWindowクラスの中身がもっと短くなっていた。drawメソッドの中で描画しちゃえば済むのか…。なるほど…。
こういうことができるなら、リアルタイムに何かを動かしながら調整していく感じのツールが作りやすいであろう予感。
眺めているうちに、なんとなく分かってきた。もしかすると、こういうことかな…。
- ゲーム画面を描画するための RenderTarget を生成して、グローバル変数に入れておく。
- ゲーム画面への描画は、そのグローバルなRenderTargetに対して行う。
- メインループの中で、そのグローバルな RenderTarget を、ゲーム画面用ウインドウのクライアントのイメージに対して描画してやる。
rubima.rb を改造して、少しだけ短めのサンプルソースにしてみたり。
_game_and_info.rb
# DXRubyWSのウインドウ内に、60FPSで動くゲーム画面を表示してみるテスト # sample/rubima.rb を参考に作成 require 'dxruby' require_relative 'lib/dxrubyws' require_relative 'lib/standardgui' # ---------------------------------------- # ゲーム画面用クラス # ゲーム画面内で画像がバウンドするだけの処理 class GameMain attr_accessor :width, :height, :image # 初期化 def initialize @x, @y = 100, 100 @dx, @dy = 8, 4 @width = 360 @height = 480 @image = Image.new(64, 64, C_WHITE) end # 更新 def update # 座標に速度を加算 @x += @dx @y += @dy # 画面外に出そうなら速度の向きを反転させる @dx *= -1 if (@x <= 0 and @dx < 0) or ((@x + @image.width) >= @width and @dx > 0) @dy *= -1 if (@y <= 0 and @dy < 0) or ((@y + @image.height) >= @height and @dy > 0) end # 描画 def draw # グローバルなRenderTargetに対して描画してる $rt.draw(@x, @y, @image) end end # ---------------------------------------- # ウインドウシステム用のクラス定義 module WS # ---------------------------------------- # ゲーム画面が表示されるウインドウ class GameWindow < WSWindow def initialize(*args) super end # サイズ変更されたら再描画 def resize(*args) super self.client.image.draw(0, 0, $rt) # ゲーム画面サイズも変更しておく $gamemain.width = self.width $gamemain.height = self.height - 32 end # 描画 def draw super end end # ---------------------------------------- # ゲーム画面ではないほうのウインドウ class DetailWindow < WSWindow def initialize(*args) super # ラベル生成と登録 x, y, w, h = 8, 8, 100, 16 @label = WSLabel.new(x, y, w, h, "TEST") self.client.add_control(@label) # ボタン生成と登録 x, y, w, h = 8, 32, 150, 20 button = WSButton.new(x, y, w, h, "画像読み込み") self.client.add_control(button) # ボタンが押された時の処理を登録 button.add_handler(:click, self.method(:on_click)) @count = 0 end # 状態更新 def update # カウントアップをラベルで表示してみる @label.caption = @count.to_s @count += 1 super end # ボタンが押された時の処理 def on_click(obj, tx, ty) # ファイル選択ダイアログを開く filter = [ ["PNGファイル(*.png)", "*.png"], ["すべてのファイル(*.*)", "*.*"], ] filepath = Window.openFilename(filter, "画像ファイルを選択") if filepath # ゲーム画面用クラスの画像を差し替える $gamemain.image = Image.load(filepath) end end end end # ---------------------------------------- # ここから、ゲームのメイン処理 font = Font.new(24) # フォント生成 Window.width, Window.height = 800, 600 # 画面サイズ変更 # ゲーム画面を描画するための RenderTarget を生成して # グローバル変数に入れておく $rt = RenderTarget.new(360, 480, [0, 0, 0]) # ゲーム画面クラスを生成 $gamemain = GameMain.new() # ゲーム画面用ウインドウを生成して画面に登録 gamewindow = WS::GameWindow.new(50,100,360,480) WS::desktop.add_control(gamewindow, :gamewindow) # ゲーム画面ではないウインドウを生成して画面に登録 detailwindow = WS::DetailWindow.new(450,100,200,200) WS::desktop.add_control(detailwindow, :detailwindow) # メインループ Window.loop do break if Input.key_push?(K_ESCAPE) # Esc キーで終了 # ここでゲームの処理をする $gamemain.update $gamemain.draw # ここまで来れば、グローバルなRenderTargetに、 # ゲーム画面の内容が描画されてるはず # ゲーム画面用ウインドウに、グローバルなRenderTargetの内容を描画する WS.desktop.gamewindow.client.image.draw(0, 0, $rt) WS.update # ここで WS.update を呼んでる # 各種情報を画面に出力 s = "CPU : #{Window.get_load.to_i} %" Window.draw_font(0, 0, s, font, :z => 100) endDXRubyWSのウインドウの中で、ゲーム画面っぽいものが動いてくれた。なるほど…こういう仕組みなのか…。
他のサンプルはどうなのだろうと思って、 _DXRubyWS/sample/rubima3.rb を眺めてみたら、こちらは GameWindowクラスの中身がもっと短くなっていた。drawメソッドの中で描画しちゃえば済むのか…。なるほど…。
こういうことができるなら、リアルタイムに何かを動かしながら調整していく感じのツールが作りやすいであろう予感。
[ ツッコむ ]
以上です。