Difference between revisions of "Menu Tutorial by NeoLogiX"

From Spherical
Jump to: navigation, search
(created)
 
m (An example menu system: boldface)
Line 102: Line 102:
 
Here would be where I would put an example of a menu system using the skeleton procedure. Until this article is updated feel free to look for the various incarnations of my NMenu system to study:
 
Here would be where I would put an example of a menu system using the skeleton procedure. Until this article is updated feel free to look for the various incarnations of my NMenu system to study:
  
* NMenu v1 is meant to be a replacement for the functionality of Flikky's menu system [[Script:flik_menu.js|flik_menu]]. NMenu v1 can display menu items in a grid arrangement and supports custom background and foreground elements in a manner similar to [[Script:flik_menu.js|flik_menu]]
+
* '''NMenu v1''' is meant to be a replacement for the functionality of Flikky's menu system [[Script:flik_menu.js|flik_menu]]. NMenu v1 can display menu items in a grid arrangement and supports custom background and foreground elements in a manner similar to [[Script:flik_menu.js|flik_menu]]
** NRingMenu is a fork of NMenu v1 modified to imitate the ring-style arrangement of menu items in a manner similar to Secret of Mana.
+
** '''NRingMenu''' is a fork of NMenu v1 modified to imitate the ring-style arrangement of menu items in a manner similar to Secret of Mana.
** NSimpleMenu is a fork of NMenu v1 modified to only allow display of a single-column or single-row arrangement of menu items and is meant to be a replacement for Sphere's [[Script:system/menu.js|menu.js system script]]
+
** '''NSimpleMenu''' is a fork of NMenu v1 modified to only allow display of a single-column or single-row arrangement of menu items and is meant to be a replacement for Sphere's [[Script:system/menu.js|menu.js system script]]
* NMenu v2 is an update to NMenu that allows more customization than NMenu v1 and allows creation of custom menu item arrangements without modifying the base NMenu code; it was created in an attempt to mimic a highly stylized menu system created by Sphere user Caldimion.
+
* '''NMenu v2''' is an update to NMenu that allows more customization than NMenu v1 and allows creation of custom menu item arrangements without modifying the base NMenu code; it was created in an attempt to mimic a highly stylized menu system created by Sphere user Caldimion.
* NMenu v3 is an update to NMenu that added support for using input devices other than the keyboard and increased support for non-text menu items like images and animated spritesets. NMenu v3 was initially created for a "Make a menu system in Sphere" competition.
+
* '''NMenu v3''' is an update to NMenu that added support for using input devices other than the keyboard and increased support for non-text menu items like images and animated spritesets. NMenu v3 was initially created for a "Make a menu system in Sphere" competition.
  
 
==In closing==
 
==In closing==

Revision as of 19:43, 2 August 2013

One of the most common elements of any game, RPG or otherwise, is a menu system. Menus are very flexible in purpose and are used for presenting data and choice in a straightforward manner. This theory-based tutorial may not contain actual code, but that's because each person may have his or her own unique coding style. It's up to you, the user, to come up with a way to accomplish what I demonstrate.

Creating a skeleton

You'll most likely want a Menu object that you can use to keep track of things common to each menu, like a background pic, items from which to choose, etc. Below is a list of the most likely things your menu system should contain:

  1. Graphics; a background image, other background elements like windowstyles, the little things like animations, any/all the stuff you plan on blitting during menu execution
  2. A list of items from which to choose; items can be plain text or they can be represented by images and/or other visuals like animations.
  3. Sounds; most useful menus have feedback of multiple types when you perform an action, and a sound that plays when you move the cursor/choose a menu item/exit the menu/etc is one of the most common types of feedback.
  4. A list of events that may happen when an action is performed; actions performed include but are not limited to moving the cursor, choosing a menu item, exiting the menu, and skipping disabled menu items.
  5. A timer, because timers are useful for lots of things ;)

Okay, now you should have a basic menu object ready. A menu usually runs on a loop. That loop should keep going until the menu is done, and the menu being done is a condition that you can determine. Take a look at the following:

Menu system pseudo-skeleton

