From 6f9b00ffb568a0dc87b9e73eee9290cc1e1a07c3 Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Sat, 30 Mar 2019 13:29:30 -0500 Subject: [PATCH] Improvements to GameObject and friends --- lib/cyberarm_engine/common.rb | 50 +++++++ lib/cyberarm_engine/engine.rb | 4 + lib/cyberarm_engine/game_object.rb | 129 ++++++------------ lib/cyberarm_engine/game_state.rb | 46 ++++++- .../objects/multi_line_text.rb | 8 ++ lib/cyberarm_engine/ui/gui_state.rb | 2 + 6 files changed, 150 insertions(+), 89 deletions(-) diff --git a/lib/cyberarm_engine/common.rb b/lib/cyberarm_engine/common.rb index 34a199f..0ac664b 100644 --- a/lib/cyberarm_engine/common.rb +++ b/lib/cyberarm_engine/common.rb @@ -28,6 +28,56 @@ module CyberarmEngine $window.draw_rect(x,y,width,height,color,z) end + def fill(color, z = 0) + draw_rect(0, 0, $window.width, $window.height, color, z) + end + + def lighten(color, amount = 25) + if defined?(color.alpha) + return Gosu::Color.rgba(color.red+amount, color.green+amount, color.blue+amount, color.alpha) + else + return Gosu::Color.rgb(color.red+amount, color.green+amount, color.blue+amount) + end + end + + def darken(color, amount = 25) + if defined?(color.alpha) + return Gosu::Color.rgba(color.red-amount, color.green-amount, color.blue-amount, color.alpha) + else + return Gosu::Color.rgb(color.red-amount, color.green-amount, color.blue-amount) + end + end + + def get_asset(path, hash, klass) + asset = nil + hash.detect do |_asset, instance| + if _asset == path + asset = instance + true + end + end + + unless asset + instance = klass.new(path) + hash[path] = instance + asset = instance + end + + return asset + end + + def get_image(path) + get_asset(path, Engine::IMAGES, Gosu::Image) + end + + def get_sample(path) + get_asset(path, Engine::SAMPLES, Gosu::Sample) + end + + def get_song(path) + get_asset(path, Engine::SONGS, Gosu::Song) + end + def window $window end diff --git a/lib/cyberarm_engine/engine.rb b/lib/cyberarm_engine/engine.rb index 75426b5..aec1e32 100644 --- a/lib/cyberarm_engine/engine.rb +++ b/lib/cyberarm_engine/engine.rb @@ -1,5 +1,9 @@ module CyberarmEngine class Engine < Gosu::Window + IMAGES = {} + SAMPLES= {} + SONGS = {} + attr_accessor :show_cursor attr_reader :current_state, :last_frame_time diff --git a/lib/cyberarm_engine/game_object.rb b/lib/cyberarm_engine/game_object.rb index 4ff1191..8636832 100644 --- a/lib/cyberarm_engine/game_object.rb +++ b/lib/cyberarm_engine/game_object.rb @@ -1,39 +1,43 @@ module CyberarmEngine class GameObject - INSTANCES = [] - IMAGES = {} - SAMPLES= {} - attr_accessor :image, :x, :y, :z, :angle, :center_x, :center_y, :scale_x, :scale_y, - :color, :alpha, :mode, :options, :paused, :radius, :last_x, :last_y - attr_reader :world_center_point + include Common + + attr_accessor :image, :angle, :position, :velocity, :center_x, :center_y, :scale_x, :scale_y, + :color, :alpha, :mode, :options, :paused, :radius, :last_position def initialize(options={}) if options[:auto_manage] || options[:auto_manage] == nil - INSTANCES.push(self) - $window.current_game_state.add_game_object(self) + $window.current_state.add_game_object(self) end @options = options @image = options[:image] ? image(options[:image]) : nil - @x = options[:x] ? options[:x] : 0 - @y = options[:y] ? options[:y] : 0 - @z = options[:z] ? options[:z] : 0 - @last_x = 0 - @last_y = 0 + x = options[:x] ? options[:x] : 0 + y = options[:y] ? options[:y] : 0 + z = options[:z] ? options[:z] : 0 + @position = Vector.new(x, y, z) + @velocity = Vector.new + @last_position = Vector.new @angle = options[:angle] ? options[:angle] : 0 + @center_x = options[:center_x] ? options[:center_x] : 0.5 @center_y = options[:center_y] ? options[:center_y] : 0.5 + @scale_x = options[:scale_x] ? options[:scale_x] : 1 @scale_y = options[:scale_y] ? options[:scale_y] : 1 + @color = options[:color] ? options[:color] : Gosu::Color.argb(0xff_ffffff) @alpha = options[:alpha] ? options[:alpha] : 255 @mode = options[:mode] ? options[:mode] : :default + @paused = false @speed = 0 @debug_color = Gosu::Color::GREEN @world_center_point = Vector.new(0,0) + setup - @debug_text = MultiLineText.new("", color: @debug_color, y: self.y-(self.height*self.scale), z: 9999) - @debug_text.x = self.x + + @debug_text = MultiLineText.new("", color: @debug_color, y: @position.y-(self.height*self.scale), z: 9999) + @debug_text.x = @position.x if @radius == 0 || @radius == nil @radius = options[:radius] ? options[:radius] : defined?(@image.width) ? ((@image.width+@image.height)/4)*scale : 1 end @@ -41,12 +45,12 @@ module CyberarmEngine def draw if @image - @image.draw_rot(@x, @y, @z, @angle, @center_x, @center_y, @scale_x, @scale_y, @color, @mode) + @image.draw_rot(@position.x, @position.y, @position.z, @angle, @center_x, @center_y, @scale_x, @scale_y, @color, @mode) end if $debug - show_debug_heading if $heading - $window.draw_circle(self.x, self.y, radius, 9999, @debug_color) + show_debug_heading + $window.draw_circle(@position.x, @position.y, radius, 9999, @debug_color) if @debug_text.text != "" $window.draw_rect(@debug_text.x-10, (@debug_text.y-10), @debug_text.width+20, @debug_text.height+20, Gosu::Color.rgba(0,0,0,200), 9999) @debug_text.draw @@ -57,49 +61,10 @@ module CyberarmEngine def update end - def image(image_path) - image = nil - GameObject::IMAGES.detect do |img, instance| - if img == image_path - image = instance - true - end - end - - unless image - instance = Gosu::Image.new(image_path) - GameObject::IMAGES[image_path] = instance - image = instance - end - - return image - end - - def sample(sample_path) - sample = nil - GameObject::SAMPLES.detect do |smp, instance| - if smp == sample_path - sample = instance - true - end - end - - unless sample - instance = Gosu::Sample.new(sample_path) - GameObject::SAMPLES[sample_path] = instance - sample = instance - end - - return sample - end - def debug_text(text) @debug_text.text = text - end - - def update_debug_text - @debug_text.x = self.x-(@debug_text.width/2) - @debug_text.y = self.y-((self.height)*self.scale) + @debug_text.x = @position.x-(@debug_text.width / 2) + @debug_text.y = @position.y-(@debug_text.height + self.radius + self.height) end def scale @@ -117,16 +82,6 @@ module CyberarmEngine self.radius = ((@image.width+@image.height)/4)*self.scale end - def x=(i) - @last_x = @x - @x = i - end - - def y=(i) - @last_y = @y - @y = i - end - def visible true # if _x_visible @@ -151,17 +106,18 @@ module CyberarmEngine end def heading(ahead_by = 100, object = nil, angle_only = false) - direction = ((Gosu.angle(@last_x, @last_y, self.x, self.y)) - 90.0) * (Math::PI / 180.0) - ahead_by+object.speed*Engine.dt if object - _x = @x+(ahead_by*Math.cos(direction)) - _y = @y+(ahead_by*Math.sin(direction)) + direction = Gosu.angle(@last_position.x, @last_position.x, @position.x, position.y).gosu_to_radians + + _x = @position.x + (ahead_by * Math.cos(direction)) + _y = @position.y + (ahead_by * Math.sin(direction)) + return direction if angle_only return Vector.new(_x, _y) unless angle_only end def show_debug_heading _heading = heading - $window.draw_line(x, y, @debug_color, _heading.x, _heading.y, @debug_color, 9999) + Gosu.draw_line(@position.x, @position.y, @debug_color, _heading.x, _heading.y, @debug_color, 9999) end def width @@ -232,14 +188,14 @@ module CyberarmEngine # Duplication... so DRY. def each_circle_collision(object, resolve_with = :width, &block) if object.class != Class && object.instance_of?(object.class) - $window.current_game_state.game_objects.select {|i| i.class == object.class}.each do |o| + $window.current_state.game_objects.select {|i| i.class == object.class}.each do |o| distance = Gosu.distance(self.x, self.y, object.x, object.y) if distance <= self.radius+object.radius block.call(o, object) if block end end else - list = $window.current_game_state.game_objects.select {|i| i.class == object} + list = $window.current_state.game_objects.select {|i| i.class == object} list.each do |o| next if self == o distance = Gosu.distance(self.x, self.y, o.x, o.y) @@ -251,32 +207,31 @@ module CyberarmEngine end def destroy - INSTANCES.delete(self) - if $window.current_game_state - $window.current_game_state.game_objects.each do |o| + if $window.current_state + $window.current_state.game_objects.each do |o| if o.is_a?(self.class) && o == self - $window.current_game_state.game_objects.delete(o) + $window.current_state.game_objects.delete(o) end end end end # NOTE: This could be implemented more reliably - def self.all + def all INSTANCES.select {|i| i.class == self} end def self.each_circle_collision(object, resolve_with = :width, &block) if object.class != Class && object.instance_of?(object.class) - $window.current_game_state.game_objects.select {|i| i.class == self}.each do |o| + $window.current_state.game_objects.select {|i| i.class == self}.each do |o| distance = Gosu.distance(o.x, o.y, object.x, object.y) if distance <= o.radius+object.radius block.call(o, object) if block end end else - lista = $window.current_game_state.game_objects.select {|i| i.class == self} - listb = $window.current_game_state.game_objects.select {|i| i.class == object} + lista = $window.current_state.game_objects.select {|i| i.class == self} + listb = $window.current_state.game_objects.select {|i| i.class == object} lista.product(listb).each do |o, o2| next if o == o2 distance = Gosu.distance(o.x, o.y, o2.x, o2.y) @@ -289,10 +244,10 @@ module CyberarmEngine def self.destroy_all INSTANCES.clear - if $window.current_game_state - $window.current_game_state.game_objects.each do |o| + if $window.current_state + $window.current_state.game_objects.each do |o| if o.is_a?(self.class) - $window.current_game_state.game_objects.delete(o) + $window.current_state.game_objects.delete(o) end end end diff --git a/lib/cyberarm_engine/game_state.rb b/lib/cyberarm_engine/game_state.rb index 2a7426a..2428748 100644 --- a/lib/cyberarm_engine/game_state.rb +++ b/lib/cyberarm_engine/game_state.rb @@ -10,6 +10,8 @@ module CyberarmEngine @game_objects = [] @global_pause = false + @down_keys = {} + setup end @@ -24,18 +26,58 @@ module CyberarmEngine @game_objects.each(&:update) end + def draw_bounding_box(box) + x,y, max_x, max_y = box.x, box.y, box.max_x, box.max_y + + color = Gosu::Color.rgba(255, 127, 64, 240) + + # pipe = 4 + # Gosu.draw_rect(x-width, y-height, x+(width*2), y+(height*2), color, Float::INFINITY) + # puts "BB render: #{x}:#{y} w:#{x.abs+width} h:#{y.abs+height}" + # Gosu.draw_rect(x, y, x.abs+width, y.abs+height, color, Float::INFINITY) + + # TOP LEFT to BOTTOM LEFT + $window.draw_line( + x, y, color, + x, max_y, color, + Float::INFINITY + ) + # BOTTOM LEFT to BOTTOM RIGHT + $window.draw_line( + x, max_y, color, + max_x, max_y, color, + Float::INFINITY + ) + # BOTTOM RIGHT to TOP RIGHT + $window.draw_line( + max_x, max_y, color, + max_x, y, color, + Float::INFINITY + ) + # TOP RIGHT to TOP LEFT + $window.draw_line( + max_x, y, color, + x, y, color, + Float::INFINITY + ) + end + def destroy - @options = nil - @game_objects = nil + @options.clear + @game_objects.clear end def button_down(id) + @down_keys[id] = true + @game_objects.each do |o| o.button_down(id) end end def button_up(id) + @down_keys.delete(id) + @game_objects.each do |o| o.button_up(id) end diff --git a/lib/cyberarm_engine/objects/multi_line_text.rb b/lib/cyberarm_engine/objects/multi_line_text.rb index f1252b1..976c027 100644 --- a/lib/cyberarm_engine/objects/multi_line_text.rb +++ b/lib/cyberarm_engine/objects/multi_line_text.rb @@ -28,6 +28,13 @@ module CyberarmEngine end def text=(text) + + if text.lines.count < @texts.count + range = ((@texts.count - @text.lines.count)-1)..@texts.count-1 + p range + @texts.slice!(range) + end + text.split("\n").each_with_index do |line, i| if @texts[i] @texts[i].text = line @@ -36,6 +43,7 @@ module CyberarmEngine end end + self.y = @y calculate_boundry end diff --git a/lib/cyberarm_engine/ui/gui_state.rb b/lib/cyberarm_engine/ui/gui_state.rb index 6c5660b..0cacd5f 100644 --- a/lib/cyberarm_engine/ui/gui_state.rb +++ b/lib/cyberarm_engine/ui/gui_state.rb @@ -8,6 +8,8 @@ module CyberarmEngine @game_objects = [] @global_pause = false + @down_keys = {} + @root_container = Stack.new @game_objects << @root_container @containers = [@root_container]