2016/01/11(月) [n年前の日記]
#1 [dxruby][dxrubyws] DXRubyWSを試してみる
自作キャラグラエディタを書いてる際、「これがもし、DXRubyWS を使っていたら、もう少し楽に書けるのだろうか…」と気になってきたわけで。ということで、少し触ってみて雰囲気だけでも掴んでみようかなと。
DXRubyWS って何だ? …Ruby + DXRuby を使って、GUIアプリを書けるようにするためのライブラリ、という説明でいいのでしょうか。ちょっと違う気もするけど。
初心者向けに、入門記事っぽくなるように、少し細かくメモっていきますよ、と。いや、自分がそもそも初心者だけど。
DXRubyWS って何だ? …Ruby + DXRuby を使って、GUIアプリを書けるようにするためのライブラリ、という説明でいいのでしょうか。ちょっと違う気もするけど。
初心者向けに、入門記事っぽくなるように、少し細かくメモっていきますよ、と。いや、自分がそもそも初心者だけど。
◎ 環境構築その1。 :
DXRubyWS は、以下から入手。
_mirichi/DXRubyWS
右上のほうに「Download ZIP」というボタンがあるのでクリック。DXRubyWS-master.zip をDL(ダウンロード)。
ちなみに、そのうち DXRubyWSの開発が進んで、どの時期の版か分からなくなると困るので、DXRubyWS-master_20160111.zip てな感じに日付を入れてリネームしておくことにする。
さて。DXRubyWS の readme.md には、 「DXRuby1.5.16dev用」 と書いてある。どうやら、動かすためには DXRuby 1.5 開発版(dev版)が必要らしい。
DXRuby開発版(dev版)は、以下から入手できる。
_DXRuby プロジェクトWiki - ファイル置き場
現在公開されてるのは、DXRuby 1.5.19dev (Ruby 2.1.0, 32bit用)。上記ページ内の該当リンクをクリックすれば、dxruby1519dev-mswin32-ruby21.zip をDLできる。
もし、Ruby 2.1 をインストール済みで、かつ、常用してる環境なら…。dxruby1519dev-mswin32-ruby21.zip を解凍後、中に入ってる install.rb を実行するだけで DXRuby dev版のインストールは終了して、DXRubyWS を動かせる状態にできる。
が、しかし。
_mirichi/DXRubyWS
右上のほうに「Download ZIP」というボタンがあるのでクリック。DXRubyWS-master.zip をDL(ダウンロード)。
ちなみに、そのうち DXRubyWSの開発が進んで、どの時期の版か分からなくなると困るので、DXRubyWS-master_20160111.zip てな感じに日付を入れてリネームしておくことにする。
さて。DXRubyWS の readme.md には、 「DXRuby1.5.16dev用」 と書いてある。どうやら、動かすためには DXRuby 1.5 開発版(dev版)が必要らしい。
DXRuby開発版(dev版)は、以下から入手できる。
_DXRuby プロジェクトWiki - ファイル置き場
現在公開されてるのは、DXRuby 1.5.19dev (Ruby 2.1.0, 32bit用)。上記ページ内の該当リンクをクリックすれば、dxruby1519dev-mswin32-ruby21.zip をDLできる。
もし、Ruby 2.1 をインストール済みで、かつ、常用してる環境なら…。dxruby1519dev-mswin32-ruby21.zip を解凍後、中に入ってる install.rb を実行するだけで DXRuby dev版のインストールは終了して、DXRubyWS を動かせる状態にできる。
が、しかし。
◎ 環境構築の続き。複数のRubyバージョンを共存させる。 :
自分は普段、Ruby 2.0.0 + DXRuby 1.4.2 を使っていて。
DXRuby 1.5.19dev は、Ruby 2.1 用なので、Ruby 2.0.0 を常用してる自分の環境ではインストールできない。
なので、Ruby 2.1 もインストールして、Ruby 2.0.0 と共存させることにする。
以下から、Ruby 2.1 Windows版を ―― rubyinstaller-2.1.7.exe をDLして実行してインストールする。
_Downloads - RubyInstaller for Windows
注意点としては…。
Ruby 2.0.0 と 2.1 の切り替えは、pik か uru を使う。以下の記事を参考にして、インストール方法や使い方を把握。
_pikの替わりにuru〜windowsで複数バージョンのrubyを切り替える〜 - Qiita
_Windows7にRubyInstaller+Pikで複数バージョンのRuby環境を整える - ひろうぃんの雑記
ところで、pik や uru を使って Ruby のバージョンを切り替えた時は、Rubyスクリプト(.rb) をいきなり実行せず、
とりあえず、これで Ruby 2.1 を使えるようになったはず。pik か uru で、Ruby 2.1 に切り替えて、Ruby のバージョンを確認。ruby --version で確認できる。ruby 2.1.7p400 と表示されたら、Ruby 2.1 に切り替えができてる。
DXRuby dev版を、ruby install.rb を実行してインストール。
インストールされた DXRuby のバージョンを、irb上で確認してみる。
irb は、Rubyを対話的に入力して実行するためのツール。…「対話的」って、どゆこと? インタラクティブってこと。(命令を伝えたら)その場で反応が返ってくるものを、「対話的」とか「インタラクティブ」と呼んだりします。たぶん。
と、ここまでメモったところで気が付いた。DXRubyWS の readme.md には「DXRuby1.5.16dev用」と書いてある…。DXRuby 1.5.19dev、じゃなくて、1.5.16dev…。
_DXRuby プロジェクトWiki - ファイル置き場 には、DXRuby1.5.16dev ruby2.0.0(32bit)用があるわけで。
つまり、Ruby 2.0.0 を使ってるなら、1.5.16dev をインストールすれば DXRubyWS を使えた可能性が。わざわざ Ruby 2.1 までインストールする必要は無かったのかもしれない…。
まあ、何かしらで Ruby 2.1 が必要になる時もあるだろうから、各バージョンを共存させといても別にいいよな。などと嘯いて自分を納得させるのでした。
DXRuby 1.5.19dev は、Ruby 2.1 用なので、Ruby 2.0.0 を常用してる自分の環境ではインストールできない。
なので、Ruby 2.1 もインストールして、Ruby 2.0.0 と共存させることにする。
以下から、Ruby 2.1 Windows版を ―― rubyinstaller-2.1.7.exe をDLして実行してインストールする。
_Downloads - RubyInstaller for Windows
注意点としては…。
- Ruby 2.0.0 とは違う場所を指定してインストールする。Ruby 2.0.0と共存させたいので。
- 「Rubyの実行ファイルへ環境変数PATHを設定する」「.rbと.rbwファイルをRubyに関連付ける」のチェックは外す。普段は Ruby 2.1 ではなく、Ruby 2.0.0 を使いたいため。
Ruby 2.0.0 と 2.1 の切り替えは、pik か uru を使う。以下の記事を参考にして、インストール方法や使い方を把握。
_pikの替わりにuru〜windowsで複数バージョンのrubyを切り替える〜 - Qiita
_Windows7にRubyInstaller+Pikで複数バージョンのRuby環境を整える - ひろうぃんの雑記
ところで、pik や uru を使って Ruby のバージョンを切り替えた時は、Rubyスクリプト(.rb) をいきなり実行せず、
ruby hoge.rbといった形で実行しないといけない。.rb をいきなり実行すると、常用してる Ruby のほうが使われてしまうので。
とりあえず、これで Ruby 2.1 を使えるようになったはず。pik か uru で、Ruby 2.1 に切り替えて、Ruby のバージョンを確認。ruby --version で確認できる。ruby 2.1.7p400 と表示されたら、Ruby 2.1 に切り替えができてる。
DXRuby dev版を、ruby install.rb を実行してインストール。
インストールされた DXRuby のバージョンを、irb上で確認してみる。
irb は、Rubyを対話的に入力して実行するためのツール。…「対話的」って、どゆこと? インタラクティブってこと。(命令を伝えたら)その場で反応が返ってくるものを、「対話的」とか「インタラクティブ」と呼んだりします。たぶん。
> irb irb(main):001:0> require 'dxruby' => true irb(main):002:0> DXRuby::VERSION => "1.5.19dev" irb(main):003:0> exitDXRuby::VERSION には、"1.5.19dev" が入ってたので、ちゃんと DXRuby dev版がインストールできていることが分かる。
と、ここまでメモったところで気が付いた。DXRubyWS の readme.md には「DXRuby1.5.16dev用」と書いてある…。DXRuby 1.5.19dev、じゃなくて、1.5.16dev…。
_DXRuby プロジェクトWiki - ファイル置き場 には、DXRuby1.5.16dev ruby2.0.0(32bit)用があるわけで。
つまり、Ruby 2.0.0 を使ってるなら、1.5.16dev をインストールすれば DXRubyWS を使えた可能性が。わざわざ Ruby 2.1 までインストールする必要は無かったのかもしれない…。
まあ、何かしらで Ruby 2.1 が必要になる時もあるだろうから、各バージョンを共存させといても別にいいよな。などと嘯いて自分を納得させるのでした。
◎ DXRubyWSのサンプルを動かしてみる。 :
DXRubyWS-master.zip を解凍すると、sampleフォルダが入ってる。中に入って、一通り動かしてみる。
各ウインドウは、位置変更のみならず、サイズ変更もできる。サイズ変更に追随しないレイアウトと、サイズ変更に追随するレイアウトが実現できているらしい。
ただし、一番大元の、背景色が黒のウインドウは、サイズ変更ができなかった…。
DXRubyを使ったスクリプトも、ウインドウサイズを変更すると中の描画がおかしくなる時があるので、DXRubyWSも似たような制限があるのかもしれない。が、それってつまり、デスクトップサイズに合わせてウインドウサイズを変更できない、作業しやすいウインドウサイズに変更できないということで、GUIアプリを作る場合は少々厳しい場面が出てくるような気もするのだけど、今はそのあたり考えないことにする。
ゲームを動かしながら、リアルタイムでその見た目を変更できてしまうあたり、凄いというか、面白いというか。Unityも、ここまではできなかったような気がする。…と言っても、Unityは、GUIでかなりの設定・指定ができるあたりが売りだろうから、比べるのもおかしい気がするけど。提供してる便利さが、そもそも違うというか。
ソース内には、「簡易FM音源」と書いてあった。FM音源…懐かしい…。いや、今もDTMの世界ではフツーに現役ですが。
てなわけで、既に色々なウィジェットが使えそうなことが伝わってきた。
長くなってきたので、続きは別記事に分けて書こう…。
ruby minsample.rb色んなウィジェット(GUI部品/コントロール)が出てきた。
- ボタン
- ラベル
- テキストボックス
- ドロップダウンリスト
- チェックボックス
- ラジオボタン
- リストボックス
- リストビュー
各ウインドウは、位置変更のみならず、サイズ変更もできる。サイズ変更に追随しないレイアウトと、サイズ変更に追随するレイアウトが実現できているらしい。
ただし、一番大元の、背景色が黒のウインドウは、サイズ変更ができなかった…。
DXRubyを使ったスクリプトも、ウインドウサイズを変更すると中の描画がおかしくなる時があるので、DXRubyWSも似たような制限があるのかもしれない。が、それってつまり、デスクトップサイズに合わせてウインドウサイズを変更できない、作業しやすいウインドウサイズに変更できないということで、GUIアプリを作る場合は少々厳しい場面が出てくるような気もするのだけど、今はそのあたり考えないことにする。
ruby rubima.rbウインドウの中で、おそらくは60FPSのゲームが動いてる…。敵オブジェクトをクリックすると、そのオブジェクトが選択されて、右側のウインドウ内に敵の情報(HP)が表示される。自爆ボタンを押すと選択中の敵が爆発して画面から消えたので、ゲーム内のオブジェクトに対して外部から制御ができるよ、というデモなのかもしれない。
ruby rubima3.rbウインドウの中でゲームを動かしながら、BGの表示位置を別ウインドウ内に表示できている。しかも、タイルチップを選んで、真ん中のウインドウ内でBGマップに書き込むと、ゲーム内のBG表示もソレに合わせて変化する。
ゲームを動かしながら、リアルタイムでその見た目を変更できてしまうあたり、凄いというか、面白いというか。Unityも、ここまではできなかったような気がする。…と言っても、Unityは、GUIでかなりの設定・指定ができるあたりが売りだろうから、比べるのもおかしい気がするけど。提供してる便利さが、そもそも違うというか。
ruby soundblock.rb音の波形っぽいものが出てきた。Playボタンを押すと音が鳴る。スライダー、スピンボタン(スピンボックス?)が表示されていて、それぞれを変更してからPlayボタンを押すと音が変化することが分かる。
ソース内には、「簡易FM音源」と書いてあった。FM音源…懐かしい…。いや、今もDTMの世界ではフツーに現役ですが。
ruby splitcontainertest.rbもしかすると、コンテナを実現できているというデモだろうか…。「パネルE」と書かれてる部分はグループボックス? ラベル付パネル? なのかもしれない。パネルの中に、複数のウィジェットを配置できますよ、ということなのかな。
ruby statuswindow.rbこれは何のデモか分からなかった…。
ruby tabtest.rbタブの表示ができていて、かつ、スクロールバーもついていて中身をスクロールできる。
ruby test_autolayout.rb各ウインドウのサイズを変更すると、中のウィジェットのサイズもソレに合わせて追随する。自動レイアウトのデモだろうか。
てなわけで、既に色々なウィジェットが使えそうなことが伝わってきた。
長くなってきたので、続きは別記事に分けて書こう…。
[ ツッコむ ]
#2 [dxruby][dxrubyws] DXRubyWSのチュートリアル文書に従って試してみる
DXRubyWS を解凍すると、中に doc フォルダが入っていて、そこに説明文書が置いてある。
_tutorial01.txt と、 _tutorial02.txt が、チュートリアル文書(= 使用方法や機能を解説する教材のようなもの)らしい。
まずは、tutorial01.txt を写経して動作確認してみることにする。
ちなみに、スクリプトの置き場所は、libフォルダと同じ階層。
_tutorial01.txt と、 _tutorial02.txt が、チュートリアル文書(= 使用方法や機能を解説する教材のようなもの)らしい。
まずは、tutorial01.txt を写経して動作確認してみることにする。
ちなみに、スクリプトの置き場所は、libフォルダと同じ階層。
◎ 最も簡単なコード。 :
_tuto01.rb
要するに、DXRubyWS を使いたい時は、
require_relative './lib/dxrubyws' Window.loop do WS.update end真っ黒な画面が表示された。
要するに、DXRubyWS を使いたい時は、
- 最初のほうに、「require_relative './lib/dxrubyws'」と書いておく。
- 最後のほうで、「Window.loop do」「WS.update」「end」と書いておく。
◎ マウスに反応させてみる。 :
_tuto02.rb
DXRubyWS は、 _イベントドリブン で書いていく、らしい。…イベントドリブンって何だ? 何かのイベントが起きた時、そのイベントに対応した処理をするよ、ってこと。
例えば、このサンプルの場合は、「マウスボタンが押された」というイベントが発生したら、「画面に文字を描画する」という処理をしろや、と、WS.desktop.add_handler 〜 end のあたりで設定してある。だから、マウスボタンを押すと、画面に「click!」と表示されたわけで。
もし、イベントドリブンでは無い書き方をするとしたら…。例えば DXRuby で同じ処理を書くとしたら、たぶんこうなる。
_tuto02_b.rb
まあ、おそらく内部的には、イベントドリブンとやらも似たようなことを ―― 何かしらをずっと監視し続けて、とかやってると思うのだけど。プログラムを書く人間様としては、「○○が起きた時に、○○せよ」てな感覚でソースを書いていったほうが分かりやすいところがあるので、イベントドリブンなる概念があるのだろうな、などと想像してみたり。人間様が分かるように、面倒臭いところを上手に隠して、分かりやすいところだけ提供するってのは、プログラミングにおいては大事。
require_relative './lib/dxrubyws' font = Font.new(32) WS.desktop.add_handler(:mouse_push) do # マウスボタンが押されたら(「:mouse_push」のシグナルが来たら)… # 画面に「click!」と表示する Window.draw_font(0, 0, "click!", font) end Window.loop do WS.update endマウスボタンを押すと、画面に「click!」と表示された。たしかに、マウスに反応している。
DXRubyWS は、 _イベントドリブン で書いていく、らしい。…イベントドリブンって何だ? 何かのイベントが起きた時、そのイベントに対応した処理をするよ、ってこと。
例えば、このサンプルの場合は、「マウスボタンが押された」というイベントが発生したら、「画面に文字を描画する」という処理をしろや、と、WS.desktop.add_handler 〜 end のあたりで設定してある。だから、マウスボタンを押すと、画面に「click!」と表示されたわけで。
もし、イベントドリブンでは無い書き方をするとしたら…。例えば DXRuby で同じ処理を書くとしたら、たぶんこうなる。
_tuto02_b.rb
require 'dxruby' font = Font.new(32) Window.loop do # マウスボタンが押されたか、毎フレームチェックし続けて if Input.mousePush?(M_LBUTTON) # ボタンが押されてたら、画面に「click!」と表示する Window.draw_font(0, 0, "click!", font) end end毎フレーム、毎フレーム、「マウスボタンが押されたか?」「マウスボタンが押されたか?」と、飽きもせず、毎回毎回、延々と監視し続けて、もし押されてたら…という感じになる。
まあ、おそらく内部的には、イベントドリブンとやらも似たようなことを ―― 何かしらをずっと監視し続けて、とかやってると思うのだけど。プログラムを書く人間様としては、「○○が起きた時に、○○せよ」てな感覚でソースを書いていったほうが分かりやすいところがあるので、イベントドリブンなる概念があるのだろうな、などと想像してみたり。人間様が分かるように、面倒臭いところを上手に隠して、分かりやすいところだけ提供するってのは、プログラミングにおいては大事。
◎ コントロールを作って、マウスで動かす。 :
コントロールって何だ? GUI部品、ウィジェットのこと。ボタンとか、ラベルとか、チェックボックスとか、そういうGUI部品を、ウィジェットとかコントロールとか呼んだりする、のだと思います。たぶん。ちょっと自信ないけど。
このサンブルの場合、
このコントロールを、マウスで動かしてみる。
_tuto03_b.rb
そろそろ分からなくなってきた。以下が追加された部分。
:drag_move というシグナルが来たら(イベントが発生したら)、マウスカーソルの移動量を得られるから、それをコントロールの座標値に加算してやることで、コントロールの表示位置が変更できている、のだろう。
require_relative './lib/dxrubyws' control = WS::WSControl.new(200, 100, 100, 100) control.image = Image.new(100, 100, C_WHITE) WS.desktop.add_control(control) Window.loop do WS.update end画面の真ん中に、白い何かが表示された。たぶん、この白い何かが、コントロール、なんだろう。
このサンブルの場合、
- WS::WSControl.new() でコントロールを作って、
- Image.new() で真っ白な画像を作り、ソレをコントロールが持ってる画像として設定して
- WS.desktop.add_control() で、画面に登録。
このコントロールを、マウスで動かしてみる。
_tuto03_b.rb
require_relative './lib/dxrubyws' control = WS::WSControl.new(200, 100, 100, 100) control.image = Image.new(100, 100, C_WHITE) control.extend WS::Draggable control.add_handler(:drag_move) do |obj, dx, dy| control.x += dx control.y += dy end WS.desktop.add_control(control) Window.loop do WS.update end白い画像を、マウスドラッグで移動できるようになった。
そろそろ分からなくなってきた。以下が追加された部分。
control.extend WS::Draggable control.add_handler(:drag_move) do |obj, dx, dy| control.x += dx control.y += dy endtutorial01.txt によると…。control.extend WS::Draggable てのが、サポートモジュールとやらを使う指定っぽい。名前からしてマウスドラッグ関係の何かなんだろうな。
:drag_move というシグナルが来たら(イベントが発生したら)、マウスカーソルの移動量を得られるから、それをコントロールの座標値に加算してやることで、コントロールの表示位置が変更できている、のだろう。
◎ ドラッガブル豆腐クラスを作る。 :
tutorial01.txt によると、この後、「ドラッガブル豆腐クラス」とやらを作ってみるよ、てことになってるのですが。ここで問題発生。
ちなみに、豆腐って何? …DXRubyでは、例の白い画像を「豆腐」と呼んでることが多くて。要するに、「ドラッガブル豆腐」=「マウスでドラッグできる白い画像」、なんだと思います。たぶん。
_tuto04.rb
動かしてみたら、エラーが。
_Rubyのエラーメッセージwrong number of arguments (a for b)の意味 - Qiita によると、
つまり、def on_drag_move(obj, dx, dy) は、obj, dx, dy の、3つの引数が書いてあるけど、この名前のメソッドは、本当は2つしか引数が無いはずやで? 間違えてるで? みたいな?
lib/module.rb を開いて、on_drag_move で検索してみたり。
_tuto04_b.rb
要するに、こんな感じでコントロール(ウィジェット/GUI部品)を、クラスとして作って増やしていけますよ、ということなのかな…。
これで _tutorial01.txt の内容は一通り試せた。
_tutorial02.txt では標準GUIの使い方が説明されているらしい。明日、眺めてみることにしよう…。
ちなみに、豆腐って何? …DXRubyでは、例の白い画像を「豆腐」と呼んでることが多くて。要するに、「ドラッガブル豆腐」=「マウスでドラッグできる白い画像」、なんだと思います。たぶん。
_tuto04.rb
require_relative './lib/dxrubyws' module WS class DraggableTofu < WSControl include Draggable def initialize(x, y, width, height) super self.image = Image.new(width, height, C_WHITE) self.add_handler(:drag_move, self.method(:on_drag_move)) end def on_drag_move(obj, dx, dy) self.x += dx self.y += dy end end end tofu = WS::DraggableTofu.new(200, 100, 100, 100) WS.desktop.add_control(tofu) Window.loop do WS.update end
動かしてみたら、エラーが。
> ruby tuto04.rb tuto04.rb:17:in `on_drag_move': wrong number of arguments (2 for 3) (ArgumentError) from C:/home/prg/ruby/test_dxruby/dxrubyws_test/lib/module.rb:132:in `on_mouse_move' from C:/home/prg/ruby/test_dxruby/dxrubyws_test/lib/core.rb:112:in `mouse_event_dispatch' from C:/home/prg/ruby/test_dxruby/dxrubyws_test/lib/dxrubyws.rb:118:in `update' from C:/home/prg/ruby/test_dxruby/dxrubyws_test/lib/dxrubyws.rb:165:in `update' from tuto04.rb:28:in `block in <main>' from tuto04.rb:27:in `loop' from tuto04.rb:27:in `<main>'on_drag_move ってところで、何かを間違えてるっぽいけど…。
_Rubyのエラーメッセージwrong number of arguments (a for b)の意味 - Qiita によると、
tuto04.rb:17:in `on_drag_move': wrong number of arguments (2 for 3) (ArgumentError)てのは、3つ引数が来るはずなのに、2つ来たよ、という意味なのかな…。
つまり、def on_drag_move(obj, dx, dy) は、obj, dx, dy の、3つの引数が書いてあるけど、この名前のメソッドは、本当は2つしか引数が無いはずやで? 間違えてるで? みたいな?
lib/module.rb を開いて、on_drag_move で検索してみたり。
def on_drag_move(tx, ty) signal(:drag_move, tx, ty) endうむ。引数は2つですね。なら、2つに修正すればいいのかな。
_tuto04_b.rb
require_relative './lib/dxrubyws' module WS class DraggableTofu < WSControl include Draggable def initialize(x, y, width, height) super self.image = Image.new(width, height, C_WHITE) self.add_handler(:drag_move, self.method(:on_drag_move)) end # def on_drag_move(obj, dx, dy) def on_drag_move(dx, dy) self.x += dx self.y += dy end end end tofu = WS::DraggableTofu.new(200, 100, 100, 100) WS.desktop.add_control(tofu) Window.loop do WS.update end動いた。豆腐をマウスでドラッグできてる。
要するに、こんな感じでコントロール(ウィジェット/GUI部品)を、クラスとして作って増やしていけますよ、ということなのかな…。
これで _tutorial01.txt の内容は一通り試せた。
_tutorial02.txt では標準GUIの使い方が説明されているらしい。明日、眺めてみることにしよう…。
[ ツッコむ ]
以上、1 日分です。