Enhance game over scene: implement GameOver class with options for retry and main menu, add background image, and handle mouse and keyboard interactions.
This commit is contained in:
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
@@ -18,7 +18,7 @@ class EnemyHandler
|
|||||||
def spawn!
|
def spawn!
|
||||||
# For now, just spawn a single enemy at a fixed location
|
# For now, just spawn a single enemy at a fixed location
|
||||||
start_room_coords = $bus.get(:start_room_coords)
|
start_room_coords = $bus.get(:start_room_coords)
|
||||||
if @enemies.empty?
|
if @enemies.empty? && start_room_coords
|
||||||
@enemies << Force.new((start_room_coords[0] * 2 + 1 + 4) * 60 + 30, (start_room_coords[1] * 2 + 1 + 4) * 60 + 30)
|
@enemies << Force.new((start_room_coords[0] * 2 + 1 + 4) * 60 + 30, (start_room_coords[1] * 2 + 1 + 4) * 60 + 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+7
-4
@@ -8,7 +8,10 @@ class HealthBar
|
|||||||
|
|
||||||
def take_damage(amount)
|
def take_damage(amount)
|
||||||
@health -= amount
|
@health -= amount
|
||||||
@health = 0 if @health < 0
|
if @health <= 0
|
||||||
|
@health = 0
|
||||||
|
$bus.emit(:change_scene, GameOver)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def heal(amount)
|
def heal(amount)
|
||||||
@@ -16,12 +19,12 @@ class HealthBar
|
|||||||
@health = @max_health if @health > @max_health
|
@health = @max_health if @health > @max_health
|
||||||
end
|
end
|
||||||
|
|
||||||
def draw(x, y)
|
def draw
|
||||||
# Draw the background of the health bar (red)
|
# Draw the background of the health bar (red)
|
||||||
Gosu.draw_rect(x, y, 100, 10, Gosu::Color::RED)
|
Gosu.draw_rect(30, 10, 100, 10, Gosu::Color::RED)
|
||||||
|
|
||||||
# Draw the foreground of the health bar (green) based on current health
|
# Draw the foreground of the health bar (green) based on current health
|
||||||
health_width = (health.to_f / max_health) * 100
|
health_width = (health.to_f / max_health) * 100
|
||||||
Gosu.draw_rect(x, y, health_width, 10, Gosu::Color::GREEN)
|
Gosu.draw_rect(30, 10, health_width, 10, Gosu::Color::GREEN)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
+1
-1
@@ -17,7 +17,7 @@ class HUDLayer
|
|||||||
@hud_bg.draw(0, 0, Float::INFINITY)
|
@hud_bg.draw(0, 0, Float::INFINITY)
|
||||||
|
|
||||||
@inventory.draw
|
@inventory.draw
|
||||||
@health.draw(10, 10)
|
@health.draw
|
||||||
|
|
||||||
@hud_fg.draw(0, 0, Float::INFINITY)
|
@hud_fg.draw(0, 0, Float::INFINITY)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
class LorentzField
|
class LorentzField
|
||||||
BASE_TIME = 25 # Base time for the field to be active in seconds
|
BASE_TIME = 25 # Base time for the field to be active in seconds
|
||||||
|
|
||||||
def initialize
|
def initialize(bus)
|
||||||
|
@bus = bus
|
||||||
@time = 0
|
@time = 0
|
||||||
@active = false
|
@active = false
|
||||||
@font = Gosu::Font.new(24, name: "assets/fonts/tn.ttf")
|
@font = Gosu::Font.new(24, name: "assets/fonts/tn.ttf")
|
||||||
|
|
||||||
$bus.on(:lorentz_field?) do
|
@bus.on(:lorentz_field?) do
|
||||||
next @active
|
next @active
|
||||||
end
|
end
|
||||||
|
|
||||||
$bus.on(:lorentz_field) do
|
@bus.on(:lorentz_field) do
|
||||||
if @active
|
if @active
|
||||||
t = @time
|
t = @time
|
||||||
remaining = BASE_TIME - t
|
remaining = BASE_TIME - t
|
||||||
@@ -33,10 +34,10 @@ class LorentzField
|
|||||||
|
|
||||||
def attack(_direction)
|
def attack(_direction)
|
||||||
return if @active
|
return if @active
|
||||||
$bus.emit(:consume, :lorentz_field, 1)
|
@bus.emit(:consume, :lorentz_field, 1)
|
||||||
@active = true
|
@active = true
|
||||||
@time = 0
|
@time = 0
|
||||||
$bus.emit(:lorentz_field!, true)
|
@bus.emit(:lorentz_field!, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update(dt)
|
def update(dt)
|
||||||
@@ -46,7 +47,7 @@ class LorentzField
|
|||||||
if @time >= BASE_TIME
|
if @time >= BASE_TIME
|
||||||
@time = 0
|
@time = 0
|
||||||
@active = false
|
@active = false
|
||||||
$bus.emit(:lorentz_field!, false)
|
@bus.emit(:lorentz_field!, false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
class GameOver < Scene
|
||||||
|
OPTIONS = {
|
||||||
|
"Retry" => -> { $bus.emit(:change_scene, Game) },
|
||||||
|
"Main Menu" => -> { $bus.emit(:change_scene, Menu) }
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
super
|
||||||
|
@font = Gosu::Font.new(32, name: "assets/fonts/tn.ttf")
|
||||||
|
@selected_index = 0
|
||||||
|
@bg_image = Gosu::Image.new("assets/images/game_over_bg.png", retro: true)
|
||||||
|
@last_mouse_pos = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(_dt)
|
||||||
|
pos = $bus.get(:mouse_pos)
|
||||||
|
return unless pos
|
||||||
|
|
||||||
|
if @last_mouse_pos.nil? || ( (pos[0] - @last_mouse_pos[0]).abs > 2 || (pos[1] - @last_mouse_pos[1]).abs > 2 )
|
||||||
|
hovered_option = item_at(pos)
|
||||||
|
@selected_index = hovered_option[0] if hovered_option
|
||||||
|
@last_mouse_pos = pos.dup
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def draw
|
||||||
|
@bg_image.draw(0, 0, 1)
|
||||||
|
|
||||||
|
OPTIONS.each_with_index do |(text, _), index|
|
||||||
|
y = 260 + index * 50
|
||||||
|
if index == @selected_index
|
||||||
|
@font.draw_text("[ #{text.ljust(10)} ]", 50, y, 1, 1, 1, Gosu::Color::YELLOW)
|
||||||
|
else
|
||||||
|
@font.draw_text(" #{text.ljust(10)} ", 50, y, 1, 1, 1, Gosu::Color::WHITE)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def button_down(id, pos)
|
||||||
|
case id
|
||||||
|
when Gosu::KB_UP
|
||||||
|
@selected_index = (@selected_index - 1) % OPTIONS.size
|
||||||
|
when Gosu::KB_DOWN
|
||||||
|
@selected_index = (@selected_index + 1) % OPTIONS.size
|
||||||
|
when Gosu::KB_RETURN
|
||||||
|
OPTIONS.values[@selected_index].call
|
||||||
|
end
|
||||||
|
|
||||||
|
return unless id == Gosu::MS_LEFT && pos
|
||||||
|
|
||||||
|
selected_option = item_at(pos)
|
||||||
|
selected_option[1].call if selected_option
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def item_at(pos)
|
||||||
|
OPTIONS.each_with_index do |(_, action), index|
|
||||||
|
y = 260 + index * 50
|
||||||
|
if pos[1].between?(y, y + 32) && pos[0].between?(50, 50 + @font.text_width(" " * 14))
|
||||||
|
return [index, action]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
class Menu < Scene
|
class Menu < Scene
|
||||||
OPTIONS = {
|
OPTIONS = {
|
||||||
"Start" => -> { $bus.emit(:change_scene, Game.new) },
|
"Start" => -> { $bus.emit(:change_scene, Game) },
|
||||||
"Settings" => -> { $bus.emit(:change_scene, Settings.new) },
|
"Settings" => -> { $bus.emit(:change_scene, Settings) },
|
||||||
"Quit" => -> { $bus.emit(:quit_game) }
|
"Quit" => -> { $bus.emit(:quit_game) }
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ module Config
|
|||||||
@config.merge!(data.transform_keys(&:to_sym))
|
@config.merge!(data.transform_keys(&:to_sym))
|
||||||
end
|
end
|
||||||
|
|
||||||
$bus.on(:settings) { |k| @config[k] }
|
$bus.on(:settings, :master) { |k| @config[k] }
|
||||||
|
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
|
|||||||
+8
-3
@@ -12,7 +12,7 @@ class EventBus
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Subscribe to an event
|
# Subscribe to an event
|
||||||
def on(event, owner: nil, &callback)
|
def on(event, owner = nil, &callback)
|
||||||
owner ||= callback.binding.eval("self")
|
owner ||= callback.binding.eval("self")
|
||||||
@events[event] << { callback: callback, owner: owner }
|
@events[event] << { callback: callback, owner: owner }
|
||||||
end
|
end
|
||||||
@@ -51,9 +51,14 @@ class EventBus
|
|||||||
results
|
results
|
||||||
end
|
end
|
||||||
|
|
||||||
# Unsubscribe all events for a given owner (e.g. when an object is destroyed)
|
def reset
|
||||||
|
@events.each do |_, handlers|
|
||||||
|
handlers.reject! { |h| h[:owner] != :master }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def remove_owner(owner)
|
def remove_owner(owner)
|
||||||
@events.each do |event, handlers|
|
@events.each do |_, handlers|
|
||||||
handlers.reject! { |h| h[:owner] == owner }
|
handlers.reject! { |h| h[:owner] == owner }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -12,8 +12,4 @@ class Scene
|
|||||||
|
|
||||||
def button_down(id, pos)
|
def button_down(id, pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
def close
|
|
||||||
$bus.remove_owner(self)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
@@ -7,6 +7,7 @@ require_relative 'utils/utils'
|
|||||||
require_relative 'utils/scene'
|
require_relative 'utils/scene'
|
||||||
require_relative 'settings/scene'
|
require_relative 'settings/scene'
|
||||||
require_relative 'menu/scene'
|
require_relative 'menu/scene'
|
||||||
|
require_relative 'game_over/scene'
|
||||||
require_relative 'game/scene'
|
require_relative 'game/scene'
|
||||||
|
|
||||||
class Window < Gosu::Window
|
class Window < Gosu::Window
|
||||||
@@ -23,18 +24,18 @@ class Window < Gosu::Window
|
|||||||
@scene = Menu.new
|
@scene = Menu.new
|
||||||
@last_time = Gosu.milliseconds
|
@last_time = Gosu.milliseconds
|
||||||
|
|
||||||
$bus.on(:quit_game) { close! }
|
$bus.on(:quit_game, :master) { close! }
|
||||||
|
|
||||||
$bus.on(:mouse_pos) do
|
$bus.on(:mouse_pos, :master) do
|
||||||
next mouse_relative(mouse_x, mouse_y)
|
next mouse_relative(mouse_x, mouse_y)
|
||||||
end
|
end
|
||||||
|
|
||||||
$bus.on(:change_scene) do |new_scene|
|
$bus.on(:change_scene, :master) do |new_scene|
|
||||||
@scene.close
|
$bus.reset
|
||||||
@scene = new_scene
|
@scene = new_scene.new
|
||||||
end
|
end
|
||||||
|
|
||||||
$bus.on(:shade) do
|
$bus.on(:shade, :master) do
|
||||||
shade!
|
shade!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user