Menu's in XNA

Started by
12 comments, last by falcon93 12 years, 9 months ago
I am a total noob in XNA. I mean, I know some stuff, but am a total noob.

I am having troubles with making a menu in XNA like Play, Credits, Exit.

I want it so you can click the Play, Credits, Exit and have the credits show, and then for play make it so that the menu "hides or disappears" and then the playing screen shows.

Thanks
Advertisement
Moving to For Beginners.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

There's a couple tutorials in the Education Catalog you might start with.

Game State Management Sample

Network Game State Management
This is actually pretty easy to do if you are familiar with object-orientated programming.

First of all, you want to be able to hide/show your menu (collection of buttons), and it would also be good to have a place to check button clicks. Therefore, it can be a good idea to do a MainMenu class. In your main menu class, you can do like this to get ability to show/hide your menu:


public void Update()
{
if (visible)
{
button_play.Update();
button_credits.Update();
button_quit.Update();
}
}

public void Draw()
{
if (visible)
{
button_play.Draw();
button_credits.Draw();
button_quit.Draw();
}
}



If you want to show you menu, simply set the the bool visible to true, and if you want to hide it, change it to false.
Ex:
main_menu.visible = true;

When you want to check button click, put this code in your main_menu class:

public void Update()
{
Point x = new Point(Mouse.GetState().X, Mouse.GetState().Y);

if (visible)
{
button_play.Update();
button_credits.Update();
button_quit.Update();

if (Mouse.GetState().LeftButton == ButtonState.Pressed)
{
if (button_play.rectangle.Contains(x))
{
// What happens when the button was clicked?
}

if (button_credits.rectangle.Contains(x))
{
// What happens when the button was clicked?
}

if (button_quit.rectangle.Contains(x))
{
// What happens when the button was clicked?
}
}

}
}



Hope that helps. Maybe I missunderstood what you searched help for, if so just shout smile.gif
Falcon93 is quite correct on many points so i am just going to add something more. A menu is basically a collection of States or at least where sub options of the menu are incurred. What this means is that it really is just a branching section in the code that breaks the game down and runs along a path selected.

Simply put you could even do it with a switch statement if you really wanted to do but there are better ways. One of the best ways to do it is with a Game State management system each part of your game could be referred to as a state eg ( Menu, Options, Game Play, HighScore )

Each on of these states are separate from each other in one form of way or another and can have there own code to deal with just there state. Writing a Game State Manager is not really to hard but depending on the features you want it to have it can become more difficult. But it basically breaks down like this.

Game State Manager

Screen " Represents a game state"

The Game State Manager runs one screen at a time calling methods from the Screen class such as Update and Draw.
You inherit the screen class to make the Game State for example you can have a MenuScreen and in that all the code to the menu could go.

There are a lot of examples on how to do this across the web if you really want to make a game and worries less about the underlying stuff i suggest taking a look at the XNA Game Engine
called Flat Red Ball http://FlatRedBall.com you can find me there from time to time and it comes with the above mentioned Game State Management.

Regards XainFaith
Thanks. Helped out a lot.
I want to jump in and comment based on my experience. The snippet of code regarding checking if the mouse is currently pressed and then processing the clicks will likely cause a problem (may not, I'm not sure if XNA is super magical, as I've never worked with it). The issue comes from the fact that the user may click (press and then release) the mouse entirely between times which this condition is checked, which could result in a click being completely ignored. The way I've solved this in the past is by having a 'mouse' class which responds to any sort of mouse event, and keeps track of buttons that are currently pressed, and buttons that have been pressed AT ANY POINT since the last time the class was instructed to reset itself, resulting in two separate 'checking' functions, "isPressed(int Button)" and "hasBeenPressed(int Button)". I'm not aware if xna deals with input in this event oriented method, but I don't see why it wouldn't. In the time since I worked out this solution, I've seen it in at least a couple of places, so I'm sure it's fairly standard.

EDIT: yeah, it's probably worth downvoting some advice just because it doesn't necessarily apply to you. Thanks, whoever.
Here is a bit to get your started off since XNA does not use a polling input system things can become tricky very fast and checking for a left mouse down is not that same as a click.

Here is my mouse class for XNA 4.0 the MouseEventData is just a struct with some basic data you can pass down ill add it too so you can see it.

[source]

public delegate void MouseEvent(MouseEventData mouseData);

