## Nathan Hinton ## Main entry point for the game. Sets up the world and holds the main loop require 'gosu' require 'yaml' require './producer.rb' require './consumer.rb' require './dialouge_box.rb' FONT_PATH = 'assets/font/Cousine-Regular.ttf' # Viewport resolution WIDTH = Gosu::screen_width HEIGHT = Gosu::screen_height 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_PRODUCER_CHANCE = 0.01 GAME_PRODUCER_VALUE_MULT = 0.1 GAME_PRODUCER_BASE_SPEED = 1 # Camera settings CAMERA_MOVE_RANGE = 10 CAMERA_MOVE_SPEED = 1 CAMERA_MOVE_MAX_SPEED = 5 CAMERA_MIN_ZOOM = 16 # Boxes across CAMERA_MAX_ZOOM = 80 # Boxes across class NumFactory < Gosu::Window def initialize super WIDTH, HEIGHT, :fullscreen => true self.caption = "Number factory" @background_color = Gosu::Color::BLUE @camera_x = 0 @camera_y = 0 @camera_boxes = 30 # Default zoom @camera_zoom = 1 @camera_x_zoom_offset = WIDTH.to_f / (@camera_boxes * BOX_SIZE * 2).to_f @camera_y_zoom_offset = HEIGHT.to_f / (@camera_boxes * BOX_SIZE * 2).to_f @dd = DialougeBox.new(0, 0, WIDTH, HEIGHT, "This is a really really really really really really really really really really string\nof test text!") @dialouges = [] # Load from file or initialize a new game begin game_save_data = YAML.load_file("#{GAME_SAVE_DIRECTORY}/positions.yaml") puts game_save_data # Load from file OR generate new save file @producers = [ Producer.new(0, 0, 1, 1), Producer.new(1000, 1000, 1, 1), Producer.new(2000, 2000, 1, 1), ] @consumers = [] @belts = [] rescue Errno::ENOENT # File does not exist puts "Generating new game..." @game_width = GAME_WIDTH @game_height = GAME_HEIGHT @producers = [] @consumers = [] # Consumer in center @belts = [] # 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(center_x, center_y, BOX_SIZE, WIDTH, HEIGHT), ) # 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.new( xx, yy, (Math.sqrt((xx - center_x)**2 + (yy - center_y) ** 2) * GAME_PRODUCER_VALUE_MULT).to_i, GAME_PRODUCER_BASE_SPEED, BOX_SIZE, WIDTH, HEIGHT, ) ) end end end end # End file loading # Move the camera to the center of the map: @camera_x = @game_width / 2 @camera_y = @game_height / 2 # Render the background @background = Gosu.render(@game_width * BOX_SIZE, @game_height * BOX_SIZE) { im = Gosu::Image.new('assets/images/background_square.png', {:tileable => true}) zoom = BOX_SIZE / 30.0 (@game_width).to_i.times do |ww| puts ww (@game_height).to_i.times do |hh| im.draw(ww * BOX_SIZE, hh * BOX_SIZE, 0, zoom, zoom) end end } @tick_time = Time.now() @delta_time = 0 end def button_down(id) if id == Gosu::KB_ESCAPE close elsif [Gosu::MS_WHEEL_UP, Gosu::KB_Z].include? id @camera_boxes -= 2 if @camera_boxes < CAMERA_MIN_ZOOM @camera_boxes = CAMERA_MIN_ZOOM end @camera_zoom = WIDTH / (@camera_boxes * BOX_SIZE).to_f @camera_x_zoom_offset = WIDTH.to_f / (@camera_boxes * BOX_SIZE * 2).to_f @camera_y_zoom_offset = HEIGHT.to_f / (@camera_boxes * BOX_SIZE * 2).to_f elsif [Gosu::MS_WHEEL_DOWN, Gosu::KB_X].include? id @camera_boxes += 2 if @camera_boxes > CAMERA_MAX_ZOOM @camera_boxes = CAMERA_MAX_ZOOM end @camera_zoom = WIDTH.to_f / (@camera_boxes * BOX_SIZE).to_f @camera_x_zoom_offset = WIDTH.to_f / (@camera_boxes * BOX_SIZE * 2).to_f @camera_y_zoom_offset = HEIGHT.to_f / (@camera_boxes * BOX_SIZE * 2).to_f elsif id == Gosu::KB_DOWN @camera_y += 1 elsif id == Gosu::KB_UP @camera_y -= 1 elsif id == Gosu::KB_LEFT @camera_x -= 1 elsif id == Gosu::KB_RIGHT @camera_x += 1 elsif id == Gosu::KB_SPACE @camera_boxes = 30 @camera_zoom = WIDTH.to_f / (@camera_boxes * BOX_SIZE).to_f @camera_x_zoom_offset = WIDTH.to_f / (@camera_boxes * BOX_SIZE * 2).to_f @camera_y_zoom_offset = HEIGHT.to_f / (@camera_boxes * BOX_SIZE * 2).to_f else super end end ## Called every frame def update @delta_time = Time.now() - @tick_time delta_mult = @delta_time * 30 #puts "Time: #{@delta_time}, Mult: #{delta_mult}" # Timing debug @tick_time = Time.now() ### CAMERA ### # Move the camera if needed if self.mouse_x < CAMERA_MOVE_RANGE @camera_x -= ([(CAMERA_MOVE_SPEED * ((CAMERA_MOVE_RANGE - self.mouse_x ) / 5)), CAMERA_MOVE_MAX_SPEED].min * delta_mult) elsif self.mouse_x > WIDTH - CAMERA_MOVE_RANGE @camera_x += ([(CAMERA_MOVE_SPEED * ((CAMERA_MOVE_RANGE - (WIDTH - self.mouse_x + 1)) / 5)), CAMERA_MOVE_MAX_SPEED].min * delta_mult) end if self.mouse_y < CAMERA_MOVE_RANGE @camera_y -= ([(CAMERA_MOVE_SPEED * ((CAMERA_MOVE_RANGE - self.mouse_y ) / 5)), CAMERA_MOVE_MAX_SPEED].min * delta_mult) elsif self.mouse_y > HEIGHT - CAMERA_MOVE_RANGE @camera_y += ([(CAMERA_MOVE_SPEED * ((CAMERA_MOVE_RANGE - (HEIGHT - (self.mouse_y + 1)) ) / 5)), CAMERA_MOVE_MAX_SPEED].min * delta_mult) 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 ### ITEMS ### @producers.each do |producer| producer.update(delta_mult, @camera_x, @camera_y, @camera_zoom, self.mouse_x, self.mouse_y) end @belts.each do |belt| belt.update(delta_mult) end @consumers.each do |consumer| consumer.update(delta_mult, @camera_x, @camera_y, @camera_zoom, self.mouse_x, self.mouse_y) end @dialouges.each do |dialouge| dialouge.update(0, 0, newtext: "My new text is: #{delta_mult}") end end ## Called when OS wants to update window. def draw # Draw mouse coords: onscreen_items = 0 @background.draw( (((((WIDTH / BOX_SIZE.to_f) / 2.0) - (@camera_x * @camera_zoom)) * (BOX_SIZE))), ((((HEIGHT / BOX_SIZE.to_f) / 2.0) - (@camera_y * @camera_zoom)) * (BOX_SIZE)), 0, @camera_zoom, @camera_zoom ) @producers.each do |producer| if producer.draw_x <= WIDTH && producer.draw_x >= 0 if producer.draw_y <= HEIGHT && producer.draw_y >= 0 producer.draw() onscreen_items += 1 end end end @consumers.each do |consumer| if consumer.draw_x <= WIDTH && consumer.draw_x >= 0 if consumer.draw_y <= HEIGHT && consumer.draw_y >= 0 consumer.draw() onscreen_items += 1 end end end @dialouges.each do |dialouge| dialouge.draw() end 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("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).draw(1600, 75, 1) Gosu::Image.from_text("Camera boxes: #{@camera_boxes}", 20, font: FONT_PATH).draw(1600, 175, 1) Gosu::Image.from_text("Camera location: #{@camera_x}, #{@camera_y}", 20, font: FONT_PATH).draw(1600, 200, 1) Gosu::Image.from_text("Camera zoom: #{@camera_zoom}, #{@camera_x_zoom_offset}", 20, font: FONT_PATH).draw(1600, 225, 1) 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) end end NumFactory.new.show