Hello. I'm working on a virtual pet game in pico-8 and need some help on how to make in-game menu. In the game, the menu is how you care for the pet with options like feed and cure and the options have sub menus for different options like which type of food you want. The main menu options are represented by icons but the sub menus are represented by text. The problem I'm running into is creating the menus in the first place as I can't figure out a solution to this and the options I have looked up online I can't make sense of the code.
Basically, you need a way to keep track of which option is currently selected, a way to show each option when they're not selected, a way to show each option when they're selected, and a way to switch options. If you're going to use mouse support, then switching options will probably mean a hit test (which is about the same as a collision test). Otherwise, switching options will mean a way to keep track of which options are connected to which other options.
If you're good at using tables, I would recommend each menu option be put in a table containing its drawing function, a function on being clicked, and an indication of whether they're currently selected, then put all the menu options in an over-arching table in the order that makes the most sense for how they'll be arranged on screen (ie. top to bottom if they're in a vertical line) along with an indication of which is currently selected by index. From there you can respond to input by moving the currently selected index, updating the options on which is currently selected, and then call the functions all neeeded. This method also has the benefit that if you have multiple menus in memory at once and a good menu drawing function to run through them, you can have submenus by just drawing multiple menus but only updating ones that are currently accessible. In the case that you want a grid instead of a line of options, you can still use a single index value, but combining that with the width of the grid to derive an x and y value with the %
and \
operators. Also, since you have a specific common ways of drawing that you mentioned, prototyping the menu options might help. Basically, you just make function for each type of menu option that returns a table with the settings for that option type.
If you're not good with tables and not in a position to practice using them and read about them and such, I would instead recommend having a separate drawing/updating pair of functions for each menu and just use long if/elseif chains. It's not token or speed efficient, but it does still work.
Related, you'll also want to decide how to show which option is selected. If you have a cursor image (like a arrow) you could just have the menu option that's current selected draw the arrow next to itself as a solution to both option type. Similarly, drawing a rectangle, circle or ellipse behind the menu option works too. If you'd rather have then be highlighted, then the text ones can just change text color, but the icons might need a separate version of each icon to highlight them.
This topic shows generic ways to have multiple game states: https://www.lexaloffle.com/bbs/?tid=34476
A menu is basically just a list of actions so a simple—not necessarily best or most efficient—implementation is just to use an array of labels and functions. Ignoring nested menus for the moment, a simple menu could work like this:
-- create a menu for changing the screen color. -- the background color of the screen bg = 0 -- the currently selected menu item selection = 1 colors_menu = { {'red', function() bg=8 end}, {'green', function() bg=11 end}, {'blue', function() bg=12 end}, } |
Then you can write functions for drawing and updating your menus.
function draw_menu(m) for i=1,#m do if i==selection then -- if this item is the selection print an arrow and then the -- label print('> '..m[i][1]) else -- if it's not the selection only print the label (with a -- couple spaces so everything lines up. print(' '..m[i][1]) end end end function update_menu(m) -- change the currently selected/highlighted item if btnp(2) then selection -= 1 elseif btnp(3) then selection += 1 end -- wrap the cursor from top to bottom or bottom to top as -- appropriate. if selection > #m then selection = 1 elseif selection < 1 then selection = #m end -- activate the current selection if btnp(4) then m[selection][2]() end end |
Finally, use those functions in _update and _draw.
function _update() update_menu(colors_menu) end function _draw() cls(bg) draw_menu(colors_menu) end |
Nested menus can work pretty much exactly the same way. Add new menus, add a variable to keep track of which menu is currently active, and add an item to the existing menu whose action changes the currently active menu. Like so:
colors_menu = { {'red', function() bg=8 end}, {'green', function() bg=11 end}, {'blue', function() bg=1 end}, {'nested', function() current_menu = nested_menu selection = 1 end } } nested_menu = { {'black', function() bg=0 end}, {'brown', function() bg=4 end}, } current_menu = colors_menu |
And then just change _update and _draw to use the current_menu.
function _update() update_menu(current_menu) end function _draw() cls(bg) draw_menu(current_menu) end |
These are pretty bare-bones but you can modify the draw_menu and update_menu functions to display them where and how you want and add additional functionality like being able to close or navigate back to the previous menu as two obvious examples.
In my examples the menu/action functions don't take any parameters but, of course, they certainly can. So for your use case, I'd probably have all of the functions take the pet as an input and then the function can do whatever it needs to do: increase health, decrease hunger, or whatever.
Hope that helps.
[Please log in to post a comment]