The menu also takes care of notifying me when an item has been clicked via a callback, and also offsets the position of the item on hover.
The following is the basic gist of how it can be used:
@menu = Menu.new(self) #instantiate the menu, passing the Window in the constructor @menu.add_item(Gosu::Image.new(self, "item.png", false), 100, 200, 1, lambda { self.close }, Gosu::Image.new(self, "item_hover.png", false)) @menu.add_item(Gosu::Image.new(self, "item2.png", false), 100, 250, 1, lambda { puts "something" }, Gosu::Image.new(self, "item2_hover.png", false))
The arguments of add_item are the image showed when the item is in its normal state, the x position, y position, z-order, the callback that will be invoked when that item is clicked and finally an optional parameter of an image that is used when the item is hovered upon.
Then hook to the button_down event of your Window, and inform the menu that the mouse has been clicked:
def button_down (id) if id == Gosu::MsLeft then @menu.clicked end end
Finally, just draw and update the menu in the hooked methods:
def update @menu.update end def draw @menu.draw end
I made a simple demo of this and you can download it from here.
The following is the source of the two aforementioned classes:
class Menu def initialize (window) @window = window @items = Array.new end def add_item (image, x, y, z, callback, hover_image = nil) item = MenuItem.new(@window, image, x, y, z, callback, hover_image) @items << item self end def draw @items.each do |i| i.draw end end def update @items.each do |i| i.update end end def clicked @items.each do |i| i.clicked end end end
class MenuItem HOVER_OFFSET = 3 def initialize (window, image, x, y, z, callback, hover_image = nil) @window = window @main_image = image @hover_image = hover_image @original_x = @x = x @original_y = @y = y @z = z @callback = callback @active_image = @main_image end def draw @active_image.draw(@x, @y, @z) end def update if is_mouse_hovering then if !@hover_image.nil? then @active_image = @hover_image end @x = @original_x + HOVER_OFFSET @y = @original_y + HOVER_OFFSET else @active_image = @main_image @x = @original_x @y = @original_y end end def is_mouse_hovering mx = @window.mouse_x my = @window.mouse_y (mx >= @x and my >= @y) and (mx <= @x + @active_image.width) and (my <= @y + @active_image.height) end def clicked if is_mouse_hovering then @callback.call end end end
Note that both the code and the method in general can be greatly improved and refactored. Just take a look at the code and modify it as you see fit :)