LeverDashMan
「アクションゲームアルゴリズムマニアックス」っつー本がある。
話のタネにと思ってずっと前に買ったのだが例によってそのまま積んであった。
タイトルの通り、アクションゲームにありそーなアルゴリズムについて片っ端から説明とサンプルコードが書いてある。
ありそーなって言うか、そのほとんどはかなり古いアイデア一発ゲー時代のものを取り上げているのだから、どっかで見たことあるものばっかりだ。
これをDXRubyで作ったらどうなるかなー、と思って、試してみた。
画像はサンプルのものを縮小加工した。元は縮小描画していたが、それだと何かと面倒・不便だ。DXRubyは4点指定で縮小回転描画を自由にできるようには作っていない。
色は面倒だったから画像をそのまま(白で描かれている)。サンプルの実行ファイルは白黒反転していて、これはテクスチャの色を黒で単色塗りつぶし描画しているためだ。これもDXRubyには無い。
んで、コードの方は元がC++なのを、なるべくそのまま保つように努力してみた。
サンプルのフレームワークまでそのまま移植する価値は感じられないから簡略化した。サンプルコードになっている部分(サンプルでいうStage1.hのところ、クラスで言えばLeverDashMan、StaticFloor、StaticTree、LeverDashStage)はほぼそのままのクラス構成、アルゴリズムとなっている。
どっちかと言うとこれをRubyっぽく書き直すとどうなるか、というのが気にはなるが、そもそも俺は「Rubyっぽいコード」は書けないから無茶な話だ。誰か書いてみて。
あと、絵はサンプルを加工したものだから、それを含んで公開することはできない。
require 'dxruby' Window.width = 800 Window.height = 600 MAX_X = 16 MAX_Y = 12 class Task @@tasklist = [] def initialize @@tasklist << self end def self.list @@tasklist end def draw Window.draw(@x * Window.width / MAX_X, @y * Window.height / MAX_Y, @image) end end class Game def initialize(stage) @stage = stage.new end def move @stage.move Task.list.delete_if {|obj| obj.move} end def draw Task.list.each {|obj| obj.draw} end end class LeverDashMan < Task attr_reader :vx @@image = Image.load("texture/man.png") MAX_SPEED = 0.5 ACCEL = 0.01 def initialize @x = 3 @y = MAX_Y - 2 @vx = 0.1 @image = @@image super end def move if Input.key_down?(K_RIGHT) @vx += ACCEL elsif Input.key_down?(K_LEFT) @vx -= ACCEL else @vx -= ACCEL * 0.5 end @vx = 0 if @vx < 0 @vx = MAX_SPEED if @vx > MAX_SPEED @angle = @vx / MAX_SPEED * 0.1 return false end def draw Window.draw_rot(@x * Window.width / MAX_X, @y * Window.height / MAX_Y, @image, 360 * @angle) end end class StaticFloor < Task attr_accessor :x @@image = Image.load("texture/floor.png") def initialize(x) @x = x @y = MAX_Y - 1 @image = @@image super() end def move @x += MAX_X + 1 if @x <= -1 return false end end class StaticTree < Task attr_accessor :x @@image = Image.load("texture/tree.png") def initialize @x = MAX_X + 3 @y = MAX_Y - 4 @image = @@image super end def move return @x <= -3 end end class LeverDashStage def initialize @man = LeverDashMan.new (0..16).each do |x| StaticFloor.new(x) end @dist = 0 end def move Task.list.each do |obj| obj.x -= @man.vx if !obj.is_a?(LeverDashMan) end @dist -= @man.vx if @dist < 0 StaticTree.new @dist = rand * MAX_X end end end game = Game.new(LeverDashStage) Window.loop do game.move game.draw end