Skip to content

Menu Buttons

noooway edited this page May 22, 2017 · 33 revisions

In this part I want to implement a simple main menu screen.

I use a simple menu, that consist of just two buttons: "Play" and "Quit". Each button is a rectangle, represented by it's own image (in fact, a different quads of the same image). A button has a selected flag, which is activated if a mouse pointer hovers over it. If a button is selected, it's image changes.

Being a rectangle, a button needs position, width, and height. To display a texture, it needs an image and a quad. A different quad is used if the selected flag is active. If no image or quad is provided, a text is displayed instead. According to this description, a button constructor has the following form.

function buttons.new_button( o )
   return( { position = o.position or vector( 300, 300 ),
             width = o.width or 100,         
             height = o.height or 50,
             text = o.text or "hello",
             image = o.image or nil,
             quad = o.quad or nil,
             quad_when_selected = o.quad_when_selected or nil,
             selected = false } )
end
  1. Update and draw
function buttons.update_button( single_button, dt )
   local mouse_pos = vector( love.mouse.getPosition() )
   if( buttons.inside( single_button, mouse_pos ) ) then
      single_button.selected = true
   else
      single_button.selected = false
   end
end

function buttons.draw_button( single_button )
   if single_button.selected then
      if single_button.image and single_button.quad_when_selected then
         love.graphics.draw( single_button.image,
                             single_button.quad_when_selected, 
                             single_button.position.x,
                             single_button.position.y )
      else
         love.graphics.rectangle( 'line',
                                  single_button.position.x,
                                  single_button.position.y,
                                  single_button.width,
                                  single_button.height )
         local r, g, b, a = love.graphics.getColor()
         love.graphics.setColor( 255, 0, 0, 100 )
         love.graphics.print( single_button.text,
                              single_button.position.x,
                              single_button.position.y )
         love.graphics.setColor( r, g, b, a )
      end
   else
      if single_button.image and single_button.quad then
         love.graphics.draw( single_button.image,
                             single_button.quad, 
                             single_button.position.x,
                             single_button.position.y )
      else
         love.graphics.rectangle( 'line',
                                  single_button.position.x,
                                  single_button.position.y,
                                  single_button.width,
                                  single_button.height )
         love.graphics.print( single_button.text,
                              single_button.position.x,
                              single_button.position.y )         
      end
   end
end

function buttons.inside( single_button, pos )
   return
      single_button.position.x < pos.x and
      pos.x < ( single_button.position.x + single_button.width ) and
      single_button.position.y < pos.y and
      pos.y < ( single_button.position.y + single_button.height )
end
  1. In the "menu" state create start and quit buttons:
local menu_buttons_image = love.graphics.newImage( "img/800x600/buttons.png" )
local button_tile_width = 128
local button_tile_height = 64
local play_button_tile_x_pos = 0
local play_button_tile_y_pos = 0
local quit_button_tile_x_pos = 0
local quit_button_tile_y_pos = 64
local selected_x_shift = 128
local tileset_width = 256
local tileset_height = 128
local play_button_quad = love.graphics.newQuad(
   play_button_tile_x_pos,
   play_button_tile_y_pos,
   button_tile_width,
   button_tile_height,
   tileset_width,
   tileset_height )
local play_button_selected_quad = love.graphics.newQuad(
   play_button_tile_x_pos + selected_x_shift,
   play_button_tile_y_pos,
   button_tile_width,
   button_tile_height,
   tileset_width,
   tileset_height )
local quit_button_quad = love.graphics.newQuad(
   quit_button_tile_x_pos,
   quit_button_tile_y_pos,
   button_tile_width,
   button_tile_height,
   tileset_width,
   tileset_height )
local quit_button_selected_quad = love.graphics.newQuad(
   quit_button_tile_x_pos + selected_x_shift,
   quit_button_tile_y_pos,
   button_tile_width,
   button_tile_height,
   tileset_width,
   tileset_height )

function menu.load( prev_state, ... )
   start_button = buttons.new_button{
      text = "New game",
      position = vector( (800 - button_tile_width) / 2, 200),
      width = button_tile_width,
      height = button_tile_height,
      image = menu_buttons_image,
      quad = play_button_quad,
      quad_when_selected = play_button_selected_quad
   }
   quit_button = buttons.new_button{
      text = "Quit",
      position = vector( (800 - button_tile_width) / 2, 310),
      width = button_tile_width,
      height = button_tile_height,
      image = menu_buttons_image,
      quad = quit_button_quad,
      quad_when_selected = quit_button_selected_quad
   }
   music:play()
end
  1. Draw and update the buttons
function menu.update( dt )
   buttons.update_button( start_button, dt )
   buttons.update_button( quit_button, dt )
end

function menu.draw()
   buttons.draw_button( start_button )
   buttons.draw_button( quit_button )
end
  1. On mousepress quit or activate gamestate
function menu.mousereleased( x, y, button, istouch )
   if button == 'l' or button == 1 then
      if buttons.mousereleased( start_button, x, y, button ) then
         gamestates.set_state( "game", { current_level = 1 } )
      elseif buttons.mousereleased( quit_button, x, y, button ) then
         love.event.quit()
      end
   elseif button == 'r' or button == 2 then
      love.event.quit()
   end    
end

function buttons.mousereleased( single_button, x, y, button )
   return single_button.selected 
end

    Home
    Acknowledgements
    Todo

Chapter 1: Prototype

  1. The Ball, The Brick, The Platform
  2. Game Objects as Lua Tables
  3. Bricks and Walls
  4. Detecting Collisions
  5. Resolving Collisions
  6. Levels

    Appendix A: Storing Levels as Strings
    Appendix B: Optimized Collision Detection (draft)

Chapter 2: General Code Structure

  1. Splitting Code into Several Files
  2. Loading Levels from Files
  3. Straightforward Gamestates
  4. Advanced Gamestates
  5. Basic Tiles
  6. Different Brick Types
  7. Basic Sound
  8. Game Over

    Appendix C: Stricter Modules (draft)
    Appendix D-1: Intro to Classes (draft)
    Appendix D-2: Chapter 2 Using Classes.

Chapter 3 (deprecated): Details

  1. Improved Ball Rebounds
  2. Ball Launch From Platform (Two Objects Moving Together)
  3. Mouse Controls
  4. Spawning Bonuses
  5. Bonus Effects
  6. Glue Bonus
  7. Add New Ball Bonus
  8. Life and Next Level Bonuses
  9. Random Bonuses
  10. Menu Buttons
  11. Wall Tiles
  12. Side Panel
  13. Score
  14. Fonts
  15. More Sounds
  16. Final Screen
  17. Packaging

    Appendix D: GUI Layouts
    Appendix E: Love-release and Love.js

Beyond Programming:

  1. Game Design
  2. Minimal Marketing (draft)
  3. Finding a Team (draft)

Archive

Clone this wiki locally