MENU:

  • initialize menu vars
  • start timer
  • MAIN LOOP:
    • blit bg & under-elements
    • blit menu items & main elements
    • draw fg & over-elements
    • FlipScreen()
    • HANDLE EVENTS/ACTIONS:
      process cursor movement
      process item selection and/or menu escaping
      process constant events (update timers, etc)
      END HANDLE EVENTS
    • check for menu end conditions
    • if conditions are not met, continue
    • else END MAIN LOOP
  • stop timer
  • resolve menu's end (return to maps, title screen, etc)
  • reset menu info (reset graphics positions, reset timers, etc)
  • END MENU

That's basically the process a menu goes through. Keep in mind this is pseudo-code and implementing it in your game's programming style is the tricky part. In my opinion the easiest part is deciding where to put all the graphic elements. The hard part is handling the actions. This skeleton may be edited/updated in the future to include other menu system types, such as the ring-style menus found in Secret of Mana. Further explanation of each phase of the menu follows.

Dissecting the skeleton

Here we'll discuss the above phases at length.

Initialize phase

Initialize menu vars
There are usually no visible effects when these particular initializations take place. Such variables include windowstyle placement vars, user-triggered flags such as "show cursor," etc.
Initialize menu item vars
If there are any disabled menu items, treat them as disabled.
Start timers
It's recommended that there's always at least one timer running in the background - the main menu timer. This particular timer should be used for timed events general to the entire menu system and its submenus, as well as animation of global menu imagery like backgrounds and foregrounds. Other timers you can use include ones that keep track of animation of individual menu items, though if you code menu items thoroughly each item would likely have its own individual timer independent of the menu's global timers.

Main loop

For the purposes of this tutorial, a menu's main loop consists of three stages or phases: a blit phase, an action/event-handling phase, and a phase to check for menu-ending conditions. They are described below.

Blit phase

The blit phase should be used to do nothing but draw all your graphical elements to the screen. It is highly recommended you separate your blit phase into the following three functions:

Blit backgrounds & underlays
Even menus in RPGs as old as Final Fantasy and Phantasy Star had a "dynamic background" somehow; it didn't necessarily animate as some later games do, but instead was often the map itself. Draw your background elements here (if you set your code up properly, you can even have animated elements in your background such as moving clouds or a rotating zodiac that run along a timer), as well as any underlaid elements. Underlays include windowstyles for the menu itself, for menu items, and for static persistent data like "amount of money," but make sure background elements are drawn first.
Blit menu items & primary elements
Where are the menu items? Here. Draw the items, static and dynamic, active and disabled, in this stage. Also include any static persistent data like an "amount of money" box in the corner. Specialized menus like a party management menu would draw the party here, for example.
This stage is also where you'd draw the animations for those elements that animate like a spriteset menu item.
Blit foregrounds & overlays
For most menu systems, all that's left to draw are foregrounds and any overlaid elements not yet handled. Foregrounds can include more clouds and animated glows, and overlays include a target pointer over the highlighted menu item.
FlipScreen()
Always remember to flip the screen after something is drawn, otherwise you won't be able to see it. The above structure of a menu system does all of its visual rendering before any action processing, though design specs can allow for mingling the two processes.

Event-handling phase

Well-written design specs for a menu system should have the render phase separated from the action/event-handling phase.

Process cursor movement
A menu is essentially an array that keeps track of what choice is currently highlighted and whether it's selectable or not. At its core, cursor movement is basically increasing or decreasing the index that points to which item is highlighted, with possible customization to handle non-standard arrangements like grids and mouse input. Common events include playing a "cursor moved" sound and/or animating movement of the cursor to the newly highlighted item.
There are a few schools of thought as to the format of a menu item. It's really dependent on the requirements of the design specs, but usually used is an array of objects in the format { itemtype, itemid, itemaction }, where itemtype is the menu item type (usually "text" or "image" with other values as needed), itemid is the index of the item relative to the rest of the menu choices ('0' is the first menu item, '1' is the second, etc.), and itemaction is the action that would execute when the item is selected. itemaction is usually a function, the specs of which were presumably determined long before the menu system was coded, but can also affect other menu items as needed and/or even the menu itself.
Process item selection and/or menu escaping
Get ready to execute a function. If a highlighted menu item is selected, perform its associated action. If a menu's escape key/button is pressed, exit the active menu. The design specs should also include whether timers continue during this menu processing or not, as well as if a given menu system allows for submenu processing without creating new menu instances.
Process constant events
Automatic events are handled here - properly updating timers for animations like outline glowing, spriteset animation, cursor animation, etc. Update them here.

