Sign in to follow this  
davj88

good/best way to build up a menu

Recommended Posts

using VS2008, D3D sdk march 2008, xp OS hi guys! As you can read in the title, I was asking myself how should I build up a smart 'menu' system. I've read some articles and guides but they have confused me for the most: Right now I have a very simple menu which is displayed on startup with "Play/Quit" and a little arrow "->" that shows the user's current selection. In order to make it I've two globals (bool _menu, bool _play) and two Render() [Render() and MenuRender()]. As the user selects "Play" I switch _bool and _menu and so do the Render() functions. This brings me the first problem: should I keep on having so much globals just to make a 'page' of the menu? For example, if I have Play/Credits/Score/Music Room/Replay... and so on, I am forced to use a global for each page and a Render for each page, which is (I suppose) very very nasty. The next thing I was worried about was the way to 'display' the menu and, moreover, how to track the user's choice: Now I'm using a RECT rect1 to 'draw' text on the screen, and RECT rect2 to 'move' the little arrow '->'. Whenever the user types Enter (or Z) I check rect2.top and use a swtich(rect2.top) in order to understand what the user wants to do. This works fine with just 1 menu page and 2 simple options such as Play / Quit, but I have the feeling it will only get worse if I need to add pages and options (since I'll have to check in which page of the menu the user is right now, comparing with the globals, etc, etc leading to a long and useless code). Even if I can keep on this way, I'm sure there is a better way to handle everything. Should I use scripts in some way? Should I use a menu class? Should I use and array of functions? Should I use all of the above? What would you use? What do you use :P? I'm not asking you the actual 'code' for everything, I just want some advices and/or links to good (not already read :P) guides and so on ^^. I hope I'm not bothering too much ^^

Share this post


Link to post
Share on other sites
You seem to have a decent idea of how to use your tools, but your theory isn't quite there--from your description, I would say that you need to decouple interface and logic more.

For example, you say you're switching based on "rect2.top". This isn't a good idea; your logic is depending on an implementation detail. What you should be doing is having some sort of enumeration or other indicative value in the backend, using that for your logic code, and rendering based on that indicative value (assigning rect2.top, where you're drawing your indicator arrow, based on it). Your way works, but it is not clean and maintaining it is going to be a serious pain.

Generally--and this is not a hard and fast rule, but it seems to be true in this case--global variables are bad, and there are almost always better ways to provide the same functionality. I would abstract each rendering subsystem into a separate class (all inheriting from the same base class). My own projects generally have a "SceneController" class which I subclass for menus and the game itself, with an Update() and a Draw() method. Handle game logic and state changes with the Update() method, and Draw() the screen. It has some other benefits, but that's the big one. (I use C# rather than C++, so this may be a little harder to set up in C++, but it should be the same principles.)

-Ed

Share this post


Link to post
Share on other sites
Quote:
Original post by EdR
You seem to have a decent idea of how to use your tools, but your theory isn't quite there--from your description, I would say that you need to decouple interface and logic more.


That's the point.
Even if I can 'render' what I have in my mind, I always lack of order and efficiency. Unfortunatelly I can see this is not an easy subject to 'teach' (and even learn) since maybe it's greatly based on experience.
I've read something about a script enging in order to setup the menu and handle it, but it really scared me. I was going to use class somehow instead but I needed some advices.

"My own projects generally have a "SceneController" class which I subclass for menus and the game itself, with an Update() and a Draw() method. Handle game logic and state changes with the Update() method, and Draw() the screen."

Do you mean that you have multiple Update() and Draw() for each 'state' (for example, menu page) your game should reach?

I'm very confused, forgive me :P



Share this post


Link to post
Share on other sites
Quote:
Do you mean that you have multiple Update() and Draw() for each 'state' (for example, menu page) your game should reach?
Basically, yes. Here's a hypothetical example. This is probably not the best way to do this, mind you, but it works for me. Code will be C#-ish (this has not been actually built, so syntax errors ahoy), but the principles should be obvious.


public class SceneController
{
protected Boolean isRunning = true;

public SceneController() { }

public abstract void Update();
public abstract void Draw();

public virtual void Go()
{
while (this.isRunning)
{
this.Update(); // my own code has Update return a Boolean
// that is stored in my equivalent of isRunning,
// but that's just implementation details
this.Draw();
}
}
}




My individual scene controllers - be they a rolling list of credits, the main menu, or the main game scene - all subclass from SceneController. While there's probably a better way to handle shifting between scene controllers, I do it inline, as below. There are some probably-obvious advantages to doing it this way. (My own code has a few beautifiers that I've omitted here, that support gradual fade-ins and fade-outs, but you can add that yourself.)


public override void Update()
{
// do some stuff
DialogBoxController dBox = new DialogBoxController("Do you want to answer Yes or No?", DialogBoxController.Buttons.YesNo);
dBox.Go(); // this starts the Go() loop of the secondary controller, which
// will run until it sets its own isRunning to false; for the
// example here we'll guarantee that dBox will store a result
// value in a field.
Debug.Print(dBox.Result); // will echo something like "Namespace.DialogBoxController.ButtonResult.Yes")
// do more stuff
}




It's a little hackish if you're going one-way and never intend to return to the previous scene controller, I admit that, and I suppose you could have stack overflows from a truly obscene number of recursive calls, but I know of no more straightforward way to do it. I also do not work with 3D graphics, so there may be additional requirements in that realm that make this unfeasible.

-Ed

Share this post


Link to post
Share on other sites
thanks for you reply!
I'm trying to code a .cpp class hierarchy using your example. I'm quite new with classes, virtual and abstract stuffs. It'll be a good exercise anyway :P
Still I don't get how do you manage to return to the previous menu page (SceneController). I mean:

dBox.Go(); // this starts the Go() loop of the secondary controller, which
// will run until it sets its own isRunning to false; for the
// example here we'll guarantee that dBox will store a result
// value in a field.

If the user types Escape in order to go back in the menu 'flow', your secondary controller will handle this message and terminate. (right?).
But what's next? How do you keep trace of the previous menu page? Do you store it somewhere or do you handle it just with classes?

I do admit I still lack of insight using classes and maybe there is something that should be obvious to me but it is not :P

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this