diff --git a/assets/images/hud.aseprite b/assets/images/hud.aseprite new file mode 100644 index 0000000..35df33b Binary files /dev/null and b/assets/images/hud.aseprite differ diff --git a/assets/images/hud.png b/assets/images/hud.png new file mode 100644 index 0000000..f812c62 Binary files /dev/null and b/assets/images/hud.png differ diff --git a/assets/images/hud_fg.aseprite b/assets/images/hud_fg.aseprite new file mode 100644 index 0000000..e015cb2 Binary files /dev/null and b/assets/images/hud_fg.aseprite differ diff --git a/assets/images/hud_fg.png b/assets/images/hud_fg.png new file mode 100644 index 0000000..b163aa5 Binary files /dev/null and b/assets/images/hud_fg.png differ diff --git a/assets/images/inventory.aseprite b/assets/images/inventory.aseprite deleted file mode 100644 index 29efdf3..0000000 Binary files a/assets/images/inventory.aseprite and /dev/null differ diff --git a/assets/images/inventory.png b/assets/images/inventory.png deleted file mode 100644 index dec6615..0000000 Binary files a/assets/images/inventory.png and /dev/null differ diff --git a/game/enemy/handler.rb b/game/enemy/handler.rb index 13f211a..ac5a956 100644 --- a/game/enemy/handler.rb +++ b/game/enemy/handler.rb @@ -12,10 +12,10 @@ class EnemyHandler def spawn! # For now, just spawn a single enemy at a fixed location - start_room_coords = $bus.get(:start_room_coords) - if @enemies.empty? - @enemies << Enemy.new((start_room_coords[0] * 2 + 1 + 4) * 60 + 30, (start_room_coords[1] * 2 + 1 + 4) * 60 + 30) - end + #start_room_coords = $bus.get(:start_room_coords) + #if @enemies.empty? + # @enemies << Enemy.new((start_room_coords[0] * 2 + 1 + 4) * 60 + 30, (start_room_coords[1] * 2 + 1 + 4) * 60 + 30) + #end end def draw diff --git a/game/hud.rb b/game/hud.rb deleted file mode 100644 index 9624fef..0000000 --- a/game/hud.rb +++ /dev/null @@ -1,9 +0,0 @@ -class HUD - def initialize - @inventory_bg = Gosu::Image.new("assets/images/inventory.png", retro: true) - end - - def draw - @inventory_bg.draw(0, 0, Float::INFINITY) - end -end \ No newline at end of file diff --git a/game/hud/inventory.rb b/game/hud/inventory.rb new file mode 100644 index 0000000..cbe4d68 --- /dev/null +++ b/game/hud/inventory.rb @@ -0,0 +1,167 @@ +class Inventory + OFFSET = [27, 34] + COLS = 3 + ROW_HEIGHT = 48 + COL_WIDTH = 40 + + CRAFT_RECIPES = { + lorentz_field: { wood: 16, metal: 8, science: 2 }, + torch: { wood: 8 }, + radar: { wood: 2, metal: 8, science: 2 }, + landmine: { wood: 16, metal: 8 }, + shrodingers_mine: { wood: 16, metal: 8, science: 1 }, + event_horizon: { metal: 16, science: 2 }, + occams_razor: { wood: 2, metal: 1 }, + quantum_bow: { wood: 32, metal: 16, science: 8 }, + blade_of_recursion: { wood: 32, metal: 8, science: 4 } + }.freeze + + def initialize + items = [ + :wood, :metal, :science, + :lorentz_field, :torch, :radar, + :landmine, :shrodingers_mine, :event_horizon, + :occams_razor, :quantum_bow, :blade_of_recursion + ] + + @grid = items.each_slice(COLS).map do |slice| + slice.map do |type| + [type, initial_amount_max(type)] + end + end + + @inventory_selected = :wood + @font = Gosu::Font.new(8, name: "assets/fonts/tn.ttf") + + $bus.on(:obtain) do |type, amount| + row, col = find_slot(type) + next unless row + @grid[row][col][1][0] += amount + @grid[row][col][1][0] = @grid[row][col][1][1] if @grid[row][col][1][0] > @grid[row][col][1][1] + end + end + + # Draw the inventory + def draw + x_start, y_start = OFFSET + y = y_start + + @grid.each do |row| + x = x_start + row.each do |type, (amount, max)| + # Background highlighting + if type == @inventory_selected + Gosu.draw_rect(x + 2, y + 2, 32, 32, Gosu::Color.new(255 * 0.7, 249, 208, 64), Float::INFINITY) + elsif amount == max + Gosu.draw_rect(x + 2, y + 2, 32, 32, Gosu::Color.new(255 * 0.7, 128, 239, 128), Float::INFINITY) + end + + # Empty overlay + Gosu.draw_rect(x + 2, y + 2, 32, 32, Gosu::Color.new(255 * 0.6, 0, 0, 0), Float::INFINITY) if amount == 0 + + # Amount text + @font.draw_text("#{amount.to_s.rjust(3)}/#{max.to_s.ljust(3)}", x, y + 37, Float::INFINITY, 1, 1, Gosu::Color::WHITE) + x += COL_WIDTH + end + y += ROW_HEIGHT + end + end + + # Handle input + def button_down(id, pos) + case id + when Gosu::MS_LEFT, Gosu::MS_RIGHT + mouse_click(*pos, id) + when Gosu::KB_1 then @inventory_selected = :occams_razor + when Gosu::KB_2 then @inventory_selected = :quantum_bow + when Gosu::KB_3 then @inventory_selected = :blade_of_recursion + when Gosu::KB_C + row, col = find_slot(@inventory_selected) + @inventory_selected = @grid[(row + 1) % @grid.size][col][0] + when Gosu::KB_V + row, col = find_slot(@inventory_selected) + @inventory_selected = @grid[row][(col + 1) % @grid[row].size][0] + end + end + + # Mouse click detection + def mouse_click(mx, my, id) + x_start, y_start = OFFSET + row_idx = ((my - y_start) / ROW_HEIGHT).floor + col_idx = ((mx - x_start) / COL_WIDTH).floor + + return if row_idx < 0 || row_idx >= @grid.size + return if col_idx < 0 || col_idx >= @grid[row_idx].size + + type, (amount, max) = @grid[row_idx][col_idx] + + if id == Gosu::MS_LEFT + @inventory_selected = type + elsif id == Gosu::MS_RIGHT + if DEBUG && [:wood, :metal, :science].include?(type) + @grid[row_idx][col_idx][1][0] = max + else + craft(type, ctrl: Gosu.button_down?(Gosu::KB_RIGHT_CONTROL) || Gosu.button_down?(Gosu::KB_LEFT_CONTROL)) + end + end + end + + private + + def craft(type, ctrl: false) + return unless CRAFT_RECIPES.key?(type) + + recipe = CRAFT_RECIPES[type] + + # How many we can craft + possible_counts = recipe.map { |res, req| grid_value(res) / req } + max_possible = possible_counts.min + return if max_possible == 0 + + craft_amount = ctrl ? max_possible : 1 + + # Subtract resources + recipe.each do |res, req| + row, col = find_slot(res) + @grid[row][col][1][0] -= req * craft_amount + end + + # Add crafted item + row, col = find_slot(type) + @grid[row][col][1][0] += craft_amount + # Clamp to max + @grid[row][col][1][0] = @grid[row][col][1][1] if @grid[row][col][1][0] > @grid[row][col][1][1] + end + + # Helper to get amount of resource + def grid_value(type) + row, col = find_slot(type) + return 0 unless row + @grid[row][col][1][0] + end + + # Initial amount/max mapping + def initial_amount_max(type) + case type + when :wood, :metal then [0, 64] + when :science then [0, 32] + when :lorentz_field then [0, 4] + when :torch then [0, 8] + when :radar then [0, 4] + when :landmine, :shrodingers_mine then [0, 8] + when :event_horizon then [0, 4] + when :occams_razor, :quantum_bow, :blade_of_recursion then [0, 1] + else [0, 0] + end + end + + # Find slot in grid for a type + def find_slot(type) + @grid.each_with_index do |row, r| + row.each_with_index do |(t, _), c| + return [r, c] if t == type + end + end + nil + end +end \ No newline at end of file diff --git a/game/hud/layer.rb b/game/hud/layer.rb new file mode 100644 index 0000000..16e1342 --- /dev/null +++ b/game/hud/layer.rb @@ -0,0 +1,21 @@ +require_relative "inventory" + +class HUDLayer + def initialize + @hud_bg = Gosu::Image.new("assets/images/hud.png", retro: true) + @hud_fg = Gosu::Image.new("assets/images/hud_fg.png", retro: true) + @inventory = Inventory.new + end + + def draw + @hud_bg.draw(0, 0, Float::INFINITY) + + @inventory.draw + + @hud_fg.draw(0, 0, Float::INFINITY) + end + + def button_down(id, pos) + @inventory.button_down(id, pos) + end +end \ No newline at end of file diff --git a/game/maze.rb b/game/maze.rb index 51ea6f4..661f643 100644 --- a/game/maze.rb +++ b/game/maze.rb @@ -4,7 +4,6 @@ class Maze def initialize @maze = MazeData.new(80, 80) @spritesheet = Gosu::Image.load_tiles("assets/images/walls.png", 20, 40, retro: true) - puts @spritesheet.size $bus.on(:maze_size) { [80, 80] } diff --git a/game/scene.rb b/game/scene.rb index bbe690b..6d8a307 100644 --- a/game/scene.rb +++ b/game/scene.rb @@ -1,6 +1,5 @@ -require_relative 'state' require_relative 'maze' -require_relative 'hud' +require_relative 'hud/layer' require_relative 'props/handler' require_relative 'enemy/handler' require_relative 'character' @@ -19,7 +18,7 @@ class Game < Scene @enemies = EnemyHandler.new @props = PropsHandler.new - @hud = HUD.new + @hud = HUDLayer.new @camera = [0, 0] @@ -152,5 +151,7 @@ class Game < Scene def button_down(id, pos) return $bus.emit(:change_scene, Menu.new) if id == Gosu::KB_ESCAPE + + @hud.button_down(id, pos) end end \ No newline at end of file diff --git a/game/state.rb b/game/state.rb deleted file mode 100644 index efba277..0000000 --- a/game/state.rb +++ /dev/null @@ -1,42 +0,0 @@ -class State - # This class holds state information - # for example the player inventory / items - # also their health, stealth, and memory bars - # it can handle mouse input for inventory management and item usage - # it can also handle keyboard input for quick item usage - - def initialize - @inventory = { - # basic resources - :wood => 0, - :metal => 0, - :science => 0, - - # nuetrals - :torch => 0, - :radar => 0, - - # placeable weapons - :landmine => 0, - :shrodingers_mine => 0, - :event_horizon => 0, - - # attack weapons - :occams_razor => 0, - :quantum_bow => 0, - :blade_of_recursion => 0, - - # utility weapon - :lorentz_field => 0 - } - @inventory_selected = :wood - @upgrades = [] - @health = 100 - @stealth = 100 - @memory = 256 - - $bus.on(:obtain) do |type, amount| - @inventory[type] += amount if @inventory.key?(type) - end - end -end \ No newline at end of file diff --git a/utils/maze.rb b/utils/maze.rb index 12bf6e5..c1182e9 100644 --- a/utils/maze.rb +++ b/utils/maze.rb @@ -160,7 +160,7 @@ class MazeData (0...self.width).each do |x| print wall_chars[wall_type(x, y)] end - puts + print "\n" end end