From 9ab515dce2d5b00ba4b39bb0ab2bf07f4b1f36c3 Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Fri, 11 Oct 2019 20:01:35 -0500 Subject: [PATCH] Entities are now definable --- i-mic-rts.rb | 1 - lib/entities/construction_worker.rb | 11 +++++ lib/entities/harvester.rb | 34 +++++++++++++++ lib/entities/power_plant.rb | 15 +++++++ lib/entity.rb | 66 ++++++++++++++++++++++++++--- lib/map.rb | 4 ++ lib/player.rb | 1 + lib/states/game.rb | 8 ++-- 8 files changed, 129 insertions(+), 11 deletions(-) create mode 100644 lib/entities/construction_worker.rb create mode 100644 lib/entities/harvester.rb create mode 100644 lib/entities/power_plant.rb diff --git a/i-mic-rts.rb b/i-mic-rts.rb index 45ad04e..80f2f07 100755 --- a/i-mic-rts.rb +++ b/i-mic-rts.rb @@ -26,7 +26,6 @@ require_relative "lib/states/menus/multiplayer_lobby_menu" require_relative "lib/zorder" require_relative "lib/entity" -# require_relative "lib/entities/" require_relative "lib/map" require_relative "lib/tiled_map" diff --git a/lib/entities/construction_worker.rb b/lib/entities/construction_worker.rb new file mode 100644 index 0000000..2d8c15b --- /dev/null +++ b/lib/entities/construction_worker.rb @@ -0,0 +1,11 @@ +IMICRTS::Entity.define_entity(:construction_worker, :unit, 1000, "Constructs buildings") do |entity| + entity.radius = 14 + entity.movement = :ground + entity.max_health = 100.0 + + entity.body_image = "vehicles/construction_worker/images/construction_worker.png" + entity.shell_image = "vehicles/construction_worker/images/construction_worker.png" + + entity.on_tick do + end +end diff --git a/lib/entities/harvester.rb b/lib/entities/harvester.rb new file mode 100644 index 0000000..1128add --- /dev/null +++ b/lib/entities/harvester.rb @@ -0,0 +1,34 @@ +IMICRTS::Entity.define_entity(:harvester, :unit, 1400, "Harvests ore") do |entity, director| + entity.radius = 10 + entity.movement = :ground + entity.max_health = 100.0 + + entity.body_image = "vehicles/harvester/images/harvester.png" + entity.shell_image = "vehicles/harvester/images/harvester.png" + + @capacity = 10.0 + @bed = 0.0 + + entity.on_tick do + if @bed >= @capacity + entity.seek_refinery + else + entity.seek_ore + end + end + + entity.define_singleton_method(:seek_ore) do + ore = director.map.ores.compact.sort_by { |ore| next unless ore; ore.position.distance(entity.position) }.first + + n = (ore.position - entity.position).normalized + n.z = 0 + entity.position += n * 3 + end + + entity.define_singleton_method(:seek_refinery) do + end + + entity.define_singleton_method(:rotate_towards) do |target| + entity.angle = Gosu.angle(target.x, target.y, entity.position.x, entity.position.y) + end +end diff --git a/lib/entities/power_plant.rb b/lib/entities/power_plant.rb new file mode 100644 index 0000000..40153da --- /dev/null +++ b/lib/entities/power_plant.rb @@ -0,0 +1,15 @@ +IMICRTS::Entity.define_entity(:power_plant, :building, 800, "Generates power") do |entity| + entity.radius = 14 + entity.max_health = 100.0 + + entity.body_image = "vehicles/power_plant/images/power_plant.png" + entity.shell_image = "vehicles/power_plant/images/power_plant.png" + + entity.on_tick do + entity.produce_power + end + + define_singleton_method(:produce_power) do + @player.power += 10 + end +end diff --git a/lib/entity.rb b/lib/entity.rb index d0f0db1..a47ac38 100644 --- a/lib/entity.rb +++ b/lib/entity.rb @@ -1,11 +1,27 @@ class IMICRTS class Entity - attr_reader :player, :id, :position, :angle, :radius, :target, :state - def initialize(player:, id:, manifest: nil, images:, position:, angle:) + Stub = Struct.new(:name, :type, :cost, :description, :setup) + @entities = {} + + def self.get(name) + @entities.dig(name) + end + + def self.define_entity(name, type, cost, description, &block) + if entity = get(name) + raise "#{name.inspect} is already defined!" + else + @entities[name] = Stub.new(name, type, cost, description, block) + end + end + + attr_reader :player, :id, :name, :type + attr_accessor :position, :angle, :radius, :target, :state, + :movement, :health, :max_health, + :turret + def initialize(name:, player:, id:, position:, angle:, director:) @player = player @id = id - @manifest = manifest - @images = images @position = position @angle = angle @@ -13,7 +29,14 @@ class IMICRTS @target = nil @state = :idle - # process_manifest + if entity = Entity.get(name) + @name = entity.name + @type = entity.type + + entity.setup.call(self, director) + else + raise "Failed to find entity #{name.inspect} definition" + end @goal_color = Gosu::Color.argb(175, 25, 200, 25) @target_color = Gosu::Color.argb(175, 200, 25, 25) @@ -25,6 +48,22 @@ class IMICRTS def deserialize end + def body_image=(image) + @body_image = Gosu::Image.new("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true) + end + + def shell_image=(image) + @shell_image = Gosu::Image.new("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true) + end + + def turret_body_image=(image) + @turret_body_image = Gosu::Image.new("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true) + end + + def turret_shell_image=(image) + @turret_shell_image = Gosu::Image.new("#{IMICRTS::ASSETS_PATH}/#{image}", retro: true) + end + def target=(entity) @target = entity end @@ -42,11 +81,20 @@ class IMICRTS end def draw - @images.draw_rot(@position.x, @position.y, @position.z, @angle) + @body_image.draw_rot(@position.x, @position.y, @position.z, @angle) + @shell_image.draw_rot(@position.x, @position.y, @position.z, @angle, 0.5, 0.5, 1, 1, @player.color) end def update - rotate_towards(@target) if @target + rotate_towards(@target) if @target && @movement + end + + def tick(tick_id) + @on_tick.call if @on_tick + end + + def on_tick(&block) + @on_tick = block end def selected_draw @@ -84,4 +132,8 @@ class IMICRTS @angle %= 360.0 end end +end + +Dir.glob("#{IMICRTS::GAME_ROOT_PATH}/lib/entities/*.rb").each do |entity| + require_relative entity end \ No newline at end of file diff --git a/lib/map.rb b/lib/map.rb index c758f87..87e9d7f 100644 --- a/lib/map.rb +++ b/lib/map.rb @@ -2,6 +2,7 @@ class IMICRTS class Map Tile = Struct.new(:position, :color, :image, :state, :type) + attr_reader :tiles, :ores def initialize(map_file:) @tiled_map = TiledMap.new(map_file) @@ -19,6 +20,9 @@ class IMICRTS end end end + + @tiles.freeze + @ores.freeze end def add_terrain(x, y, tile_id) diff --git a/lib/player.rb b/lib/player.rb index 5ea412b..1848b4d 100644 --- a/lib/player.rb +++ b/lib/player.rb @@ -17,6 +17,7 @@ class IMICRTS end def tick(tick_id) + @entities.each { |ent| ent.tick(tick_id) } end def update diff --git a/lib/states/game.rb b/lib/states/game.rb index 1ef3dea..2738b1f 100644 --- a/lib/states/game.rb +++ b/lib/states/game.rb @@ -8,7 +8,7 @@ class IMICRTS @selected_entities = [] - @debug_info = CyberarmEngine::Text.new("", y: 10, z: Float::INFINITY) + @debug_info = CyberarmEngine::Text.new("", y: 10, z: Float::INFINITY, shadow_color: Gosu::Color.rgba(0, 0, 0, 200)) @sidebar = stack(height: 1.0) do background [0x55555555, 0x55666666] @@ -19,18 +19,20 @@ class IMICRTS @buttons = stack(width: 75) do @h = button("Harvester", width: 1.0) do @player.entities << Entity.new( + name: :harvester, + director: @director, player: @player, id: @player.next_entity_id, - images: Gosu::Image.new("#{ASSETS_PATH}/vehicles/harvester/images/harvester.png", retro: true), position: CyberarmEngine::Vector.new(rand(window.width), rand(window.height), ZOrder::GROUND_VEHICLE), angle: rand(360) ) end @c = button("Construction Worker", width: 1.0) do @player.entities << Entity.new( + name: :construction_worker, + director: @director, player: @player, id: @player.next_entity_id, - images: Gosu::Image.new("#{ASSETS_PATH}/vehicles/construction_worker/images/construction_worker.png", retro: true), position: CyberarmEngine::Vector.new(rand(window.width), rand(window.height), ZOrder::GROUND_VEHICLE), angle: rand(360) )