ふみふみ

@ゲーム制作

ちょっとだけ光、あれ。
標準のSpriteクラスに素直に差し替え。Window.draw_tileでマップ描画。
次は敵&操作可能オブジェクトも表示して、地形共々衝突判定へ、戦闘っぽいの実装してから、
大まかなシステムの構成を探っていきます。


require 'dxruby'

# @todo
# - 描画関連はその内分離
# - 向き・歩行アニメ、武器を振る、ジャンプ
# - 敵・衝突・戦闘 

class TaskForce
  def initialize
    @tasks = []
  end
  def add(task)
    @tasks << task
  end
  def delete(task)
    @tasks.delete(task)    
  end
  def delete_if(&block) ; @tasks.delete_if(&block) ; end  # { |t| !t.update }
  def sort ; ; end
  def run
    Sprite.update(@tasks)
    Sprite.draw(@tasks)
  end
  def clean_sprite ; Sprite.clean ; end
end

module Task
  def task_init
    @priority = 0
    @task_id = nil
    @active = @visible = true
  end
end

module Animation
  def animation_init(image = nil)
    @anime_index = 2
    return unless image
    @image_tiles = image
    @image_tiles[@anime_index]
  end
end

class Actor < Sprite
  include Task
  def initialize(res)
    image = res[:image][:chara][@task_id]
    if image
      if image.is_a?(Array)
        extend Animation
        image = animation_init(image)
     end
    else
      # 空もしくは空画像を生成予定
      self.visible = false
    end
    super(0, 0, image)
  end
  def update ; @active ; end
end

class Player < Actor
  def initialize(res)
    @task_id = :kukumaru
    super
    self.scale_x = self.scale_y = 3
    self.x = Window.width / 2 - self.image.width / 2
    self.y = Window.height / 1.5 - self.image.height / 2
  end
  def update
    unless @routine
      @routine = Fiber.new {
        loop {
          self.x += Input.x * 2
          self.y += Input.y * 2
          Fiber.yield
        }
      }
    end
    @routine.resume
  end
end

class Map
  include Task
  def initialize(res)
    @image_array = res[:image][:map][:mapchip]
    @map_data = [
      [5,5,5,5,5,5,0,3,3,3,3,3,3,0,5,5,5,5,5,5],
      [5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5],
      [5,0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,5],
      [5,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,5],
      [5,0,0,0,0,0,0,0,2,1,1,2,0,0,0,0,0,0,0,5],
      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0],
      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
      [0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0],
      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
      [5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5],
      [5,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,5],
      [5,0,4,0,0,0,0,0,0,0,0,4, 0,0,0,0,0,0,0,5],
      [5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,5],
      [5,5,5,5,5,5,0,0,0,0,0,0,0,0,5,5,5,5,5,5]
    ]
    @base_x = @base_y = @start_x = @start_y = 0
    @size_x, @size_y = 20, 15
    @z = 0
  end
  def draw
    Window.draw_tile(@base_x, @base_y, @map_data, @image_array, 
     @start_x, @start_y, @size_x, @size_y, @z)
  end
end

module Game
  def self.start
    Game::Base.new.play
  end
  class Base
    def initialize(*opt)
      Window.caption = "九々。"
      Window.mag_filter = TEXF_POINT
      @task_force = TaskForce.new
      @res = {image: {}, data: {}}

      load_resource
    end
    RESOURCE_DATA = {
      chara: {x: 4, y: 1},
      map: {x: 3, y: 2}
    } 
    def load_resource
      RESOURCE_DATA.each { |type, v|
        buff = @res[:image][type] = {}
        Dir.glob("img/#{type}/*.png") { |f|
          buff[File.basename(f, ".*").to_sym] = Image.load_tiles(f, v[:x], v[:y]).freeze
          buff.freeze
        }
      }
    end

    def ready
      Fiber.new {
        @task_force.add(Map.new(@res))
        @task_force.add(Player.new(@res))
          loop {
            @task_force.run
            Fiber.yield
        }
      }
    end
    def play
      @routine = ready
      Window.loop { @routine.resume }
    end
  end
end