4

I am a noob at programming but before we start please answer me why does update execute more than once an explain it like i am a dummy.

Anyways so i am trying to make this code run only once because as of now it executes it more than once.

 protected override void Update(GameTime gameTime)
    {
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();

        // TODO: Add your update logic here

         button = Mouse.GetState();




         if (button.X < buttonPosition.X || button.Y < buttonPosition.Y || button.X > buttonPosition.X + font1.MeasureString(buttonText).X ||
             button.Y > buttonPosition.Y + font1.MeasureString(buttonText).Y)
             buttonColour = new Color(0, 0, 0);//if the mouse if not hovering over the font it stays that color
         else
             buttonColour = new Color(0, 255, 255);//changes to this color if it is hovering over text

        if(button.LeftButton==ButtonState.Pressed)
         display = (display == false) ? true : false;  //if display = true it will set it to false
        //if false then it will set it to false



 }

This is the Draw method if you need it.

 protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);
        spriteBatch.Begin();
        spriteBatch.DrawString(font1, buttonText, buttonPosition, buttonColour);   //this is the button leftbutton has to click to trigger the below if statement.
        if (display)
            spriteBatch.DrawString(font1, text, position, Color.White);
        spriteBatch.End();  //it will draw this when leftbutton  clicks the above button

        // TODO: Add your drawing code here

        base.Draw(gameTime);
    }
Wasiim Ouro-sama
  • 131
  • 3
  • 16

2 Answers2

6

You are getting this behavior because the Update method is getting called automatically multiple times per second by XNA, probably somewhere around 60 times per seconds. It's the same thing with Draw, which will probably render around 60 FPS.

Because of this, if you're pressing a button for one second and the method gets called 60 times, ButtonState.Pressed will evaluate to true for those 60 times.

To fix this, you need to keep an history of your buttons. This can be achieve by storing the state on each update:

//Define this at class level
private MouseState lastMouseState = new MouseState();

protected override void Update(GameTime gameTime)
{
    // your other stuff

    MouseState currentState = Mouse.GetState(); //Get the state
    if (currentState.LeftButton == ButtonState.Pressed &&
        lastMouseState.LeftButton == ButtonState.Released) //Will be true only if the user is currently clicking, but wasn't on the previous call.
    {
        display = !display; //Toggle the state between true and false.
    }

    lastMouseState = currentState;
}

So now the click will be registered only once (Because the mouse needs to be currently clicking, but have to be in the released state previously). You will need to keep an history for the keyboard too, if you include it someday.

I also changed your logic for the display toggling, much cleaner that way. You also had an error in your comment (should be //if false then it will set it to true). It's normal, comments often lie; always try to comment as less as you can, only the code holds the truth.


If that's any help to you, here's the helper class I was using before:

public class InputState : GameComponent
{
    private KeyboardState currentKeyboardState;
    private KeyboardState lastKeyboardState;
    private MouseState lastMouseState;
    private MouseState currentMouseState;

    public InputState(Game game) : base(game)
    {
        game.Components.Add(this);

        currentKeyboardState = new KeyboardState();
        lastKeyboardState = new KeyboardState();
        currentMouseState = new MouseState();
        lastMouseState = new MouseState();
    }

    public override void Update(GameTime gameTime)
    {
        lastKeyboardState = currentKeyboardState;
        currentKeyboardState = Keyboard.GetState();
        lastMouseState = currentMouseState;
        currentMouseState = Mouse.GetState();

        base.Update(gameTime);
    }

    public bool IsNewLeftClick()
    {
        return currentMouseState.LeftButton == ButtonState.Pressed &&
            lastMouseState.LeftButton == ButtonState.Released;
    }

    public bool IsNewRightClick()
    {
        return currentMouseState.RightButton == ButtonState.Pressed &&
            lastMouseState.RightButton == ButtonState.Released;
    }

    public Point GetMousePosition()
    {
        return new Point(currentMouseState.X, currentMouseState.Y);    
    }

    public bool IsNewKeyPress(params Keys[] keys)
    {
        return keys.Any(k => (currentKeyboardState.IsKeyDown(k) &&
                    lastKeyboardState.IsKeyUp(k)));
    }

    public bool IsCurrentlyPressed(params Keys[] keys)
    {
        return keys.Any(k => currentKeyboardState.IsKeyDown(k));
    }
}

It will register itself as a game component, no need to add it. The state will be updated by itself, so just call the helper methods.

Your last if would become:

if (inputState.IsNewLeftClick())
    display = !display;

It's a little cleaner that way, and it offers a centralized way to handle mouse/keyboard (yay for SRP).

Pierre-Luc Pineault
  • 8,993
  • 6
  • 40
  • 55
  • This is so confusing i dont get the explanation behind it but the code works thanks – Wasiim Ouro-sama Feb 16 '15 at 02:58
  • Which part are you having trouble with? XNA can be pretty confusing at first. Also, there's a damn good tutorial over at MSDN [here](http://msdn.microsoft.com/en-us/library/dd254918%28v=xnagamestudio.31%29.aspx), the source is available and there's a bunch of pretty useful stuff in there. – Pierre-Luc Pineault Feb 16 '15 at 02:59
  • Not to sound blunt, but I'm afraid that if you don't understand the posted answer, you might want to spend some more time learning about the C# structure, and generally about Object oriented programming. – Falgantil Feb 16 '15 at 13:50
0
private KeyboardState currentKeyboardState;
private KeyboardState lastKeyboardState;

lastKeyboardState = currentKeyboardState;
currentKeyboardState = Keyboard.GetState();

public bool IsNewKeyPress(params Keys[] keys)
    {
        return keys.Any(k => (currentstate.IsKeyDown(k) &&
                    laststate.IsKeyUp(k)));
    }

if (IsNewKeyPress(Keys.Space))
        { //Do something }

For any Key on Keyboard this one worked! Thanks bro Pierre

Playonce
  • 3
  • 4