にしへ
衝突判定(Sprite.check)入れて、デバッグやイベントコールバック関連を組み込み始めたり。
明日はドット素材の補給のターン。互いの勢いを阻害せずに上手いこと回して行かねば。
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(system) Sprite.update(@tasks) task_size = @tasks.size - 1 col_flag = false 0.upto(task_size) { |i| (i+1).upto(task_size) { |j| col_flag = true if Sprite.check(@tasks[i], @tasks[j]) } } Sprite.draw(@tasks) system[:debug_text]["Shoooooooot!!!!!"] if col_flag # system[:debug_map_no].call end def clean_sprite ; Sprite.clean ; end end module Task def task_init( id: nil, priority: 0, visible: true, **opt) @task_id, @priority = id, priority @active, @visible = true, visible end end module Animation def animation_init(image = nil) return unless image @image_tiles = image self.image = @image_tiles[@anime_index = 0] end def anime_size @image_tiles.size end def anime_frame(index) # return if index < 0 || index >= anime_size @anime_index = index self.image = @image_tiles[@anime_index] end end class Actor < Sprite include Task def initialize(res, **opt) task_init(**opt) image = res[:image][opt[:image]][@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 def move(x, y) self.x, self.y = x, y self end end class Player < Actor def initialize(res) @task_id = :kukumaru super(res, id: :kukumaru, image: :chara) 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 anime_frame(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 def hit(target) # p "hit to #{target}" end def shot(target) # p "shot to #{target}" end end class Enemy < Actor def initialize(res) super(res, id: :enemy, image: :enemy) 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 anime_frame(rand(@image_tiles.size)) end end class Artifact < Actor end class Map include Task WIDTH, HEIGHT = 20, 15 SIZE = 32 # 16*2 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 class Event def initialize @events = {} end def add(name, listener) @events[name] = [] unless @events[name] @events[name] << listener end def delete(name, listener = nil) if @events[name] unless listener @events[name].clear else @events[name].delete(listener) end end end def clear ; @events.clear ; end def trigger(name) @events[name] or @events[name].each(&:call) 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: {}} @debug_font_max = Font.new(40, "", weight: true, italic: true) @debug_font_min = Font.new(12, "") @system = { event: Event.new, debug_text: proc {|text, x = 5, y = 5| Window.draw_font(x, y, text, @debug_font_max) }, debug_map_no: proc { Map::WIDTH.times { |x| Map::HEIGHT.times { |y| Window.draw_font(x*Map::SIZE, y*Map::SIZE, "#{y*Map::WIDTH+x}", @debug_font_min) } } } } load_resource end RESOURCE_DATA = { chara: {x: 4, y: 1}, map: {x: 3, y: 2}, enemy: {x: 7, y: 1} } 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(Enemy.new(@res).move(320-64, 224)) @task_force.add(Enemy.new(@res).move(320+48, 224) ) @task_force.add(Player.new(@res)) loop { screen_shot @task_force.run(@system) Fiber.yield } } end def screen_shot Window.get_screen_shot("screen_shot#{Time.now.to_i}.png", FORMAT_PNG) if Input.key_push?(K_S) end def play @routine = ready Window.loop { @routine.resume } end end end