internal class MouseInput
{
#region Fields

public int X { get; private set; }
public int Y { get; private set; }

#endregion

#region Events

private MouseState LastState;

public event MouseEvent MouseLeftDown;
public event MouseEvent MouseLeftUp;

public event MouseEvent MouseRightDown;
public event MouseEvent MouseRightUp;

public event MouseEvent MouseMove;

#endregion

#region Constructor

public MouseInput()
{
this.LastState = Mouse.GetState();
}

#endregion

#region Update Method

public void Update()
{
MouseState mState = Mouse.GetState();
this.X = mState.X;
this.Y = mState.Y;

MouseEventData mouseData = new MouseEventData();

#region Mouse Move Event

if (this.LastState.X != mState.X || this.LastState.Y != mState.Y)
{
mouseData.X = mState.X - LastState.X;
mouseData.Y = mState.Y - LastState.Y;
mouseData.Button = MouseButton.None;
if (this.MouseMove != null)
{
this.MouseMove(mouseData);
}
}

#endregion

mouseData.X = this.X;
mouseData.Y = this.Y;

#region Check for Left button Mouse input

if (mState.LeftButton == ButtonState.Pressed)
{
if (this.LastState.LeftButton == ButtonState.Released)
{
if (this.MouseLeftDown != null)
{
mouseData.Button = MouseButton.Left;
this.MouseLeftDown(mouseData);
}
}

}
else
{
if (this.LastState.LeftButton == ButtonState.Pressed)
{
if (this.MouseLeftUp != null)
{
mouseData.Button = MouseButton.Left;
this.MouseLeftUp(mouseData);
}
}
}

#endregion

#region Check for Right button Mouse input

if (mState.RightButton == ButtonState.Pressed)
{
if (this.LastState.RightButton == ButtonState.Released)
{
if (this.MouseRightDown != null)
{
mouseData.Button = MouseButton.Right;
this.MouseRightDown(mouseData);
}
}

}
else
{
if (this.LastState.RightButton == ButtonState.Pressed)
{
if (this.MouseRightUp != null)
{
mouseData.Button = MouseButton.Right;
this.MouseRightUp(mouseData);
}
}
}

#endregion

this.LastState = mState;
}

#endregion
}
[/source]

and now for the MouseEventData

[source]


public struct MouseEventData
{
public MouseButton Button;

public int X;
public int Y;
}

[/source]

in your case just check for a mouse left up event and then see what button your in, since the mouse left up only fires after the left mouse has been pressed and release you will get much more accurate input.
hope this helps to at least show you how to poll xna input.

I want to jump in and comment based on my experience. The snippet of code regarding checking if the mouse is currently pressed and then processing the clicks will likely cause a problem (may not, I'm not sure if XNA is super magical, as I've never worked with it). The issue comes from the fact that the user may click (press and then release) the mouse entirely between times which this condition is checked, which could result in a click being completely ignored. The way I've solved this in the past is by having a 'mouse' class which responds to any sort of mouse event, and keeps track of buttons that are currently pressed, and buttons that have been pressed AT ANY POINT since the last time the class was instructed to reset itself, resulting in two separate 'checking' functions, "isPressed(int Button)" and "hasBeenPressed(int Button)". I'm not aware if xna deals with input in this event oriented method, but I don't see why it wouldn't. In the time since I worked out this solution, I've seen it in at least a couple of places, so I'm sure it's fairly standard.


I'm using the above code in my 2D game, and it works, without problems.



if (Mouse.GetState().LeftButton == ButtonState.Pressed)
This will check if the left mouse button is pressed. It doesn't check if the button has been clicked, it just checks if the button is pressed.



Point x = new Point(Mouse.GetState().X, Mouse.GetState().Y);
This saves the x and y location of the mouse. So everytime the gameloop loops through this part it will initialize the mouse point, x. It has to be outside the if-statement, as it requires to be updated always. This is most easy solved by creating a class for the mouse that will update it.



if (button_play.rectangle.Contains(x))
All rectangles contains a method called contains. This method checks if a point is inside the rectangle. So what we check here is if the current location of the mouse is inside the rectangle, in other words; we check if the mouse is on the button.


Lets say that both if statements was true, that means that the mouse button was pressed when the mouse was on a button, which will give us the result we want. This is a very simple and effective way check button clicks, and it's surly possible to check it in many more ways, but why make it more complicated than required? There's only two small "downsides" with this strategy, but it still works without any bugs or problems at all.

The downsides are:

1. It's possible to click the left mouse button, then move the mouse over the button, and it will still registrate it as I pressed the button. If you want to follow the default windows button system, then you can simple solve this matter with a bool.

2. It's not 100% correct to initilize the x point everytime the game loop loops throug your mouse code. What you should instead do, is to have your own mouse class, where you update (not initialize) the position. The class Mouse is already used by in the xna library, so I usually use Cursor as class name. Updating the mouse position, without initializing it everytime the game loop loops through your cursor class, is done like this:


position.x = Mouse.GetState().X;
position.y = Mouse.GetState().Y;
Sure it works under ideal circumstances, but if there is a bit of lag, and someone clicks even a little bit fast, it is not unreasonable to suggest that the user might click and have nothing happen. My suggestion makes that eventuality completely impossible. But I guess these days no one cares about proper coding, just get it working asap because F*** GOOD CODE.

Seriously though, I'm not saying the above code doesn't work, I'm saying it is not entirely robust to the level of certainty that you will probably want to guarantee in a game. If I click, I expect my gun to shoot, regardless of how quickly i released the mouse. If you only test for the current state of the mouse you might miss clicks that entirely occurred between the last game loop and the current.

This topic is closed to new replies.

Advertisement