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)
end
DXRubyWSのウインドウの中で、ゲーム画面っぽいものが動いてくれた。なるほど…こういう仕組みなのか…。他のサンプルはどうなのだろうと思って、 _DXRubyWS/sample/rubima3.rb を眺めてみたら、こちらは GameWindowクラスの中身がもっと短くなっていた。drawメソッドの中で描画しちゃえば済むのか…。なるほど…。
こういうことができるなら、リアルタイムに何かを動かしながら調整していく感じのツールが作りやすいであろう予感。
[ ツッコむ ]
以上です。