End phase (aka "Is the main loop done?")

We have to end the menu somehow. Check for it here.

Check for menu end conditions
If the menu's end conditions are not met, continue the menu as detailed above and/or as detailed in your design specs.
Else, if the menu's end conditions are met, end the main loop.

End conditions can be as simple as "the menu's escape key or button has been pressed;" end conditions are usually defined per-menu if special circumstances are necessary, and such per-menu circumstances should be defined in your design specs. Special end conditions include a countdown timer reaching zero (eg, if a story event has an NPC only giving the player 10 seconds to choose a menu item).

Resolve phase

Once main loop has completed, everything about the active menu needs to be resolved. Do that here.

Stop timers
If there are any running timers dependent on the actual menu loop, stop them. This will stop any animation dependent on that timer, though if your menu system is coded thoroughly you can initialize a new timer that will handle menu-exiting animations and such.
Resolve menu's end
If you chose a menu item, execute that item's action if it hasn't already been executed. If you don't code your menu to include submenu handling, you can instead code your items' actions to create new menus; keep in mind that execution of these menus would likely block, therefore the base menu won't finish resolving until those menus are escaped.
If you simply escape the menu, however, usually nothing would execute and control would return to whatever had it last. A simple escape function could include playing a different "menu escaped" sound while the menu animates closing.
Reset menu info
There are generally two ways to create a menu: use one menu over and over (many games do this), or copy an existing menu (some other games do this). If you program your game to copy an existing menu, you only have to keep track of the copy, and once the menu is done you can trash that copy. If you program your game to use a menu over and over, however, you need to account for that in this phase. Some games allow remembering the cursor position of various menus, some allow changing the menu's colors or other graphical elements. Positions of graphical elements would also need to be reset to their pre-execution positions, especially if animations are dependent on their positions.
Timers may have been running during the menu's execution. Reset any timers to zero that are temporary for this menu. If a global timer is running but was paused during menu execution, have it unpause.
Return to the map
It is recommended to provide a graphical transition to play so that the change from menu screen to map screen isn't sudden and "unnatural." This transition can be a menu shrink, a menu fade out, etc. It doesn't have to be stylish or complicated, though other than my own N-Trans library there seems to be a lack of graphical screen transition functions readily available in Sphere.

An example menu system

Here would be where I would put an example of a menu system using the skeleton procedure. Until this article is updated feel free to look for the various incarnations of my NMenu system to study:

  • NMenu v1 is meant to be a replacement for the functionality of Flikky's menu system flik_menu. NMenu v1 can display menu items in a grid arrangement and supports custom background and foreground elements in a manner similar to flik_menu
    • NRingMenu is a fork of NMenu v1 modified to imitate the ring-style arrangement of menu items in a manner similar to Secret of Mana.
    • NSimpleMenu is a fork of NMenu v1 modified to only allow display of a single-column or single-row arrangement of menu items and is meant to be a replacement for Sphere's menu.js system script
  • NMenu v2 is an update to NMenu that allows more customization than NMenu v1 and allows creation of custom menu item arrangements without modifying the base NMenu code; it was created in an attempt to mimic a highly stylized menu system created by Sphere user Caldimion.
  • NMenu v3 is an update to NMenu that added support for using input devices other than the keyboard and increased support for non-text menu items like images and animated spritesets. NMenu v3 was initially created for a "Make a menu system in Sphere" competition.

In closing

If there are any questions, you can ask at the forums or the Talk. Happy coding! Apollolux (talk) 22:16, 31 July 2013 (UTC)