From 8be63d8ebe9826ce4072260eeaa7da8afcf706c3 Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Wed, 2 Oct 2019 22:35:44 -0500 Subject: [PATCH] Added Director, Player and stubbed Order, mostly working Entity#rotate_towards --- i-mic-rts.rb | 4 +++ lib/camera.rb | 2 +- lib/director.rb | 39 +++++++++++++++++++++++ lib/entity.rb | 20 +++++++++++- lib/order.rb | 64 ++++++++++++++++++++++++++++++++++++++ lib/orders/camera_moved.rb | 4 +++ lib/player.rb | 20 ++++++++++++ lib/states/game.rb | 42 ++++++++++++++++--------- lib/window.rb | 9 ++++-- 9 files changed, 185 insertions(+), 19 deletions(-) create mode 100644 lib/director.rb create mode 100644 lib/order.rb create mode 100644 lib/orders/camera_moved.rb create mode 100644 lib/player.rb diff --git a/i-mic-rts.rb b/i-mic-rts.rb index ed6ee98..72f581a 100644 --- a/i-mic-rts.rb +++ b/i-mic-rts.rb @@ -23,4 +23,8 @@ require_relative "lib/zorder" require_relative "lib/entity" # require_relative "lib/entities/" +require_relative "lib/order" +require_relative "lib/director" +require_relative "lib/player" + IMICRTS::Window.new(width: Gosu.screen_width / 4 * 3, height: Gosu.screen_height / 4 * 3, fullscreen: false, resizable: true).show \ No newline at end of file diff --git a/lib/camera.rb b/lib/camera.rb index b2411bf..4b91e9a 100644 --- a/lib/camera.rb +++ b/lib/camera.rb @@ -16,7 +16,7 @@ class IMICRTS def window; $window; end - def draw(&block) + def draw(*args, &block) if block center_point = center Gosu.translate(@position.x, @position.y) do diff --git a/lib/director.rb b/lib/director.rb new file mode 100644 index 0000000..af4a263 --- /dev/null +++ b/lib/director.rb @@ -0,0 +1,39 @@ +class IMICRTS + class Director + def initialize(map:, players:, networking_mode: :virtual, tick_rate: 10) + @map = map + @players = players + @networking_mode = networking_mode + @tick_rate = tick_rate + + @last_tick_at = Gosu.milliseconds + @tick_time = 1000.0 / @tick_rate + end + + def update + if (Gosu.milliseconds - @last_tick_at) >= @tick_time + @last_tick_at = Gosu.milliseconds + + tick + end + end + + def tick + @players.each(&:tick) + end + + def player(id) + @players.find { |player| player.id == id } + end + + def issue_order(player_id, order_id, *args) + # pp Order.order_name(order_id) + # pp args + end + + + def entities + @players.map { |player| player.entities }.flatten + end + end +end \ No newline at end of file diff --git a/lib/entity.rb b/lib/entity.rb index 7e78c3b..69d41a1 100644 --- a/lib/entity.rb +++ b/lib/entity.rb @@ -1,6 +1,6 @@ class IMICRTS class Entity - attr_reader :position, :angle + attr_reader :position, :angle, :radius def initialize(manifest: nil, images:, position:, angle:) @manifest = manifest @images = images @@ -37,5 +37,23 @@ class IMICRTS def draw_gizmos Gosu.draw_rect(@position.x - @radius, @position.y - (@radius + 2), @radius * 2, 2, Gosu::Color::GREEN, ZOrder::ENTITY_GIZMOS) end + + def rotate_towards(vector) + _angle = Gosu.angle(@position.x, @position.y, vector.x, vector.y) + a = (360 + (_angle - @angle)) % 360 + + # Fails if vector is directly behind entity + if @angle.between?(_angle - 3, _angle + 3) + @angle = _angle + elsif a < 180 + @angle -= 1 + else + @angle += 1 + end + + @angle %= 360 + + pp [a, _angle, @angle] + end end end \ No newline at end of file diff --git a/lib/order.rb b/lib/order.rb new file mode 100644 index 0000000..2193570 --- /dev/null +++ b/lib/order.rb @@ -0,0 +1,64 @@ +class IMICRTS + class Order + @@orders = {} + + def self.order_name(order_id) + IMICRTS::Order.constants(false).find { |const| IMICRTS::Order.const_get(const) == order_id } + end + + def self.define_handler(order_id, arguments: [], &handler) + raise "Handler from #{order_name(order_id)} already defined!" if @@orders.dig(order_id) + + @@orders[order_id] = IMICRTS::Order.new(id: order_id, arguments: arguments, &handler) + end + + def initialize(id:, arguments:, &handler) + + end + + def execute + @handler.call(self, Director.instance) + end + end + + orders = [ + :CAMERA_MOVED, + :CAMERA_ZOOMED, + + :ENTITY_SELECTED, + :ENTITY_DESELECTED, + :ENTITY_DESTROYED, + :ENTITY_DAMAGED, + :ENTITY_REPAIRED, + + :SELECTED_UNITS, + :DESELECTED_UNITS, + + :MOVE, + :STOP, + :GUARD, + :ATTACK, + :PATROL, + + :BUILD_ORDER, + :CANCEL_BUILD_ORDER, + :BUILD_ORDER_COMPLETE, + + :BUILDING_POWER_STATE, + :BUILDING_REPAIR, + :BUILDING_SELL, + + :MESSAGE_BROADCAST, + :MESSGE_TEAM, + :MESSAGE_DIRECT, + ] + + offset = 0 + orders.each_with_index do |order, i| + IMICRTS::Order.const_set(order, i + offset) + end +end + +Dir.glob("#{IMICRTS::GAME_ROOT_PATH}/lib/orders/*.rb").each do |order| + require_relative order +end \ No newline at end of file diff --git a/lib/orders/camera_moved.rb b/lib/orders/camera_moved.rb new file mode 100644 index 0000000..385e174 --- /dev/null +++ b/lib/orders/camera_moved.rb @@ -0,0 +1,4 @@ +IMICRTS::Order.define_handler(IMICRTS::Order::CAMERA_MOVED, arguments: [:player_id, :x, :y]) do |order, director| + director.player(order.player_id).move_camera(order.x, order.y) +end + diff --git a/lib/player.rb b/lib/player.rb new file mode 100644 index 0000000..f2932f9 --- /dev/null +++ b/lib/player.rb @@ -0,0 +1,20 @@ +class IMICRTS + class Player + attr_reader :id, :name, :entities, :orders, :camera + def initialize(id:, name: nil) + @id = id + @name = name ? name : "Novice-#{id}" + + @entities = [] + @orders = [] + @camera = Camera.new + end + + def tick + puts "Player #{@id}-#{@name} ticked: #{Gosu.milliseconds}" + end + + def entity(id) + end + end +end \ No newline at end of file diff --git a/lib/states/game.rb b/lib/states/game.rb index 3fc3dd9..242cc48 100644 --- a/lib/states/game.rb +++ b/lib/states/game.rb @@ -1,9 +1,11 @@ class IMICRTS class Game < CyberarmEngine::GuiState def setup - @units = [] + window.show_cursor = true @selected_entities = [] - @camera = Camera.new + + @player = Player.new(id: 0) + @director = Director.new(map: nil, players: [@player]) @mouse_pos = CyberarmEngine::Text.new("X: 0\nY: 0", x: 500, y: 10, z: Float::INFINITY) @sidebar = stack(height: 1.0) do @@ -14,14 +16,14 @@ class IMICRTS flow do @buttons = stack(width: 75) do @h = button("Harvester", width: 1.0) do - @units << Entity.new( + @player.entities << Entity.new( 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 - @units << Entity.new( + @player.entities << Entity.new( 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) @@ -49,8 +51,8 @@ class IMICRTS Gosu.draw_rect(0, 0, window.width, window.height, Gosu::Color.rgb(10, 175, 35)) - @camera.draw do - @units.each(&:draw) + @player.camera.draw(0, 0, window.width, window.height) do + @director.entities.each(&:draw) @selected_entities.each(&:selected_draw) # draw_rect(@camera.center.x - 10, @camera.center.y - 10, 20, 20, Gosu::Color::BLACK, Float::INFINITY) @@ -66,14 +68,19 @@ class IMICRTS def update super - @camera.update + @director.update + @player.camera.update + + @selected_entities.each do |ent| + ent.rotate_towards(@goal) if @goal + end if @selection_start select_entities end - mouse = @camera.mouse_pick(window.mouse_x, window.mouse_y) - @mouse_pos.text = "Aspect Ratio: #{@camera.aspect_ratio}\nZoom: #{@camera.zoom}\nX: #{window.mouse_x}\nY: #{window.mouse_y}\n\nX: #{mouse.x}\nY: #{mouse.y}" + mouse = @player.camera.mouse_pick(window.mouse_x, window.mouse_y) + @mouse_pos.text = "Aspect Ratio: #{@player.camera.aspect_ratio}\nZoom: #{@player.camera.zoom}\nX: #{window.mouse_x}\nY: #{window.mouse_y}\n\nX: #{mouse.x}\nY: #{mouse.y}" end def button_down(id) @@ -82,31 +89,36 @@ class IMICRTS case id when Gosu::MS_LEFT unless @sidebar.hit?(window.mouse_x, window.mouse_y) - @selection_start = CyberarmEngine::Vector.new(window.mouse_x, window.mouse_y) - @camera.position + @selection_start = CyberarmEngine::Vector.new(window.mouse_x, window.mouse_y) - @player.camera.position end when Gosu::MS_RIGHT @anchor = nil end - @camera.button_down(id) unless @sidebar.hit?(window.mouse_x, window.mouse_y) + @player.camera.button_down(id) unless @sidebar.hit?(window.mouse_x, window.mouse_y) end def button_up(id) super case id + when Gosu::MS_RIGHT + @goal = @player.camera.mouse_pick(window.mouse_x, window.mouse_y) when Gosu::MS_LEFT @box = nil @selection_start = nil + + @director.issue_order(@player.id, Order::SELECTED_UNITS, @selected_entities) end - @camera.button_up(id) + @player.camera.button_up(id) end def select_entities - @box = CyberarmEngine::BoundingBox.new(@selection_start, CyberarmEngine::Vector.new(window.mouse_x, window.mouse_y) - @camera.position) + @box = CyberarmEngine::BoundingBox.new(@selection_start, CyberarmEngine::Vector.new(window.mouse_x, window.mouse_y) - @player.camera.position) - selected_entities = @units.select do |ent| - @box.point?(ent.position) + selected_entities = @player.entities.select do |ent| + @box.point?(ent.position - ent.radius) || + @box.point?(ent.position + ent.radius) end if Gosu.button_down?(Gosu::KB_LEFT_SHIFT) || Gosu.button_down?(Gosu::KB_RIGHT_SHIFT) diff --git a/lib/window.rb b/lib/window.rb index 9783e9b..46c90e6 100644 --- a/lib/window.rb +++ b/lib/window.rb @@ -4,8 +4,13 @@ class IMICRTS @last_update_time = Gosu.milliseconds self.caption = "#{IMICRTS::NAME} (#{IMICRTS::VERSION} #{IMICRTS::VERSION_NAME})" - # push_state(Boot) - push_state(MainMenu) + if ARGV.join.include?("--fast") + push_state(MainMenu) + elsif ARGV.join.include?("--debug") + push_state(Game) + else + push_state(Boot) + end end def update