[MyGame]アニメーションの指定方法案
taro = Image.new('taro.bmp') taro.disp_size '32x32' taro.set_anim :left, 15, [0, 1, 2, 1], :loop taro.start_anim :left taro.start_anim # 全パタンのループ taro.set_anim nil, 30 taro.disp_size 32, 32 [:right, :left, :up, :down].each_with_index do |key, i| taro.set_anim key, [0 + i, 1 + i, 2 + i, 1 + i], :loop end
プログラミング言語の勉強を継続する三つのポイント
これの1つ目と3つ目はなるほどと思います。でも2はちょっと。
自分用に2を修正してみます。
【読む】書くのもよいけれど、読むことも大切。知っていることだけでやりくりせず、書籍やWebで幅広い情報を集めてよりよい解法を見つけよう。他人の書いたソースを読むことも大事。
書くのは楽しいけど、読むのは苦手なんだよなあ。だからみんなが知っている当たり前のことを知らなくて、苦労していることが多い。せっかちでとにかくちょっと読んだら書かずにはいられない性格なんです。勉強会に来るような人たちにこういうタイプはいないようですが。
ぐーたらしてない日記の class Task
メモ。きれいなコードなので理解しやすい。
- タスク生成時に与えたプライオリティを考慮したタスク同士の双方向リンク
- run メソッド経由でメソッドを実行(メソッド名をシンボルで与える)することにより任意のメソッドを子タスクもろとも実行可能
- run_down はプライオリティを逆にして実行
- タスクの検索機能
- 木構造のダンプ機能
小さな実装なのに実用的ぽくてすばらしい。id にはシンボルも使いたいかも。
起動しなくなったgp6(gentoo)はファイルシステムが壊れていた
クローゼットの奥から引っ張り出してディスプレイにつないでみたら、ファイルシステムが壊れているといわれてブートしない。
面倒なのでDebianを新規インストールしちゃおうかなと思ったけど「バカが征く on Rails」が入ったままだ。あれは開発環境をそのまま公開していたのであすこにしかソースがない。Wikiに貼ってあるソースは古いしなあ。と思ってどっかにバックアップとってないかなと思って探してみたら、壊れたマシンのデータを固めたものを10月15日にレンタルサーバーに上げてあった。良くやった過去のオレ。
新しいPCも来たし、これからはちゃんと Subversion でやっていくつもり。
[開発ログ]lighttpdで動かす
まずlighttpd。
apt-get install libc6/unstable apt-get install lsb-base/unstable
のあと
apt-get install lighttpd
rcconfでlighttpdの自動を解除。
次にfcgi。
apt-get install libfcgi-dev
のあと、
gem install fcgi (略) ERROR: While executing gem ... (RuntimeError) ERROR: Failed to build gem native extension. Gem files will remain installed in /home/dan/ruby/lib/ruby/gems/1.8/gems/fcgi-0.8.6.1 for inspection. ruby extconf.rb install fcgi\nchecking for fcgiapp.h... yes checking for FCGX_Accept() in -lfcgi... no
うーむ。半日くらい悩む。そうだgemを使わずに普通に入れてみよう。
wget http://sugi.nemui.org/pub/ruby/fcgi/ruby-fcgi-0.8.6.tar.gz tar xzvf ruby-fcgi-0.8.6.tar.gz cd ruby-fcgi-0.8.6 ruby install.rb config --without-ext ruby install.rb setup ruby install.rb install
--without-extをつけないと結局 gem と同じエラーだった。
config/lighttpd.conf を新しいものに更新して、 public/dispatch.fcgi の先頭のパスを書き換えて
script/server
動いた。
参考
[開発ログ]野良ビルド ruby 1.8.4 + gem + rails-1.1.2 on Debian のインストールに挑戦
混乱すると嫌なので apt-get したものをあらかじめ消しておく。
apt-get remove rake apt-get remove rails
/usr/share/rails/ が消滅していることを確認。
まず ruby 1.8.4 。
wget ftp://ftp.ruby-lang.org/pub/ruby/ruby-1.8.4.tar.gz tar xzvf ruby-1.8.4.tar.gz cd ruby-1.8.4 ./configure --prefix=/home/dan/ruby make make install
パスを通しておく。
PATH=~/ruby/bin:$PATH ; export PATH
動作確認。
ruby -v ruby 1.8.4 (2005-12-24) [i686-linux]
次に RubyGems 。
http://rubyforge.org/frs/download.php/5207/rubygems-0.8.11.tgz tar xzvf rubygems-0.8.11.tgz cd rubygems-0.8.11 ruby setup.rb
ここで問題発生。
/home/dan/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:21:in `require__': no such file to load -- zlib (LoadError) from /home/dan/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:21:in `require' from /home/dan/ruby/lib/ruby/site_ruby/1.8/rubygems/package.rb:9
うーむ。ruby-zlibが必要ぽい。
wget http://www.blue.sky.or.jp/atelier/ruby/ruby-zlib-0.6.0.tar.gz tar xzvf ruby-zlib-0.6.0.tar.gz cd ruby-zlib-0.6.0 ruby extconf.rb
すると、
checking for deflateReset() in -lz... no checking for deflateReset() in -llibz... no checking for deflateReset() in -lzlib... no *** extconf.rb failed *** Could not create Makefile due to some reason, probably lack of necessary libraries and/or headers. Check the mkmf.log file for more details.
うーむ。解決方法がわからなかった。仕方がないので、激しくダメなことのような気もするけど、
cp /usr/lib/ruby/1.8/i386-linux/zlib.so ~/ruby/lib/ruby/1.8/i686-linux/
と無理やりzlib.soのバイナリファイルをコピーして持ってきてから rubygems をインストール。
cd rubygems-0.8.11 ruby setup.rb
一応インストールは通過した。何か危険なことが起きているかもしれない。
追記(2006/8/18)
apt-get install zlib1g-dev
してから以下でOK。
cd ruby-zlib-0.6.0 ruby extconf.rb make make install
Rails
gem install rails Successfully installed rails-1.1.2 Successfully installed rake-0.7.1 Successfully installed activesupport-1.3.1 Successfully installed activerecord-1.14.2 Successfully installed actionpack-1.12.1 Successfully installed actionmailer-1.2.1 Successfully installed actionwebservice-1.1.2 Installing RDoc documentation for rake-0.7.1... Installing RDoc documentation for activesupport-1.3.1... Installing RDoc documentation for activerecord-1.14.2... Installing RDoc documentation for actionpack-1.12.1... Installing RDoc documentation for actionmailer-1.2.1... Installing RDoc documentation for actionwebservice-1.1.2...
10 分くらいかかったが無事終了。
rails test
で動作確認。
[開発ログ]rails 1.1
新サーバ(arton-pc とかくたにさんはよんでいた)にrailsを入れた。
apt-get install rails/unstable
一応動作したものの test で大量のエラー。railsのバージョンを上げるたびに test のエラーを消すのに一苦労。この際 svn head をとってきてエラーつぶしたほうがいい気も。
Ruby は 1.8.2 のまま。というのは野良ビルドした Ruby 1.8.4 を使うには rake とかを gem なりでインストールする必要があると思うんだけど、 gem はまだ導入してないので。
ところで 1.8.2 + rails ではダメというのは勉強会でも聞いたけど、具体的にどの部分がいけないんだろう。
[Ruby]Debian に Ruby をソースから入れようとしたが
wget ftp://ftp.ruby-lang.org/pub/ruby/ruby-1.8.4.tar.gz tar xzvf ruby-1.8.4.tar.gz cd ruby-1.8.4 ./configure
とすると、
checking build system type... i686-pc-linux-gnulibc1 checking host system type... i686-pc-linux-gnulibc1 checking target system type... i686-pc-linux-gnulibc1 checking for gcc... gcc checking for C compiler default output file name... configure: error: C compiler cannot create executables See `config.log' for more details.
ちょっと調べたが原因がわからず。
[開発ログ]DebianのRubyインストール先を確認
とりあえず、開発環境の方でソースからビルドして入れてみようかな思ったけど、その前にどこにインストールされているのか調べてみよう。
$ whereis ruby ruby: /usr/bin/ruby1.8 /usr/bin/ruby /usr/lib/ruby /usr/share/man/man1/ruby.1.gz
rubyの方はリンクになっている。
lrwxrwxrwx 1 root root 7 Nov 24 15:02 ruby -> ruby1.8 -rwxr-xr-x 1 root root 3504 Oct 1 2005 ruby1.8
/usr 以下にある *.rb を探してみると、
- /usr/lib/ruby/1.8/
- /usr/share/rails/
の二カ所で見つかる。 rails 関係のファイルは /usr/share/rails/ にインストールされ、それ以外は /usr/lib/ruby/1.8/ にある模様。
ということはソースから入れれば /usr/local/ 以下に ruby が入って、そっちの ruby を使うようにし、 rails はこのまま /usr/share/ 以下にあるものを使えばいいのではないだろうか。やってみよう。
[Ruby]どこまでDRY?
なんかこういうコードがDRYでない気がしてくるのですが。
@maxx = screen.w - @image.w @maxy = screen.h - @image.h @x = rand(@maxx) @y = rand(@maxy) @vx = rand(5) + 5 @vy = rand(5) + 5
じゃあこうするんですか?
[[:x, :w], [:y, :h]].each do |x, w| eval "@max#{x} = screen.#{w} - @image.#{w} @#{x} = rand(@max#{x}) @v#{x} = rand(5) + 5" end
うーむ。
[Ruby]例外が発生したとき END {} 内で場合分けするには
予期せぬ例外でメインの処理が中断したときに END {} 内の処理を場合分けしたくなった。そういえば test/unit ではどうなっているのだろうと調べると、[ruby-list:41927] にちょうどその話しが。
at_exit do unless $! || Test::Unit.run? exit Test::Unit::AutoRunner.run end end
なるほど。
気になったので、
begin aaa rescue NameError p $! ensure p $! end p $!
を実行すると、
#<NameError: undefined local variable or method `aaa' for main:Object> nil nil
となる。
__
あれ、この exit なんで呼んでいるんだろう?
exit Test::Unit::AutoRunner.run
[開発ログ]DebianでRailsを使うにあたって
今の開発環境は全て Debian の apt-get で構築したもの。
- ruby 1.8.2 (2005-04-11) [i386-linux]
- rails 1.0 (たぶん。rails のバージョンを見る方法がわからない)
勉強会でも 1.8.2 じゃなくて 1.8.4 にするものと聞いたので、 1.8.4 にしようと思うものの Debia がよくわからずどうしたらいいものか迷う。
[ruby-list:41909] を見たりもしながら、とりあえずソースからビルドしようかなと思うのだけど、普通にソースからインストールした場合、 今既に入っている ruby 1.8.2 との関係は大丈夫なのかしら。その辺がよくわからないのでとりあえず保留。
__
あと gem 使うかどうかって選択もあるのだけど、 apt-get との共存がどうなるかわからず怖いので gem は使わない方向でいこうかと。
Rails on Debian の最新情報をまとめているところないかな。
[栽培日誌]種まきと苗木購入
今年も忙しい時期がやってきた。先週おおざっぱな草刈りを行い、昨日苗を買ってきて植え付けた。
この写真には草を必要以上に刈り取らない自然農ぽさが良く出ている。
栽培日誌をはてなかどっかに移行したい。写真を貼りやすい所がいい。
種まき
写真は先週の月曜日に蒔いたもの。今年は多くの種でポッドに挑戦。でも先週雨が多すぎて種が腐ったかも。どうも土の粘土質が高くて水はけが悪い。
苗木
トマト、ナス、キュウリ。トマトとナスは自家製堆肥を先週入れたところに植え付け。キュウリは無肥料で。
写真はトマトの苗木。ここから枯れていくケースがしばしばあるので、目が離せない。たぶん原因は買ってきた苗が温室育ちだったりして弱く、環境の変化に耐えられないことがあるんじゃないかと。だから苗の選定は重要。
去年まで狭い庭にナス科(トマトとかピーマンもナス科)を多く植えていたから、今年はもうほとんど空きスペースが残ってない。ナス科は連作障害が起るから4,5年は同じ場所に植えられないのだ。
品種
今回買ったのはこれ。フジースーパーは扱っている絶対数が少ないけど、ちゃんと品種と生産地と生産者が明記されている。
島忠はその辺ほんとテキトーでダメ。
その他
- イチゴが花をつけている
- ブルーベリーはまだ反応がない
- 今頃去年まいたシュンギクが伸びてきて収穫期。ウマー
- パセリはもう食べ放題。地植は驚くほど大きくなるのでひと株で良かったな
- シソの自然発芽はまだなので苗木を一本買った
- なぜかネギの左の列だけネギ坊主が
- 小松菜のつぼみは伸びてくるけど最初のころほどは食べられない(やっぱり花を咲かせちゃうからかなあ)。種を採るぶんだけ残してもう刈り取ってよさそう
- 今年は虫の絶対数が少ない気がする。去年はあんなにテントウムシがいたのに。食害も皆無
- 秋にまいた大根を食べるのは3月までに。筋が多すぎ
- アスパラは最初の芽を伸ばしすぎた。こまめに収穫しないと
- そうそう、ミョウガが芽を出してきた
[開発ログ]サーバーマシンがやってきた
サーバーマシンが来るかもの続き。
昨日の夜artonさんから頂きました。とあるファミレスまでご足労頂き(ほんとうにありがとうございました)、直接PCを受け取ったのだけど、もう緊張したのなんの。別れた後も小一時間足がガクガクしてた。
幸運なことにファミレスであれこれお話することができた。自分がいまやっていることを一通り話し(mixi経由で日常フットサルと家庭菜園に明け暮れていることもバレバレだった)、ここぞとばかりに例の件を持ち出し、参考になるお話をいっぱい聞くことができた。タイミング良すぎ。
忘れてしまったこと。PCにサインを入れてもらうべきだった!帰りの車の中で気がついた……。くぅっ。あとASRやExerbに関して相談しておけば良かった……。トホホ。
とかなんとか考えながら家に帰ってPCを起動すると、説明の通りもうほんと理想的な状態でDebianのインストールと設定がなされていて、あとはRails関連さえ入れればいつでも投入OKという状態でした。というわけでサーバーPCのハード面については無事に準備完了しました。
HSPとRuby
もし自分がこれから何も知らないプログラミングをはじめるとして、目の前にHSPとRubyがあったら、100回中の99回はHSPに行くと思う(いやオレのことだから判断を誤ってRubyに行ってしまう確率は高そう……)。
不運にもRubyに行ってしまった場合は、プログラムを書けるようになる前に挫折しているんじゃないかと思う。だってゲーム作りたいだけだから。おそらくはRuby/SDLにたどり着くことは出来ないし、たどりつけてもモロモロの実行環境をインストールできない。最適な言語や処理系にたどり着くまで何度もトライできるかというと、すぐに頭から煙が出てしまうので無理。なんてダメなんだろう。
そういう意味ではやっぱりHSPが興味深いのです。
もちろん今後は大きく変わってくるところだと思います。RailsでRubyはじめる人も多くなるでしょうし。
__
よく考えてなかったけどホームページだけで判断したときの話かな。
[Ruby]ひさびさに拡張ライブラリの作り方を確認
http://www.namikilab.tuat.ac.jp/~sasada/prog/rb5.html あたりを見る。
__
こんなのどうだろう。
require 'c_eval' #def test n # n.times{} #end c_eval(" VALUE test(int n){ volatile int i; for(i=0;i<(FIX2INT(n));i++){ } return Qnil; } ") test 0x3ffffff
(c_eval って名前は置いとくとして) c_eval が与えられたコードをコンパイル(前回コンパイルした結果がないまたはコードが変化してれば)して require をする。拡張ライブラリはほとんど書いたことがないんだけど、こうして書けるとある局面では便利だったりするのかなあと思ったもので。
__
最近 Rails のせいで頭がメタメタ。
__
上のc_eval、同名のメソッドは起動後一回しかevalできない気がしてたけど、そんなことないんだよなあ。コードが変化してたらコンパイルしてrequireだから。
最近徐々にメタプログラミングがわかってきたので、これまでの考え方が崩壊しつつあります(なんか前にもそんなことあった気がするけど。脱皮かな)。そっかあ、みんなのRubyはこういうものだったんだね。なんかいろいろ納得。やっぱり最後は「そうではない。君が真に目覚めれば書くまでもない」なのだろうか。
[tDiary]ツッコミのCSS設定
ここの現在の CSS はすごーくシンプルで tDiary に特化した設定はほとんどやってなかったんだけど、ツッコミがどうも見にくいのでちょっと設定した。
/* comment */ div.comment { margin: 1em 0em; } div.commentshort { margin: 0.6em 0em; } div.commentshort p { margin: 0em 1em; } div.comment div.caption { font-weight: bold; } div.commentbody { margin: 1em; } span.commentator { margin: 0.4em 0em; font-weight: bold; } span.canchor { font-size: xx-small; } div.commentbody p { margin: 0em 1em; }
[MyGame]起動
test.rb
Image.draw('mglogo.bmp') loop_game
次のようにして起動。
ruby -r mygame/boot.rb test.rb
というのはどうなんだろう。 mygame/boot.rb は余計なものといえば余計なものなんだけど、でも便利な機能がないと結局は最初に使ってもらえないという話もあるし(というか他人に使ってもらうつもりだったのか?いつの日かある程度の形になったら [ANN] MyGame 0.0.1 ってゆう ML 投げられる?)。
なんでこうしたいかというと HSP をみるとやっぱり require ... とか include ... とか init ... とか MyGame:: ... とかが邪魔なものに見えてきてしまって、なんか負けている気が。 Ruby の柔軟さならたとえ HSP の土俵でも勝負出来るというのを試してみたくて。
HSP 3.0 は、
picload "HSP3TTL.JPG"
だけでよくなったのか。以前は最後に stop 必要だと思ったけど。 HSP だと自動的にスクリーンのサイズが画像のサイズに合うんだけど、あれかっこいいなあ。
mygame/boot.rb はこう書いてみた。
BEGIN { require 'mygame' include MyGame init_game }
最初 require 'mygame' を BEGIN の外に書いちゃったのだけど、そうすると BEGIN の中が先に実行されてしまうのだ(考えてみれば当然だけど)。 BEGIN 使ったのって Ruby を初めて使った頃以来だ。
いちおう書いておくと、test.rb を次のように書けば、
require 'mygame' include MyGame init_game 640, 480 Image.draw('mglogo.bmp') loop_game
スクリーンサイズその他、詳細な条件を設定した起動が可能だし、
ruby test.rb
で実行できます。
[MyGame]イベントのサンプル
require 'mygame' include MyGame init_game image = TImage.new('ball.bmp') x, y = 0, 0 add_event(:mouse_motion) {|event| x, y = event.x, event.y } loop_game do image.draw screen, x, y end
こうも書ける。
image = TImage.new('ball.bmp') add_event(:mouse_motion) {|event| image.x, image.y = event.x, event.y } loop_game do image.draw end
デフォルトでループ終了のイベントが2つ登録されている。
add_event(:quit, :cloase) { @@loop_end = true } add_event(:key_down, :cloase) {|e| @@loop_end = true if e.sym == SDL::Key::ESCAPE }
これらを取り除くにはこうする。
remove_event(:quit, :cloase) remove_event(:key_down, :cloase)
__
ちなみにイベント呼び出しはループ内でこう実装されている。
while event = SDL::Event2.poll event.class.name =~ /\w+\z/ name = $&.gsub(/([a-z])([A-Z])/) { "#{$1}_#{$2.downcase}" }.downcase (@@events[name.to_sym] || {}).each {|key, block| block.call(event) } end
[MyGame]画像表示のサンプル
こうなった。
require 'mygame' include MyGame init_game Image.new('ball.bmp').draw loop_game
mygame.rb の最後に
include MyGame init_game
と書いておくと、
require 'mygame' Image.new('ball.bmp').draw loop_game
こうなって HSP にかなり近づけるけど、これは反則か。
ちなみに上記は無理にシンプルに書くための極端な例。普通に書くとこう。
require 'mygame' include MyGame init_game image = Image.new('ball.bmp') loop_game do image.draw end
__
なかださんからツッコミを頂いていた。
Image.draw('ball.bmp') Image['ball.bmp'].draw
現状だと draw の引数は次のようになっていて(もちろん省略可能)、
Image#draw(screen, x, y)
第1引数は描画対象となるサーフェース、2,3は描画する座標。なので前者だとこの引数のスタイルに合わない。後者はこういう形をはじめてみたので違和感があるのですが……。こんなのあり?
追記:むむ、自分の言っていることがおかしかった。
draw_image('ball.bmp')
を
Image.draw('ball.bmp')
とするのに問題はないじゃないか。引数うんぬんの話は最初の draw_image も抱えていたことなわけで。
描画先のサーフェイスを指定するような込み入った場合は Image.new をすればいいのだから、ここではなかださんのおっしゃる Image.draw('ball.bmp') でよさそうだ。
イベント処理のメモ
@@events = {} x = 5 def add_event_quit(key=nil, &block) @@events[key || block.object_id] = block end add_event_quit { puts x+=1 } add_event_quit(:aaa) { puts x+=1 } def add_event_quit(arg) if arg.is_a? Proc @@events[arg.object_id] = arg else arg.each {|key, block| @@events[key] = block } end end add_event_quit lambda { puts x+=1 } add_event_quit :bbb => lambda { puts x+=1 } p @@events puts x @@events.each do |key, block| puts "key = #{key}" block.call end puts x
なるほど lambda ってこういうことか。まあここではブロック引数版のほうがよさそうだけど。 lambda 版のメリットは複数のイベントを一回のメソッド呼び出しで登録できるところ。
key を与えるのは remove_event のため。
[Ruby]文字列 "KeyDown" を "key_down" に変換するいい方法
(いい方法かどうかは別として)思いついた。
ruby -e 'p "AbcDefGhi".gsub(/([a-z])([A-Z])/) { "#{$1}_#{$2.downcase}" }.downcase' #=> "abc_def_ghi"
でも、
"AbcDEF"
とかの文字列が与えられたときの結果がちょっと違うかもしれない。
そういえば今程度の正規表現はなぜか Ruby を使う前から書けたなあ。 結構長いこと Perl 使ってたんだよな。考えてみると Ruby の使用歴より Ruby を知る前までの Perl の使用歴の方が2倍くらい長いぞ。でも Perl は全然身につかなかった。
クラスを使うか使わないか
簡易インターフェースを作るにあたってどっちがいいか。
draw_image('ball.bmp') Image.new('ball.bmp').draw
クラス版もそんなに馴染みにくくないんじゃないだろうか(オブジェクト思考をやったことのない人にとって)。慣れればクラス版の方が扱いやすいし。うーむ。オブジェクト思考をよく知らない人にも馴染めるものがいいのだけど。あ、これってRubyの「十分に慣れた人にとって使いやすい」と方向性が違うな。
前者は、 ball.bmp を表示する命令を実行。
後者は、 ball.bmp を読み込んだ画像オブジェクトを作成して、それに描画するよう指示。(こっちは2段階だな。)
後者は、 ball.bmp を表示する処理。画像オブジェクトを作って、それを描画。(とか。)
ネームスペース
require 'mygame' MyGame::init screen = MyGame::Screen.new(320, 240) MyGame::loop do exit if MyGame::key_press?(MyGame::Key::ESCAPE) MyGame::draw_image screen, 'ball.bmp', 100, 50 end
うわあ MyGame:: ウザッ。
require 'mygame' include MyGame game_init screen = Screen.new(320, 240) game_loop do exit if key_press?(Key::ESCAPE) draw_image screen, 'ball.bmp', 100, 50 end
とすればいいかなあ。
いままでよく考えずに screen を使っていたけど、これサーフェイスだから描画命令が書き込むサーフェイスを screen に固定してしまえばよりシンプルにできる。
require 'mygame' include MyGame game_init 320, 240 game_loop do exit if key_press?(Key::ESCAPE) x = (screen.w - image_size('ball.bmp').w) / 2 y = (screen.h - image_size('ball.bmp').h) / 2 draw_image 'ball.bmp', x, y end
とした方がいいかな。 screen メソッドも用意しておく。
サーフェイスを指定する場合はこれで。
draw_surface_image surface 'ball.bmp', 100 50
ここでは関係ない話だけどこう書きたくなってくる。
require 'mygame' include MyGame game_init 320, 240 ball = Image.new('ball.bmp') ball.x = (screen.w - ball.w) / 2 ball.y = (screen.h - ball.h) / 2 game_loop do exit if key_press?(Key::ESCAPE) ball.draw end
Ruby/SDL のサウンド処理を簡易化
ライブラリ名は mygame にしようかな。
Ruby/SDL による wav ファイル再生のサンプル。
require 'sdl' SDL::init SDL::INIT_AUDIO|SDL::INIT_VIDEO SDL.setVideoMode 320,240,16,SDL::SWSURFACE SDL::Mixer.open wave = SDL::Mixer::Wave.load("sample.wav") ch = 0 loops = 0 SDL::Mixer.playChannel(ch ,wave, loops) while SDL::Mixer::play?(0) sleep 1 end
これは簡単だ。ただ playChannel の引数の順番は変えた方がいいかも。第2引数の wave は必須なので先頭に、 loop 回数指定は経験上必要になったことがないので一番後ろに。
game_loop do play_wave "sample.wav" end
チャンネルとループ回数は省略可能。
画像と同じで wave は内部でキャッシュする。ループの前であらかじめロードしておく機能があってもいいだろう。リソース解放機能も。
load_wave "sample.wav" game_loop do play_wave "sample.wav" end clear_wave "sample.wav" clear_wave_all
イベント処理をラップ (2)
昨日のイベント処理をメソッドとして定義する案を書いて、すぐにあれでは使いにくいことに気づいた。例えばマウスカーソルの位置にボールを表示する場合。簡単にはマウスの座標をループ内の x, y に伝えられないのだ。
def event_mousemotion(event) event.x # あれ、どうしよう…… event.y end game_init screen = Screen.new(SCREEN_W, SCREEN_H) x, y = 0, 0 game_loop do draw_image screen, 'ball.bmp', x, y end
じゃあ結局ループ内でマウスイベントをポーリングする仕組みのほうがいいか。ループ内に毎回判定を書くの実は好きなんだけど、もっといい方法がありそうだ。
game_loop do if event_mousemotion? x = event_mouse_x y = event_mouse_x end draw_image screen, 'ball.bmp', x, y end
こんな書き方はできないのだろうか。というかこれできるんじゃないの?
x, y = 0, 0 add_event_mousemotion {|event| x, y = event.x, event.y } game_loop do draw_image screen, 'ball.bmp', x, y end
とりあえず簡単な実装。おおうまくいく。ブロックというか proc ってほとんど使ったことなかったけどこうやって使うんだ。なるほど。
def add_event_mousemotion(&block) $event_blocks << block end require 'sdl' SDL.init SDL::INIT_VIDEO screen = SDL.setVideoMode(320, 240, 16, SDL::SWSURFACE) $event_blocks = [] x, y = 0, 0 add_event_mousemotion { puts "MouseMotion" } add_event_mousemotion {|event| x, y = event.x, event.y } loop do while event = SDL::Event2.poll case event when SDL::Event2::Quit exit when SDL::Event2::MouseMotion $event_blocks.each {|block| block.call event } end end puts x, y sleep 1.0 / 60 end
--
いやあ、やっぱりRubyのパワーすごい。今まで Ruby での GUI のゲームはあんまり手を着けてなかったんだけど、 Ruby + Ruby/SDL かなり面白いかも。
[開発ログ]サーバーマシンが来るかも
arton さんから嬉しいお話が。ありがとうございます。
慣れないヤフオクに入札したら、IRCに夢中になっているうちに制限時間が終わっていて競い忘れちゃったし、もう古いマシンを立て直すパーツ集めて復旧させるのも面倒だから新品マシン買ってしまえ!とか考え初めていたのだけど。
いやあよかったよかった。でも Dual マシンなんていじったことないよ。ドキドキ。
「rubyco(るびこ)の日記」のもくじを作るのはどうか
rubyco さんの日記は自分が Ruby の勉強をするのに役立つので、手動でリンク集的なものを作ろうと思い、作り出して、あっさり挫折。とりあえず各記事の名前と URL だけは機械的に抽出したほうがよさそう。ということで、下記スクリプトで読み込んでWiki にはっておいた。うは、すごくいっぱいある……。
require 'net/http' $KCODE = 'euc' def perse_page(path, address, port=80) result = [] response = nil Net::HTTP.version_1_2 Net::HTTP.start(address, port) do |http| response = http.request_get( path ) end response.body.scan(/<h3>.+<\/h3>/).reverse.each do |line| if line.gsub(/<span[^>].+>.+<\/span>/, '') =~ /href="([^"]+)"[^<]+<\/a>(.+)<\/h3>/ path = $1 name = $2.gsub(/<[^>]+>/, '') result << [name, path] end end result end address = 'd.hatena.ne.jp' id = 'rubyco' (2006..2006).each do |year| (1..12).each do |month| path = "/#{ id }/#{ year }%02d" % month puts "!!#{ path }" perse_page(path, address).each do |name, path| puts "*[[#{ name }|http://#{ address }#{ path }]]" end end end
イベント処理をラップ
この Ruby/SDL のイベント処理。どうラップするのがいいか。
loop do while event = SDL::Event2.poll case event when SDL::Event2::Quit exit when SDL::Event2::KeyDown puts 'A' if event.sym == SDL::Key::A end end end
こんなのはどうだろうか。
def event_quit(event) exit end def event_key_down(event) puts 'A' if event.sym == SDL::Key::A end game_init screen = Screen.new(SCREEN_W, SCREEN_H) game_loop do # ループ内の処理 end
ためしに実装。
def event_quit(event) exit end def event_keydown(event) puts 'A' if event.sym == SDL::Key::A puts 'SPACE' if event.sym == SDL::Key::SPACE end def event_mousemotion(event) p event.x p event.y end require 'sdl' SDL.init SDL::INIT_VIDEO screen = SDL.setVideoMode(320, 240, 16, SDL::SWSURFACE) loop do while event = SDL::Event2.poll name = "event_#{ event.class.to_s.match(/\w+\z/)[0].downcase }" begin __send__ name, event rescue NoMethodError puts "undefined method `#{ name }'" end end end
文字列 "KeyDown" を "key_down" に変換するいい方法ないかな。
疑問点がひとつ。
def event_keydown(event) aaa() end
とすると、
rescue NoMethodError
につかまる。
しかし、 aaa() の () をとるとと NameError が発生。
def event_keydown(event) aaa end test.rb:6:in `event_keydown': undefined local variable or method `aaa' for main: Object (NameError) from test.rb:23 from test.rb:19
ん、そうかこれはこれでいいか。
けど、
def event_keydown(event) aaa() end
の場合の NoMethodError はここの rescue で捕らえたくないんだけどどう実装すればいいのだろう。
[Ruby]exerbとRuby1.8.4コア同梱のActiveScriptRuby 1.8.4.2 リリース
これはすごくうれしい。初心者にRuby環境を紹介する場合にASRは「ruby console」があるからパスの設定が不要なのも魅力的だったし。さらにExerbも同梱されていやあ便利です。言ってみるものだなあ。
Ruby/SDL を簡易ライブラリ化
(RDスタイルに戻した。日をまたがないと切り替わらないのでしかたなく明日のエントリに書いている)
よく使う処理をシンプルなインターフェースに簡略化するならどんな形がよいか。
なんとなくの全体イメージ。
game_init game_loop do # 処理 # 描画 end
スクリーン生成
game_init screen = Screen.new(SCREEN_W, SCREEN_H) #screen = create_screen(SCREEN_W, SCREEN_H)
画像表示
この画像表示をラップするとしたらどういうインターフェースにするか。
image = SDL::Surface.load('ball.bmp') image = image.displayFormat image.setColorKey SDL::SRCCOLORKEY, image.getPixel(0,0) SDL.blitSurface image, 0, 0, 0, 0, screen, x, y
クラス版
もっとも自然。
image = Igame.new(screen, 'ball.bmp') image.x = x image.y = y game_loop do image.draw end
シンプルなラッパー版
思ったよりいいかも。非オブジェクト指向。
image = create_image('ball.bmp') game_loop do draw_image screen, image, x, y end
命令タイプ
毎回 SDL::Surface.load から作り直す。非現実的。
game_loop do draw_image screen, 'ball.bmp', x, y end
いやキャッシュすればいいからオブジェクト指向を避けるならありか。なんか良く見えてきた。
これを使ってクラスを書くのもあり。
class Ball def initialize(screen, x=0, y=0) @screen = screen @x = x @y = y end def run @x += 1 end def draw draw_image @screen, 'ball.bmp', @x, @y end end
うん、いいかも。実際は initialize を基底クラスに分離かな。
game_init screen = Screen.new(SCREEN_W, SCREEN_H) balls = Array.new(10) { Ball.new(screen, rand(SCREEN_W), rand(SCREEN_H)) } game_loop do balls.each do |ball| ball.run ball.draw end end
これ balls の生成が複雑だなもっと単純化できないものか。
balls = [] 10.times { balls << Ball.new(screen, rand(SCREEN_W), rand(SCREEN_H)) }
うーん。
balls = [] 10.times do balls << Ball.new(screen, rand(SCREEN_W), rand(SCREEN_H)) end
うーん。
balls = (0...10).map { Ball.new(screen, rand(SCREEN_W), rand(SCREEN_H)) }
最初の Array.new(10) が良く見えてきた。
あと each って難しいよね。オレ自身ブロックつきメソッドを理解したの最近だし。
balls.size.times do |i| ball[i].run ball[i].draw end
結局ブロックつきメソッドなんだけど。for は一回も書いたことないなあ。これでいいのかな。
for ball in balls ball.run ball.draw end
for は Rails でしか見たことない。 times は最近はなんか変な感じするけど、最初のころはすごくなじみやすかった覚えがある。each は最初ぜんぜんわからなかったけどすぐに慣れた(使う分には)。 for は C と違いすぎてぜんぜんなじまなかった。あ、 C とか他の言語を知らない人には for はいいのかも。
SDL IRC に参加
http://risky-safety.org/zinnia/sdl/irc.html
思ったよりたくさんの方がいらっしゃって楽しそうです。
今日から記法を「RDスタイル」から「Hatenaスタイル」に変更してみました。リンクの仕方がわかりません。
Exerb ではまる(2)
こっちのノートPC(Windows XP SP1)で昨日の手順で ball.exe を作成すると、このマシン上でも起動できない。
まず exe 以前にRuby/SDLを使おうとするとこの2つが見つからないといわれた。
- msvcr71.dll
- msvcp71.dll
これを探してきて ball.rb は動くようになった。
次に exe を作成してこれを実行すると、
sdl.rb:17:in `require': Win32API Error #5 --- アクセスが拒否されました。 (Exerb::RuntimeError) from sdl.rb:17
というエラー。この行は ruquire 'sdl.so' をしているところ。
Ruby/SDL が 1.8.4 対応で Exerb コアが 1.8.2 なんだけどその辺の問題なのだろうか。 Windows プログラミングはほとんどやったことがなくてさっぱりわからない。このあたりもこれから勉強していかないと。
[tDiary]はてなスタイルのテスト
テスト。
あれリンクの書き方が違う?例を示そうと思ってプレ記法使おうをしたら固まるぞ。むむむ。