XNA - 鼠标左键被执行多次

4

我是编程新手,在开始之前请回答我,为什么更新会执行多次,并像对待傻瓜一样解释它。

无论如何,我现在正在尝试使此代码仅运行一次,因为目前它会执行多次。

 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



 }

这是绘图方法,如果需要的话。
 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);
    }
2个回答

6
您之所以出现这种行为,是因为XNA每秒自动多次调用“Update”方法,大约在每秒60次左右。同样的,对于“Draw”也是如此,它可能会渲染大约60帧每秒。
因此,如果您按下一个按钮一秒钟,该方法将被调用60次,ButtonState.Pressed将在那60次中评估为true。
要解决这个问题,您需要保留按钮的历史记录。这可以通过在每次更新时存储状态来实现:
//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;
}

现在点击事件只会被注册一次(因为鼠标需要当前处于点击状态,但先前必须处于释放状态)。如果你将来要添加键盘的话,也需要对其进行历史记录。

我还改变了你的显示切换逻辑,这样更加清晰简洁。你的注释中也有错误(应该是 //if false then it will set it to true)。这很正常,注释经常会误导人;尽量少写注释,只有代码才是真理。


如果需要帮助的话,以下是我之前使用的辅助类:

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));
    }
}

它会自动注册为游戏组件,无需添加。状态将被自动更新,只需调用辅助方法即可。
你的最后一个 `if` 将变成:
if (inputState.IsNewLeftClick())
    display = !display;

这样做会更加清晰,并且提供了一种集中处理鼠标/键盘的方式(SRP太棒了)。


这太令人困惑了,我不理解背后的解释,但代码有效,谢谢。 - Wasiim Ouro-sama
你在哪部分遇到了困难?XNA一开始可能会很令人困惑。此外,在MSDN 此处上有一个非常好的教程,源代码可用,并且其中有很多非常有用的信息。 - Pierre-Luc Pineault
不想听起来直白,但我担心如果您不理解发布的答案,您可能需要花更多时间学习C#结构,以及面向对象编程的一般知识。 - Falgantil

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 }

对于键盘上的任何按键,这个都有效!谢谢兄弟Pierre。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接