2013/12/08(日) [n年前の日記]
#1 [dxruby][game] DXRubyを使って星を飛ばしてみる
今日も DXRuby を使って何か書いてみますよ。そろそろ自分の中でネタ切れ感がありますけど…。
今回は、星をたくさん飛ばしてみようかと。今風のソレでカッコよく言うと、パーティクル処理…ってこのレベルでそんな呼び方をしたら、なんだか怒られそうな気もしますが…。
まずは単純に、等速度運動で飛ばしてみました。
やってることは、星一つ分を表示するクラスを作って、大量に発生させてるだけです。
2Dゲームなら、この動きでも十分と言えば十分、ではあるのですけど…。例えば…。
でも、ちょっと欲が出てきました。もう少し、一工夫してみようかなと。
とりあえず、座標計算だけは3Dにしてみたりして。
ちなみに、DXRuby のサンプルスクリプト中にも、3D計算をしていて、もっと見た目がカッコイイ、flight.rb というサンプルがありますので、そちらのほうが参考になりそうな気もします。
flight.rb って、一目見ただけで、「アレが…作れそう!」と思うサンプルですよね…。眺めてるだけで、夢がひろがりんぐ。
さておき。「3D計算ってどうやればいいの?」と疑問を持つ方も居るかもしれないので、一応念のために説明図も置いときます。真横から見たらこうなるよ、という図になってます。…3D計算というか、透視投影? 透視変換? ですね。
3D空間上のx,y,z座標値と、カメラ位置から画面までの距離を使って、画面上のx,y座標を求めたい ―― 図で言えば sy を求めたいわけですけど、こんな感じで求められますよ、と。
「カメラ位置から画面までの距離って、どんな値を決めておけばいいの?」と思われる方も居るのかな…。どうせ2Dゲームで使う予定ですし、見た目がそれっぽくなればOKなので、テキトーな値でいいです。
や、広角だの望遠だの焦点距離だのを意識して、真面目に各値を算出するのもアリなんですけど。所詮はゲームなので、見た目が大事じゃないのかなと。アレコレ正確な値よりも、見た時にイケてるかどうかが大事、と自分は思ってまして。…アニメの作画と似たノリがあるような気もします。それでカッコよくなるならインチキ上等! みたいな。
ところで、この星達。遠くの星も、近くの星も、描画画像の大きさが同じなので、なんだか今一つですね…。
一応、z座標値に基づいて、大きさを変えてみましょうかね。
や。もっとさりげなく変わるかなーと思って処理を追加したけど、予想外の結果に。こんなはずでは…。まあ、これはこれで、派手だから良し。カッコよければ、なんでもOK。
updateメソッドの中で、「scale = @@scrz / self.rz」という行がありますが、ここでスケールを変えてます。変数 scale に、0.5 とか 0.25 とか掛けてあげれば、もっとさりげない見た目になるはずです。
ということで、今回は星をたくさん飛ばしてみました。一応、画像とソースを置いときますね。Public Domain ってことで。
_movestar.zip
ちなみに。
Unity には標準でパーティクルシステムがついていて、プログラムをわざわざ書かなくても、GUIで各パラメータを調整していけるのでした…。しかも、当然3Dで動くし…。ギャフン。
_Unity - パーティクル アニメータ(旧パーティクルシステム)
_Unity - パーティクルシステム(Shuriken)
でも、見るからに、操作方法を習得するのが大変そうですな…。もちろん、習得すれば、複雑なパーティクルを出せるのでしょうけど。
アプリ配布時の容量や、メモリ消費量で特に問題が無いなら、この手のソレを画像で丸々持ってしまって済ませちゃうのもアリかもですね。パーティクルを使って画像生成するソフトを紹介しておきます。
_Prominence
_発色弾
_Detonation
_パーティクリン
これらソフトで画像を作って、その画像を今回のような方法で描画するのも全然アリです。ますますド派手な画面が作れるのではないかなと。
今回は、星をたくさん飛ばしてみようかと。今風のソレでカッコよく言うと、パーティクル処理…ってこのレベルでそんな呼び方をしたら、なんだか怒られそうな気もしますが…。
まずは単純に、等速度運動で飛ばしてみました。
# 星を飛ばす。単純な等速度運動 require 'dxruby' # 星一つ分のSprite class Star < Sprite attr_accessor :dx, :dy, :rx, :ry, :cx, :cy # 初期化処理 def initialize(cx, cy, img) super self.cx = cx self.cy = cy self.image = img self.init end # 座標初期化処理 def init self.rx = self.cx # 発生位置を設定 self.ry = self.cy rad = rand(360) * Math::PI / 180.0 # 乱数で角度を得る speed = rand(6) + 2 # 乱数で速度を得る self.dx = speed * Math.cos(rad) # sin と cos を使って、速度x,yを求める self.dy = speed * Math.sin(rad) end # 毎フレーム呼ばれる処理 def update # 速度を加算 self.rx += self.dx self.ry += self.dy # 描画座標を設定。画像の中心を基準位置にしてる self.x = self.rx - self.image.width / 2 self.y = self.ry - self.image.height / 2 if self.rx < 0 or self.rx > Window.width or self.ry < 0 or self.ry > Window.height # 画面外に飛び出したら座標や速度を再初期化 self.init end end end img = Image.load("star.png") # 発生位置。画面の右上のほうに設定 cx = Window.width * 0.75 cy = Window.height * 0.25 sprs = [] 64.times do sprs.push(Star.new(cx, cy, img)) # 星を発生させて配列に登録 end # メインループ Window.loop do break if Input.keyPush?(K_ESCAPE) Sprite.update(sprs) Sprite.draw(sprs) endまた長くなった…。もっとシンプルに書けないのかな…。
やってることは、星一つ分を表示するクラスを作って、大量に発生させてるだけです。
- 星は、速度を持っていて、毎フレーム、自分の座標に速度を足して、それぞれ勝手に(?)動きます。
- 星の飛んでいく方向や、星の飛んでいく速度は、乱数で求めています。
- 画面外に出たら、発生位置、方向、速度を初期化します。
2Dゲームなら、この動きでも十分と言えば十分、ではあるのですけど…。例えば…。
- 発生位置を広げてみたり。
- 発生タイミングを揃えてみたり。
- 速度を変えてみたり。
- 星の画像がアニメをするようにしてみたり。
でも、ちょっと欲が出てきました。もう少し、一工夫してみようかなと。
とりあえず、座標計算だけは3Dにしてみたりして。
# 星を飛ばす。座標だけ3D計算 require 'dxruby' # 星一つ分のSprite class Star < Sprite attr_accessor :rx, :ry, :rz, :cx, :cy @@scrz = 200 # 画面までの距離 @@dz = -2.5 # z座標の速度 @@w = 256 # 星の発生範囲 # 初期化処理 def initialize(cx, cy, img) super self.cx = cx self.cy = cy self.image = img self.init end # 座標初期化処理 def init self.rx = rand(@@w) - (@@w / 2) # 発生位置を設定 self.ry = rand(@@w) - (@@w / 2) self.rz = rand(256) + 10 end # 毎フレーム呼ばれる処理 def update # 速度を加算 self.rz += @@dz # 画面のこちら側に飛び出してたら座標を初期化 self.init if self.rz <= 0.0 # 描画座標を算出 px = self.rx * @@scrz / self.rz py = self.ry * @@scrz / self.rz self.x = self.cx + px - self.image.width / 2 self.y = self.cy + py - self.image.height / 2 if self.x < 0 or self.x > Window.width or self.y < 0 or self.y > Window.height # 画面外に飛び出したら座標や初期化 self.init end end end img = Image.load("star.png") # 発生位置。画面の右上のほうに設定 cx = Window.width * 0.75 cy = Window.height * 0.25 sprs = [] 64.times do sprs.push(Star.new(cx, cy, img)) # 星を発生させて配列に登録 end # メインループ Window.loop do break if Input.keyPush?(K_ESCAPE) Sprite.update(sprs) Sprite.draw(sprs) endうーん。GIFアニメのフレームレートが低くて、パッと見では、違いが分かりづらいかなあ…。16FPSでは、こうなっちゃうか…。実際に、DXRubyのウインドウ上で、60FPSで眺めると、印象が随分違うのですけど…。まあ、いいや。
ちなみに、DXRuby のサンプルスクリプト中にも、3D計算をしていて、もっと見た目がカッコイイ、flight.rb というサンプルがありますので、そちらのほうが参考になりそうな気もします。
flight.rb って、一目見ただけで、「アレが…作れそう!」と思うサンプルですよね…。眺めてるだけで、夢がひろがりんぐ。
さておき。「3D計算ってどうやればいいの?」と疑問を持つ方も居るかもしれないので、一応念のために説明図も置いときます。真横から見たらこうなるよ、という図になってます。…3D計算というか、透視投影? 透視変換? ですね。
「カメラ位置から画面までの距離って、どんな値を決めておけばいいの?」と思われる方も居るのかな…。どうせ2Dゲームで使う予定ですし、見た目がそれっぽくなればOKなので、テキトーな値でいいです。
や、広角だの望遠だの焦点距離だのを意識して、真面目に各値を算出するのもアリなんですけど。所詮はゲームなので、見た目が大事じゃないのかなと。アレコレ正確な値よりも、見た時にイケてるかどうかが大事、と自分は思ってまして。…アニメの作画と似たノリがあるような気もします。それでカッコよくなるならインチキ上等! みたいな。
ところで、この星達。遠くの星も、近くの星も、描画画像の大きさが同じなので、なんだか今一つですね…。
一応、z座標値に基づいて、大きさを変えてみましょうかね。
# 星を飛ばす。座標だけ3D計算 require 'dxruby' # 星一つ分のSprite class Star < Sprite attr_accessor :rx, :ry, :rz, :cx, :cy @@scrz = 200 # 画面までの距離 @@dz = -2.5 # z座標の速度 @@w = 256 # 星の発生範囲 # 初期化処理 def initialize(cx, cy, img) super self.cx = cx self.cy = cy self.image = img self.init end # 座標初期化処理 def init self.rx = rand(@@w) - (@@w / 2) # 発生位置を設定 self.ry = rand(@@w) - (@@w / 2) self.rz = rand(256) + 10 end # 毎フレーム呼ばれる処理 def update # 速度を加算 self.rz += @@dz # 画面のこちら側に飛び出してたら座標を初期化 self.init if self.rz <= 0.0 # 描画座標を算出 px = self.rx * @@scrz / self.rz py = self.ry * @@scrz / self.rz self.x = self.cx + px - self.image.width / 2 self.y = self.cy + py - self.image.height / 2 # 大きさを変えてみる scale = @@scrz / self.rz self.scale_x = scale self.scale_y = scale if self.x < 0 or self.x > Window.width or self.y < 0 or self.y > Window.height # 画面外に飛び出したら座標や初期化 self.init end end end img = Image.load("star.png") # 発生位置。画面の右上のほうに設定 cx = Window.width * 0.75 cy = Window.height * 0.25 sprs = [] 64.times do sprs.push(Star.new(cx, cy, img)) # 星を発生させて配列に登録 end # メインループ Window.loop do break if Input.keyPush?(K_ESCAPE) Sprite.update(sprs) Sprite.draw(sprs) endうむ。ド派手になった。
や。もっとさりげなく変わるかなーと思って処理を追加したけど、予想外の結果に。こんなはずでは…。まあ、これはこれで、派手だから良し。カッコよければ、なんでもOK。
updateメソッドの中で、「scale = @@scrz / self.rz」という行がありますが、ここでスケールを変えてます。変数 scale に、0.5 とか 0.25 とか掛けてあげれば、もっとさりげない見た目になるはずです。
ということで、今回は星をたくさん飛ばしてみました。一応、画像とソースを置いときますね。Public Domain ってことで。
_movestar.zip
ちなみに。
Unity には標準でパーティクルシステムがついていて、プログラムをわざわざ書かなくても、GUIで各パラメータを調整していけるのでした…。しかも、当然3Dで動くし…。ギャフン。
_Unity - パーティクル アニメータ(旧パーティクルシステム)
_Unity - パーティクルシステム(Shuriken)
でも、見るからに、操作方法を習得するのが大変そうですな…。もちろん、習得すれば、複雑なパーティクルを出せるのでしょうけど。
アプリ配布時の容量や、メモリ消費量で特に問題が無いなら、この手のソレを画像で丸々持ってしまって済ませちゃうのもアリかもですね。パーティクルを使って画像生成するソフトを紹介しておきます。
_Prominence
_発色弾
_Detonation
_パーティクリン
これらソフトで画像を作って、その画像を今回のような方法で描画するのも全然アリです。ますますド派手な画面が作れるのではないかなと。
[ ツッコむ ]
以上です。