diff --git a/assets/images/extractor.png b/assets/images/extractor.png index e4b2f78..30d4f7a 100644 Binary files a/assets/images/extractor.png and b/assets/images/extractor.png differ diff --git a/assets/images/extractor.xcf b/assets/images/extractor.xcf index 2ebf3ce..415930f 100644 Binary files a/assets/images/extractor.xcf and b/assets/images/extractor.xcf differ diff --git a/consumer.rb b/consumer.rb index 3cead5e..6e462d6 100644 --- a/consumer.rb +++ b/consumer.rb @@ -14,7 +14,7 @@ TASKS = [ ] class Consumer - attr_reader :draw_x, :draw_y + attr_reader :draw_x, :draw_y, :size_x, :size_y # Create consumer at a position with the number and rate specified # @param x [Integer] X position to start at # @param y [Integer] Y position to start at @@ -30,6 +30,7 @@ class Consumer } @task_index = 0 @tooltip = @parent.register_dialouge(@x, @y, @box_size * SIZE, @box_size * SIZE, TASKS[@task_index], 500) + @size_x = @size_y = 3 end # Consumes numbers created @@ -37,7 +38,7 @@ class Consumer # @param camera_x [Integer] The camera X position # @param camera_y [Integer] The camera Y position # @param camera_zoom [Float] The camera zoom - def update(delta_mult, camera_x, camera_y, camera_zoom, mouse_x, mouse_y, mouse_used) + def update(delta_mult, camera_x, camera_y, camera_zoom, mouse_x, mouse_y) @draw_x = (((((@screen_width / @box_size.to_f) / 2.0) + (@x - camera_x) * camera_zoom) * @box_size) + BORDER * camera_zoom) @draw_y = (((((@screen_height / @box_size.to_f) / 2.0) + (@y - camera_y) * camera_zoom) * @box_size) + BORDER * camera_zoom) @camera_zoom = camera_zoom diff --git a/extractor.rb b/extractor.rb index 38d7dba..e0f78d3 100644 --- a/extractor.rb +++ b/extractor.rb @@ -4,19 +4,21 @@ # conveyer belts that are adjacent to it. class Extractor + attr_reader :draw_x, :draw_y, :size_x, :size_y def initialize(x, y, box_size) - @x = x - @y = y + @size_x = @size_y = 3 + @x = x - @size_x / 2 + @y = y - @size_y / 2 @box_size = box_size - @image = Gosu.render(@box_size - (2 * BORDER), @box_size - (2 * BORDER)) { - Gosu::Image.new('assets/images/producer.png').draw(0, 0, 0, @box_size / 32.0, @box_size / 32.0) + @image = Gosu.render((@size_x * @box_size) - (2 * BORDER), (@size_y * @box_size) - (2 * BORDER)) { + Gosu::Image.new('assets/images/extractor.png').draw(0, 0, 0, @box_size / 32.0, @box_size / 32.0) Gosu::Image.from_text("#{@number}", 20, font: FONT_PATH).draw(10 / 32.0 * @box_size, (8 / 32.0 * @box_size), 1, 2, 2, 0xFFFA32C0) } end - def update(delta_mult, camera_x, camera_y) - @draw_x = (((((@screen_width / @box_size.to_f) / 2.0) + (@x - camera_x) * camera_zoom) * @box_size) + BORDER * camera_zoom) - @draw_y = (((((@screen_height / @box_size.to_f) / 2.0) + (@y - camera_y) * camera_zoom) * @box_size) + BORDER * camera_zoom) + def update(delta_mult, camera_x, camera_y, camera_zoom) + @draw_x = (((((WIDTH / @box_size.to_f) / 2.0) + (@x - camera_x) * camera_zoom) * @box_size) + BORDER * camera_zoom) + @draw_y = (((((HEIGHT / @box_size.to_f) / 2.0) + (@y - camera_y) * camera_zoom) * @box_size) + BORDER * camera_zoom) @camera_zoom = camera_zoom end diff --git a/gamegrid.rb b/gamegrid.rb new file mode 100644 index 0000000..2c4ec98 --- /dev/null +++ b/gamegrid.rb @@ -0,0 +1,71 @@ +# Nathan Hinton +# Holds a grid of each otem in the game + +class GameGrid + def initialize(game_width, game_height) + + @game_grid = [] + game_width.times do |xx| + @game_grid.append(Array.new(game_height)) + end + end + + + ## Add an item to the grid + # @param x [Integer] The x position (top left corner of item) + # @param y [Integer] The y position (top left corner of item) + # @param item [Object] The item to add. Should be an actual reference to the item + # @retval [Boolean] True if the item was placed, false otherwise (space conflict) + def add_item(x, y, item) + size_x = item.size_x + size_y = item.size_y + + puts "#{item.to_s}" + puts "top left: (#{x}, #{y}), size: (#{size_x}, #{size_y})" + + # Check that the grid is empty in those spots: + size_x.times do |xx| + size_y.times do |yy| + unless @game_grid[x + xx][y + yy].nil? + puts "Failed to add item: #{item.to_s}:" + puts " - top left: (#{x}, #{y}), size: (#{size_x}, #{size_y}), collision: (#{xx}, #{yy})" + return false + end + end + end + + # place item in grid + size_x.times do |xx| + size_y.times do |yy| + @game_grid[x + xx][y + yy] = item + end + end + return true + end + + ## Add an item to the grid + # @param x [Integer] The x position (top left corner of item) + # @param y [Integer] The y position (top left corner of item) + # @param item [Object] The item to remove. Used to ensure we are removing the right thing. + def remove_item(x, y, item) + size_x = item.size_x + size_y = item.size_y + + # Check that the grid is empty in those spots: + size_x.times do |xx| + size_y.times do |yy| + if @game_grid[x + xx][y + yy] != item + raise RuntimeError.new('Item mismatch in internal game grid! Game state corrupted1') + end + end + end + + # place item in grid + size_x.times do |xx| + size_y.times do |yy| + @game_grid[x + xx][y + yy] = nil + end + end + end + +end diff --git a/main.rb b/main.rb index 2006e21..8603d3d 100644 --- a/main.rb +++ b/main.rb @@ -5,6 +5,8 @@ require 'gosu' require 'yaml' +require './gamegrid.rb' +require './extractor.rb' require './producer.rb' require './consumer.rb' require './dialouge_box.rb' @@ -19,8 +21,8 @@ BOX_SIZE = 64 # Default game settings GAME_SAVE_DIRECTORY = 'game_save_data' -GAME_WIDTH = 101 # Odd numbers look best, in squares -GAME_HEIGHT = 101 +GAME_WIDTH = 201 # Odd numbers look best, in squares +GAME_HEIGHT = 201 GAME_PRODUCER_CHANCE = 0.01 GAME_PRODUCER_VALUE_MULT = 0.1 GAME_PRODUCER_BASE_SPEED = 1 @@ -42,6 +44,7 @@ class NumFactory < Gosu::Window @background_color = Gosu::Color::BLUE @cursor_image = Gosu::Image.new('assets/images/cursor.png') @cursor = @cursor_image + @cursor_offset = 16 @camera_x = 0 @camera_y = 0 @@ -57,9 +60,11 @@ class NumFactory < Gosu::Window @adder_image = Gosu::Image.new('assets/images/adder.png') @delete_image = Gosu::Image.new('assets/images/delete.png') - @dialouges = [ - #DialougeBox.new(0, 5, BOX_SIZE, BOX_SIZE, WIDTH, HEIGHT, 'this is some really good test text!', BOX_SIZE, 500) - ] + @dialouges = [] + @extractors = [] + + # Setup the game grid + @game_grid = GameGrid.new(GAME_WIDTH, GAME_HEIGHT) # Load from file or initialize a new game begin @@ -87,17 +92,18 @@ class NumFactory < Gosu::Window # Loop through and place producers center_x = ((@game_width - 1) / 2).to_i center_y = ((@game_height - 1) / 2).to_i - - @consumers.append( - Consumer.new(self, center_x, center_y, BOX_SIZE, WIDTH, HEIGHT), - ) + consumer = Consumer.new(self, center_x, center_y, BOX_SIZE, WIDTH, HEIGHT) + if @game_grid.add_item(center_x, center_y, consumer) + @consumers.append(consumer) + end + # The value of the producer is proportional to the distance from the center ((@game_width).to_i).times do |xx| (@game_height).to_i.times do |yy| if rand < GAME_PRODUCER_CHANCE # Place a producer: - @producers.append( + producer = Producer.new( self, xx, @@ -108,7 +114,10 @@ class NumFactory < Gosu::Window WIDTH, HEIGHT, ) - ) + # Add an item to the game with checking that the internal game state is good + if @game_grid.add_item(xx, yy, producer) + @producers.append(producer) + end end end end @@ -141,6 +150,38 @@ class NumFactory < Gosu::Window end def button_down(id) + ### Process mouse ### + mouse_used = @ui.update(self.mouse_x, self.mouse_y) + + # They clicked in the game screen, attempt to place an item + if !mouse_used && id == Gosu::MS_LEFT + case @current_tool + when 'delete' + @cursor = @delete_image + @cursor_offset = @delete_image.height + #break + when 'belt' + @cursor = @belt_image + @cursor_offset = @belt_image.height + #break + when 'adder' + @cursor = @adder_image + @cursor_offset = @adder_image.height + #break + when 'extractor' + #xx = @camera_x + ((((self.mouse_x) - (WIDTH/2)) / BOX_SIZE - 1) * @camera_zoom).to_i + #yy = @camera_y + ((((self.mouse_y) - (HEIGHT/2)) / BOX_SIZE - 1) * @camera_zoom).to_i + xx = @camera_x + ((self.mouse_x - @cursor_offset + (BOX_SIZE * @camera_zoom)) / (BOX_SIZE * @camera_zoom)).to_i + yy = @camera_y + ((self.mouse_y - @cursor_offset + (BOX_SIZE * @camera_zoom)) / (BOX_SIZE * @camera_zoom)) + extractor = Extractor.new(xx, yy, BOX_SIZE) + if @game_grid.add_item(xx, yy, extractor) + @extractors.append(extractor) + end + #break + end + end + + ### Process keyboard ### if id == Gosu::KB_ESCAPE close elsif [Gosu::MS_WHEEL_UP, Gosu::KB_Z].include? id @@ -174,6 +215,7 @@ class NumFactory < Gosu::Window @camera_y_zoom_offset = HEIGHT.to_f / (@camera_boxes * BOX_SIZE * 2).to_f elsif id == Gosu::KB_G @cursor = @cursor_image + @cursor_offset = 16 @current_tool = nil else super @@ -221,30 +263,27 @@ class NumFactory < Gosu::Window end # Prevent camera from leaving the screen - @camera_x = [@camera_x, 0].max - @camera_x = [@camera_x, @game_width].min - @camera_y = [@camera_y, 0].max - @camera_y = [@camera_y, @game_width].min + @camera_x = [@camera_x.to_i, 0].max + @camera_x = [@camera_x.to_i, @game_width].min + @camera_y = [@camera_y.to_i, 0].max + @camera_y = [@camera_y.to_i, @game_width].min ### ITEMS ### - mouse_used = @ui.update(self.mouse_x, self.mouse_y) - @producers.each do |producer| producer.update(delta_mult, @camera_x, @camera_y, @camera_zoom) end - @belts.each do |belt| - belt.update(delta_mult) + @extractors.each do |extractor| + extractor.update(delta_mult, @camera_x, @camera_y, @camera_zoom) end @consumers.each do |consumer| - consumer.update(delta_mult, @camera_x, @camera_y, @camera_zoom, self.mouse_x, self.mouse_y, mouse_used) + consumer.update(delta_mult, @camera_x, @camera_y, @camera_zoom, self.mouse_x, self.mouse_y) end - if !mouse_used - @dialouges.each do |dialouge| - dialouge.update(delta_mult, @camera_zoom, self.mouse_x, self.mouse_y) - end + # Finally process the dialouges + @dialouges.each do |dialouge| + dialouge.update(delta_mult, @camera_zoom, self.mouse_x, self.mouse_y) end case @current_tool @@ -290,6 +329,15 @@ class NumFactory < Gosu::Window end end end + + @extractors.each do |extractor| + if extractor.draw_x <= WIDTH && extractor.draw_x >= 0 + if extractor.draw_y <= HEIGHT && extractor.draw_y >= 0 + extractor.draw() + onscreen_items += 1 + end + end + end @consumers.each do |consumer| if consumer.draw_x <= WIDTH && consumer.draw_x >= 0 @@ -309,6 +357,7 @@ class NumFactory < Gosu::Window Gosu::Image.from_text("#{width}, #{height}", 20, font: FONT_PATH).draw(1600, 0, 1) Gosu::Image.from_text("#{mouse_x}, #{mouse_y}", 20, font: FONT_PATH).draw(1600, 100, 1) + Gosu::Image.from_text("#{@camera_x + ((self.mouse_x - @cursor_offset + (BOX_SIZE * @camera_zoom)) / (BOX_SIZE * @camera_zoom)).to_i}, #{@camera_y + ((self.mouse_y - (HEIGHT/2)) / BOX_SIZE * @camera_zoom).to_i}", 20, font: FONT_PATH).draw(1600, 125, 1) Gosu::Image.from_text("Tick time: #{((Time.now() - @tick_time).to_f * 1000).to_i}", 20, font: FONT_PATH).draw(1600, 25, 1) Gosu::Image.from_text("FPS: #{Gosu.fps}", 20, font: FONT_PATH).draw(1600, 50, 1) Gosu::Image.from_text("items on screen: #{onscreen_items}", 20, font: FONT_PATH).draw(1600, 75, 1) @@ -318,10 +367,11 @@ class NumFactory < Gosu::Window Gosu::Image.from_text("Camera viewport: (#{@camera_min_x}, #{@camera_min_y}) to (#{@camera_max_x}, #{@camera_max_y})", 20, font: FONT_PATH).draw(1600, 250, 1) if @cursor == @cursor_image - @cursor.draw(self.mouse_x - 16, self.mouse_y - 16, 10) + @cursor.draw(self.mouse_x - @cursor_offset, self.mouse_y - @cursor_offset, 10) else - @cursor.draw(self.mouse_x - @cursor_offset, self.mouse_y - @cursor_offset, 10, BOX_SIZE / 32.0 * @camera_zoom, BOX_SIZE / 32.0 * @camera_zoom) + @cursor.draw(self.mouse_x - @cursor_offset, self.mouse_y - @cursor_offset, 10, BOX_SIZE / 32.0 * @camera_zoom, BOX_SIZE / 32.0 * @camera_zoom, 0x88_888888) end + Gosu.draw_rect(self.mouse_x - 2, self.mouse_y - 2, 4, 4, Gosu::Color::RED) end end diff --git a/producer.rb b/producer.rb index 5ec0edc..02c48c4 100644 --- a/producer.rb +++ b/producer.rb @@ -5,7 +5,7 @@ PRODUCER_DEBUG = false BORDER = 2 class Producer - attr_reader :draw_x, :draw_y + attr_reader :draw_x, :draw_y, :size_x, :size_y # Create producer at a position with the number and rate specified # @param x [Integer] X position to start at # @param y [Integer] Y position to start at @@ -28,6 +28,7 @@ class Producer puts "X: #{@x}, Y: #{@y}" @tooltip = @parent.register_dialouge(@x, @y, @box_size, @box_size, "Produces #{@rate} number per second", 500) + @size_x = @size_y = 1 end