Sign in to follow this  
Manhattanisgr8

Help with menu selection in XNA

Recommended Posts

I am making a main menu game state and have come across a problem. I have two textures for each button in order to indicate which button is currently selected. The problem I have is when the player presses the down key from the first button, it doesn't stop at the middle button, but goes all the way down to the third button. How can I have it pause at the middle button, before going down to the bottom button?

 

        //Menu selections
        private void MainMenuSelection()
        {
            // If player presses down arrow, highlight credits
            if (Keyboard.GetState(p1.pNumber).IsKeyDown(Keys.Down))
            {
                playButton.active = false;
                creditsButton.active = true;
            }
            // If player presses down again, highlight credits
            if (Keyboard.GetState(p1.pNumber).IsKeyDown(Keys.Down))
            {
                creditsButton.active = false;
                exitButton.active = true;
            }

 

Share this post


Link to post
Share on other sites

The problem is that that code executes 60 times a second, so there is a very good chance that it will execute multiple times before the user lets go of a key. You need to track the input state from both the current frame and the previous frame. That way you can detect and act on a key press the first frame in which it is pressed and ignore it until its state changes again.

 

Have a look at the Game State Management sample in the XNA Education Catalog. There is an InputState class that handles that aspect for you.

Share this post


Link to post
Share on other sites

edited the code to have a previous and current keyboard state, still haveing the same problems

 

        //Menu selections
        private void MainMenuSelection()
        {

            KeyboardState currentKeyboardState;
            currentKeyboardState = Keyboard.GetState();

            // If player presses down arrow, select credits
            if (currentKeyboardState.IsKeyDown(Keys.Down) && !previousKeyboardState.IsKeyDown(Keys.Down))
            {
                playButton.active = false;
                creditsButton.active = true;
            }

            // If player presses down again, highlight exit
            if (currentKeyboardState.IsKeyDown(Keys.Down) && ! previousKeyboardState.IsKeyDown(Keys.Down))
            {
                creditsButton.active = false;
                exitButton.active = true;
            }

            previousKeyboardState = currentKeyboardState;
        }

Share this post


Link to post
Share on other sites

So whats going on here is you're saying if the current keyboard down key is pressed and the previous keyboard down key is not pressed. Well at the moment, your second statement will always return true until the key is initially pressed, I believe that what you want to do is use the "IsKeyUp" method on the currentKeyboardState. 

 

Like So: 

 

 

 

if (currentKeyboardState.IsKeyUp(Keys.Down) && previousKeyboardState.IsKeyDown(Keys.Down)) 
{
//...
}
 

Share this post


Link to post
Share on other sites

Do you mind sharing the updated code? I don't know why this solution wouldn't work off the top of my head.

 

EDIT: 

 

Actually now that i take a step away from the PC, i realized what the problem is. You're performing both conditions at the same time. So your second condition would be something along these lines: 

 

 

 

if (currentKeyboardState.IsKeyUp(Keys.Down) && previousKeyboardState.IsKeyDown(Keys.Down) && creditsButton.active = true)
 

 

 

since you don't want the exit button to be the "next in line" to be highlighted until the button above that is already selected. 

 

Hope that works!

Edited by ch1mera

Share this post


Link to post
Share on other sites

Do you mind sharing the updated code? I don't know why this solution wouldn't work off the top of my head.

        //Menu selections
        private void MainMenuSelection()
        {

            KeyboardState currentKeyboardState;
            currentKeyboardState = Keyboard.GetState();

            // If player presses down arrow, select credits
            if (currentKeyboardState.IsKeyUp(Keys.Down) && previousKeyboardState.IsKeyDown(Keys.Down))
            {
                playButton.active = false;
                creditsButton.active = true;
            }

            // If player presses down again, highlight exit
            if (currentKeyboardState.IsKeyUp(Keys.Down) && previousKeyboardState.IsKeyDown(Keys.Down))
            {
                creditsButton.active = false;
                exitButton.active = true;
            }

            previousKeyboardState = currentKeyboardState;

I am putting this method at the bottom of Game1 and calling it in the Update() of Game1.

Share this post


Link to post
Share on other sites

Do you mind sharing the updated code? I don't know why this solution wouldn't work off the top of my head.

        //Menu selections
        private void MainMenuSelection()
        {

            KeyboardState currentKeyboardState;
            currentKeyboardState = Keyboard.GetState();

            // If player presses down arrow, select credits
            if (currentKeyboardState.IsKeyUp(Keys.Down) && previousKeyboardState.IsKeyDown(Keys.Down))
            {
                playButton.active = false;
                creditsButton.active = true;
            }

            // If player presses down again, highlight exit
            if (currentKeyboardState.IsKeyUp(Keys.Down) && previousKeyboardState.IsKeyDown(Keys.Down))
            {
                creditsButton.active = false;
                exitButton.active = true;
            }

            previousKeyboardState = currentKeyboardState;

I am putting this method at the bottom of Game1 and calling it in the Update() of Game1.

 

I believe the edit to my previous post should solve the problem.

Share this post


Link to post
Share on other sites

I believe the edit to my previous post should solve the problem.

 

Changed the code to what you suggested with no luck. Now it doesn't highlight anything but the play button which is set to active by default.

 

        //Menu selections
        private void MainMenuSelection()
        {

            KeyboardState currentKeyboardState;
            currentKeyboardState = Keyboard.GetState();

            // If player presses down arrow, select credits
            if (currentKeyboardState.IsKeyUp(Keys.Down) && previousKeyboardState.IsKeyDown(Keys.Down) && creditsButton.active == true)
            {
                playButton.active = false;
                creditsButton.active = true;
            }

            // If player presses down again, highlight exit
            if (currentKeyboardState.IsKeyUp(Keys.Down) && previousKeyboardState.IsKeyDown(Keys.Down) && exitButton.active == true)
            {
                creditsButton.active = false;
                exitButton.active = true;
            }

            previousKeyboardState = currentKeyboardState;

Would it be easier for you if I PMed you the entire Game1.cs code?

Share this post


Link to post
Share on other sites

I believe the edit to my previous post should solve the problem.

 

Changed the code to what you suggested with no luck. Now it doesn't highlight anything but the play button which is set to active by default.

 

        //Menu selections
        private void MainMenuSelection()
        {

            KeyboardState currentKeyboardState;
            currentKeyboardState = Keyboard.GetState();

            // If player presses down arrow, select credits
            if (currentKeyboardState.IsKeyUp(Keys.Down) && previousKeyboardState.IsKeyDown(Keys.Down) && creditsButton.active == true)
            {
                playButton.active = false;
                creditsButton.active = true;
            }

            // If player presses down again, highlight exit
            if (currentKeyboardState.IsKeyUp(Keys.Down) && previousKeyboardState.IsKeyDown(Keys.Down) && exitButton.active == true)
            {
                creditsButton.active = false;
                exitButton.active = true;
            }

            previousKeyboardState = currentKeyboardState;

Would it be easier for you if I PMed you the entire Game1.cs code?

 

We can PM if you like. 

 

I think this solution should work, the problem is that its done in the wrong order, if that makes sense. In the first condition you're stating that it will only run if creditsButton.active == true, but the value of creditsButton.active isn't set to true until you're inside the statement. What you want the first condition to have is playButton.active == true instead, as it seems that this value is default set to true just as the play button (as you said) is default set to to active. 

 

and likewise in the second condition, instead of exitButton.active == true, you want creditsButton.active == true. 

Share this post


Link to post
Share on other sites

We can PM if you like.

 

I sent you a PM. I changed the code to this:

        //Menu selections
        private void MainMenuSelection()
        {

            KeyboardState currentKeyboardState;
            currentKeyboardState = Keyboard.GetState();

            // If player presses down arrow, select credits
            if (currentKeyboardState.IsKeyUp(Keys.Down) && previousKeyboardState.IsKeyDown(Keys.Down) && playButton.active == true)
            {
                playButton.active = false;
                creditsButton.active = true;
            }

            // If player presses down again, highlight exit
            if (currentKeyboardState.IsKeyUp(Keys.Down) && previousKeyboardState.IsKeyDown(Keys.Down) && creditsButton.active == true)
            {
                creditsButton.active = false;
                exitButton.active = true;
            }

            previousKeyboardState = currentKeyboardState;

 

It still scrolls through the credits right down to the exit. I am pretty sure it is how and where I am calling the current and previous keyboard states

Share this post


Link to post
Share on other sites

you are asking if the down key is down both times back to back, before assigning currentKeyboardState to previousKeyboardState.  so yes it will jump all the way down to the exit button because you are asking about the same keyboardstate both times.  so both will be activated during the same Update.  you should set up the menu items in an array or list have an indexer that moves up or down one with each press.  also move your keyboardstate declerations out of the method.   like this.

int menuIndex = 0;  // place this in your menu fields
menuItem[] menuItems; //place this in your menu fields
KeyboardState currentKeyboardState; //place this in your menu fields
KeybardState previousKeyboardState; //place this in your menu fields

private void MainMenuSelection()
        {            
            currentKeyboardState = Keyboard.GetState();
            
            menuItems[index].IsActive = true;

            // If player presses down arrow go down in menu
            if (currentKeyboardState.IsKeyDown(Keys.Down) && previousKeyboardState.IsKeyUp(Keys.Down))
            {
                   //deactivate current menuItem
                   menuItems[menuIndex].IsActive = false;
 
                   //go down in the menu
                   menuIndex++;
                   
                   // keep index within the your menu items
                   if(menuIndex <= menuItems.Count)
                        index = 0;

                   //activate new menuItem
                   menuItems[index].IsActive = true;

            }

            // If player presses Up Go Up in menu
            if (currentKeyboardState.IsKeyDown(Keys.Up) && previousKeyboardState.IsKeyUp(Keys.Up))
            {
               //deactivate current menuItem
               menuItems[menuIndex].IsActive = false;

              //go up in the menu
              menuIndex--;

              // goes to last menuItem if already at top of menu
              if(menuIndex > 0)
                 index = menuItems.Count -1;

              //activate new menuItem
              menuItems[index].IsActive = true;
            }

            previousKeyboardState = currentKeyboardState;
Edited by moneal2001

Share this post


Link to post
Share on other sites

you should set up the menu items in an array

 

Would this work even though I have the two different textures for each button in a List?

 

My Button Class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace TronPongClone
{
    class Buttons
    {
        // Button texture at Idle
        public List<Texture2D> texture;

        // Button height
        public int height;

        // Button width
        public int width;

        // Button position
        public Vector2 poition;

        // Button state
        public bool active;

        public Buttons()
        {
            texture = new List<Texture2D>();
            height = 100;
            width = 300;
            poition = Vector2.Zero;
            this.active = true;
        }

        public void Update(SpriteBatch spriteBatch)
        {
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            if (active == true)
            {
                spriteBatch.Draw(texture.ElementAt(1), poition, Color.White);
            }
            if (active == false)
            {
                spriteBatch.Draw(texture.ElementAt(0), poition, Color.White);
            }
        }
    }
}

Share this post


Link to post
Share on other sites

Yea that should work.  i would create a list since you can add and remove from lists at will(adding or removing any number of buttons you need as you go).  and put something together kinda like my example and it should work just fine.  the button class you have looks set up pretty well.  

 

there are some great examples of how to do a menu system out there for xna.  a good one is at xnagpa, in his rpg tutorial(the one i think i modeled the example after if i remember right).  he also has a lot of menu control items.  and as someone mentioned earlier in the thread at the app hub resources the Game State Management Tutorial has a good menu and input handling system in it.

Edited by moneal2001

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