From e5579f48f1bf1f3305c423739205b05220b447cf Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Tue, 17 Dec 2019 15:40:26 -0600 Subject: [PATCH] Added building component, refactored components to have setup, draw, update and tick methods, added fencing for building construction area parimeter, misc other changes. --- assets/fencing/fencing.png | Bin 0 -> 218 bytes assets/fencing/fencing_edge.png | Bin 0 -> 217 bytes assets/svg/fencing/fencing.svg | 135 ++++++++++++++++++++ assets/svg/fencing/fencing_edge.svg | 112 ++++++++++++++++ lib/component.rb | 27 ++++ lib/components/build_queue.rb | 4 +- lib/components/building.rb | 95 ++++++++++++++ lib/components/movement.rb | 9 +- lib/components/sidebar_actions.rb | 4 +- lib/components/turret.rb | 4 +- lib/entities/buildings/barracks.rb | 1 + lib/entities/buildings/construction_yard.rb | 1 + lib/entities/buildings/helipad.rb | 1 + lib/entities/buildings/power_plant.rb | 2 + lib/entities/buildings/refinery.rb | 2 + lib/entities/buildings/war_factory.rb | 1 + lib/entity.rb | 23 ++-- lib/friendly_hash.rb | 5 +- lib/tools/place_entity.rb | 2 +- 19 files changed, 404 insertions(+), 24 deletions(-) create mode 100644 assets/fencing/fencing.png create mode 100644 assets/fencing/fencing_edge.png create mode 100644 assets/svg/fencing/fencing.svg create mode 100644 assets/svg/fencing/fencing_edge.svg create mode 100644 lib/components/building.rb diff --git a/assets/fencing/fencing.png b/assets/fencing/fencing.png new file mode 100644 index 0000000000000000000000000000000000000000..545b12b43956f183e28d865b26426a9c2a84e1a4 GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmSQK*5Dp-y;YjHK@;M7UB8wRq z_>O=u<5X=vX`rBFiEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0xFo-U3d z5v^}89^`B=5OBG;K1VysVVekNm`caomI-Z1h9^%-eS5Hn?cafh4j?%3{_gp!%D35a ze%iQQ=`hv$W7rUNOGvQX|1d*Iqh3eKfoSjB%8%Zy^k;u6cI=5UcOcLT22WQ%mvv4F FO#mIPN=^U( literal 0 HcmV?d00001 diff --git a/assets/fencing/fencing_edge.png b/assets/fencing/fencing_edge.png new file mode 100644 index 0000000000000000000000000000000000000000..ab53d2267b603dc62f02903f61f68f3d84c5f00e GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmSQK*5Dp-y;YjHK@;M7UB8wRq z_>O=u<5X=vX`rBFiEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0vvo-U3d z5v^~p9pr3q5OBU|zw7UtlU^=wZqAB1X7uRc@+S7i2})C5+sUu0Uczv|Q9N3JLBXMc zfsu)YLqI`+zhmwtOZ5wu2PCXNG;;xk1a3EOy~h24@jo}$`L~M?JO=7qMEn2% literal 0 HcmV?d00001 diff --git a/assets/svg/fencing/fencing.svg b/assets/svg/fencing/fencing.svg new file mode 100644 index 0000000..e9c48c3 --- /dev/null +++ b/assets/svg/fencing/fencing.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/assets/svg/fencing/fencing_edge.svg b/assets/svg/fencing/fencing_edge.svg new file mode 100644 index 0000000..506fcd3 --- /dev/null +++ b/assets/svg/fencing/fencing_edge.svg @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/lib/component.rb b/lib/component.rb index cec2908..3973a62 100644 --- a/lib/component.rb +++ b/lib/component.rb @@ -15,6 +15,33 @@ class IMICRTS @@components[name] = klass end end + + attr_reader :parent + def initialize(parent:) + @parent = parent + + setup + end + + def data + @parent.data + end + + def data=(key, value) + @parent.data[key] = value + end + + def setup + end + + def draw + end + + def update + end + + def tick(tick_id) + end end end diff --git a/lib/components/build_queue.rb b/lib/components/build_queue.rb index 7d7ae8d..25e26d4 100644 --- a/lib/components/build_queue.rb +++ b/lib/components/build_queue.rb @@ -1,9 +1,7 @@ class IMICRTS class BuildQueue < Component Item = Struct.new(:entity, :progress) - def initialize(parent:) - @parent = parent - + def setup @queue = [] end diff --git a/lib/components/building.rb b/lib/components/building.rb new file mode 100644 index 0000000..38f52cc --- /dev/null +++ b/lib/components/building.rb @@ -0,0 +1,95 @@ +class IMICRTS + class Building < Component + def setup + data.construction_progress ||= 0 + data.construction_goal ||= 100 + + @text = CyberarmEngine::Text.new("", y: @parent.position.y, z: Float::INFINITY, size: 12) + data.state = :construct # deconstruct, building, idle + end + + def draw + case data.state + when :construct + draw_construction unless @text.text.empty? + @text.text = "Building: #{(construction_progress * 100.0).round}%" + @text.x = @parent.position.x - @text.width / 2 + @text.draw + when :deconstruct + when :building + when :idle + else + raise "Unknown state!" + end + end + + def update + case data.state + when :construct + @parent.color.alpha = 255 * construction_progress + data.state = :idle if construction_complete? + end + end + + def construction_complete? + data.construction_progress >= data.construction_goal + end + + # WARNING: returns a floating point number, not network safe! + def construction_progress + data.construction_progress.to_f / data.construction_goal + end + + def construction_work(work) + raise TypeError, "Got a non integer value!" unless work.is_a?(Integer) + + data.construction_progress += work + data.construction_progress = data.construction_goal if construction_complete? + end + + def draw_construction + @fencing ||= Gosu::Image.new(IMICRTS::ASSETS_PATH + "/fencing/fencing.png") + @fencing_edge ||= Gosu::Image.new(IMICRTS::ASSETS_PATH + "/fencing/fencing_edge.png") + + tiles = [] + each_tile(@parent.position / @parent.director.map.tile_size) do |tile, data, x, y| + tiles << tile + end + + tiles.each do |tile| + # X + if tiles.find { |t| t.grid_position.x < tile.grid_position.x && t.grid_position.y == tile.grid_position.y} == nil + @fencing_edge.draw(tile.position.x - 30, tile.position.y, Float::INFINITY) + end + if tiles.find { |t| t.grid_position.x > tile.grid_position.x && t.grid_position.y == tile.grid_position.y} == nil + @fencing_edge.draw(tile.position.x, tile.position.y, Float::INFINITY) + end + # Y + if tiles.find { |t| t.grid_position.x == tile.grid_position.x && t.grid_position.y < tile.grid_position.y} == nil + @fencing.draw(tile.position.x, tile.position.y - 24, Float::INFINITY) + end + if tiles.find { |t| t.grid_position.x == tile.grid_position.x && t.grid_position.y > tile.grid_position.y} == nil + @fencing.draw(tile.position.x, tile.position.y, Float::INFINITY) + end + end + end + + def each_tile(vector, &block) + if tile = @parent.director.map.tile_at(vector.x, vector.y) + ent = Entity.get(@parent.name) + origin = (tile.grid_position - 2) + + ent.tiles.each_with_index do |array, y| + array.each_with_index do |space_required, x| + next unless space_required.is_a?(TrueClass) + + other_tile = @parent.director.map.tile_at(origin.x + x, origin.y + y) + if other_tile + block.call(other_tile, space_required, origin.x + x, origin.y + y) + end + end + end + end + end + end +end \ No newline at end of file diff --git a/lib/components/movement.rb b/lib/components/movement.rb index 94c79bf..314964d 100644 --- a/lib/components/movement.rb +++ b/lib/components/movement.rb @@ -1,8 +1,13 @@ class IMICRTS class Movement < Component attr_accessor :pathfinder - def initialize(parent:) - @parent = parent + + def update + if pathfinder && pathfinder.path_current_node + rotate_towards(pathfinder.path_current_node.tile.position + @parent.director.map.tile_size / 2) + end + + follow_path end def rotate_towards(vector) diff --git a/lib/components/sidebar_actions.rb b/lib/components/sidebar_actions.rb index 1d7d468..6a1c99f 100644 --- a/lib/components/sidebar_actions.rb +++ b/lib/components/sidebar_actions.rb @@ -3,9 +3,7 @@ class IMICRTS Action = Struct.new(:label, :image, :description, :block) attr_reader :actions - def initialize(parent:) - @parent = parent - + def setup @actions = [] end diff --git a/lib/components/turret.rb b/lib/components/turret.rb index ccb2d3b..f235926 100644 --- a/lib/components/turret.rb +++ b/lib/components/turret.rb @@ -1,9 +1,7 @@ class IMICRTS class Turret < Component attr_accessor :angle, :center - def initialize(parent:) - @parent = parent - + def setup @angle = 0 @center = CyberarmEngine::Vector.new(0.5, 0.5) end diff --git a/lib/entities/buildings/barracks.rb b/lib/entities/buildings/barracks.rb index 29ffbac..9d717be 100644 --- a/lib/entities/buildings/barracks.rb +++ b/lib/entities/buildings/barracks.rb @@ -7,6 +7,7 @@ tiles = [ ] IMICRTS::Entity.define_entity(:barracks, :building, 400, "Builds and soldiers", tiles) do |entity| + entity.has(:building) entity.has(:build_queue) entity.radius = 44 diff --git a/lib/entities/buildings/construction_yard.rb b/lib/entities/buildings/construction_yard.rb index ab05f06..dedb78c 100644 --- a/lib/entities/buildings/construction_yard.rb +++ b/lib/entities/buildings/construction_yard.rb @@ -7,6 +7,7 @@ tiles = [ ] IMICRTS::Entity.define_entity(:construction_yard, :building, 2_000, "Provides radar and builds construction workers", tiles) do |entity| + entity.has(:building) entity.has(:build_queue) entity.has(:sidebar_actions) entity.component(:sidebar_actions).add(:add_to_build_queue, {entity: :construction_worker}) diff --git a/lib/entities/buildings/helipad.rb b/lib/entities/buildings/helipad.rb index a81ac49..b5a6a37 100644 --- a/lib/entities/buildings/helipad.rb +++ b/lib/entities/buildings/helipad.rb @@ -7,6 +7,7 @@ tiles = [ ] IMICRTS::Entity.define_entity(:helipad, :building, 1_000, "Builds and rearms helicopters", tiles) do |entity| + entity.has(:building) entity.has(:build_queue) entity.has(:sidebar_actions) entity.component(:sidebar_actions).add(:add_to_build_queue, {entity: :helicopter}) diff --git a/lib/entities/buildings/power_plant.rb b/lib/entities/buildings/power_plant.rb index ea371a6..33abde8 100644 --- a/lib/entities/buildings/power_plant.rb +++ b/lib/entities/buildings/power_plant.rb @@ -7,6 +7,8 @@ tiles = [ ] IMICRTS::Entity.define_entity(:power_plant, :building, 800, "Generates power", tiles) do |entity| + entity.has(:building) + entity.radius = 24 entity.max_health = 100.0 diff --git a/lib/entities/buildings/refinery.rb b/lib/entities/buildings/refinery.rb index 9e6d9ca..a77259b 100644 --- a/lib/entities/buildings/refinery.rb +++ b/lib/entities/buildings/refinery.rb @@ -7,6 +7,8 @@ tiles = [ ] IMICRTS::Entity.define_entity(:refinery, :building, 1_400, "Generates credits", tiles) do |entity| + entity.has(:building) + entity.radius = 44 entity.max_health = 100.0 diff --git a/lib/entities/buildings/war_factory.rb b/lib/entities/buildings/war_factory.rb index 69d8490..3acc8b2 100644 --- a/lib/entities/buildings/war_factory.rb +++ b/lib/entities/buildings/war_factory.rb @@ -7,6 +7,7 @@ tiles = [ ] IMICRTS::Entity.define_entity(:war_factory, :building, 2_000, "Builds units", tiles) do |entity| + entity.has(:building) entity.has(:build_queue) entity.has(:sidebar_actions) entity.component(:sidebar_actions).add(:add_to_build_queue, {entity: :jeep}) diff --git a/lib/entity.rb b/lib/entity.rb index 8bd785f..21caec3 100644 --- a/lib/entity.rb +++ b/lib/entity.rb @@ -15,16 +15,20 @@ class IMICRTS end end - attr_reader :director, :player, :id, :name, :type, :speed + attr_reader :director, :player, :id, :name, :type, :speed, :data attr_accessor :position, :angle, :radius, :target, :state, :movement, :health, :max_health, :turret, :center, :particle_emitters, :color - def initialize(name:, player:, id:, position:, angle:, director:) + def initialize(name:, player:, id:, position:, angle:, director:, proto_entity: false) @player = player @id = id @position = position @angle = angle @director = director + @proto_entity = proto_entity + + @data = FriendlyHash.new + @speed = 0.5 @color = Gosu::Color.rgba(255, 255, 255, 255) @@ -125,18 +129,14 @@ class IMICRTS render unless @render @render.draw_rot(@position.x, @position.y, @position.z, @angle, @center.x, @center.y, 1, 1, @color) - component(:turret).draw if component(:turret) - @particle_emitters.each(&:draw) + unless @proto_entity + @components.values.each(&:draw) + @particle_emitters.each(&:draw) + end end def update - if component(:movement) - if component(:movement).pathfinder && component(:movement).pathfinder.path_current_node - component(:movement).rotate_towards(component(:movement).pathfinder.path_current_node.tile.position + @director.map.tile_size / 2) - end - - component(:movement).follow_path - end + @components.values.each(&:update) @particle_emitters.each do |emitter| @particle_emitters.delete(emitter) if emitter.die? @@ -146,6 +146,7 @@ class IMICRTS def tick(tick_id) @on_tick.call if @on_tick + component(:building).construction_work(1) if component(:building) end def on_tick(&block) diff --git a/lib/friendly_hash.rb b/lib/friendly_hash.rb index d109a2f..0590bbd 100644 --- a/lib/friendly_hash.rb +++ b/lib/friendly_hash.rb @@ -12,10 +12,13 @@ class IMICRTS @hash[key.to_sym] = value end - def method_missing(method) + def method_missing(method, argument = nil) if value = @hash.dig(method) value + elsif argument != nil + @hash[method.to_s.sub("=", "").to_sym] = argument else + return false unless argument # May result in bugginess! raise "Unknown value for: #{method}" end end diff --git a/lib/tools/place_entity.rb b/lib/tools/place_entity.rb index de396e3..cb3ef3a 100644 --- a/lib/tools/place_entity.rb +++ b/lib/tools/place_entity.rb @@ -6,7 +6,7 @@ class IMICRTS @entity = @options[:entity] @construction_worker = @options[:construction_worker] - @preview = Entity.new(name: @entity, player: @player, id: 0, position: CyberarmEngine::Vector.new, angle: 0, director: @director) + @preview = Entity.new(name: @entity, player: @player, id: 0, position: CyberarmEngine::Vector.new, angle: 0, director: @director, proto_entity: true) end def draw