擬似3D再び
手元のDXRuby1.5.0devにMatrix/VectorとSpriteの追加機能を実装してみたので、昔やってた擬似3Dの計算をするSpriteを作ってみた。
require 'dxruby' class Sprite3D < Sprite attr_accessor :v def self.set_transform(sw, sh, zn, zf) @@view = Matrix.new([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [-sw/2, -sh/2, zn, 1]]) @@proj = Matrix.new([[2.0 * zn / sw, 0, 0, 0], [0, 2.0 * zn / sh, 0, 0], [0, 0, zf / (zf - zn), 1], [0, 0, -zn * zf / (zf - zn), 0]]) @@vp = Matrix.new([[ sw / 2, 0, 0, 0], [ 0, sh / 2, 0, 0], [ 0, 0, -1, 0], [ sw / 2, sh / 2, 0, 1]]) @@zn = zn end def initialize(v, image) @v = v self.image = image self.offset_x = nil self.offset_y = nil end def update temp = Vector.new(@v.x, @v.y, @v.z, 1) * @@view * @@proj self.scale_x = self.scale_y = @@zn / temp.w self.xyz = temp / temp.w * @@vp end end Sprite3D.set_transform(640, 480, -300, -5000) objects = Array.new(10) { Sprite3D.new(Vector.new(0, 0, 0), Image.new(200, 200, [rand()*255, rand()*255, rand()*255])) } y_angle = 0 Window.loop do y_angle += 2 objects.each_with_index do |s, i| s.v = Vector.new(800, 0, 0) * Matrix.rotation_y(i * 36 + y_angle) * Matrix.rotation_x(-10) + Vector.new(320, 240, -1000) end Sprite.update(objects) Sprite.draw(objects) break if Input.key_push?(K_ESCAPE) end
座標は1点の指定になるから画像の中心点と定義して、xyzのVectorをv=で設定してやると3Dのパースを計算して描画する。パースについてはSprite3D.set_transformであらかじめ設定しておく。zが0の時に等倍になるようにview行列に細工がしてある。zのソートと同様に、奥にいくほどマイナスの値になる。
空間内を移動するような擬似3Dゲーを作るにはカメラの移動とかをサポートしないといけないのでこのままではダメだが、なんとなく雰囲気はつかめる。