How to slow down or stop key presses in XNA

后端 未结 12 2115
北恋
北恋 2021-02-01 05:38

I\'ve begun writing a game using XNA Framework and have hit some simple problem I do not know how to solve correctly.

I\'m displaying a menu using Texture2D and using th

相关标签:
12条回答
  • 2021-02-01 05:54

    I've built a (large) class that helps a lot with any and all XNA input related tasks, it makes what you're asking for easy.

    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Input;
    
    namespace YourNamespaceHere
    {
        /// <summary>
        /// an enum of all available mouse buttons.
        /// </summary>
        public enum MouseButtons
        {
            LeftButton,
            MiddleButton,
            RightButton,
            ExtraButton1,
            ExtraButton2
        }
    
        public class InputHelper
        {
            private GamePadState _lastGamepadState;
            private GamePadState _currentGamepadState;
    #if (!XBOX)
            private KeyboardState _lastKeyboardState;
            private KeyboardState _currentKeyboardState;
            private MouseState _lastMouseState;
            private MouseState _currentMouseState;
    #endif
            private PlayerIndex _index = PlayerIndex.One;
            private bool refreshData = false;
    
            /// <summary>
            /// Fetches the latest input states.
            /// </summary>
            public void Update()
            {
                if (!refreshData)
                    refreshData = true;
                if (_lastGamepadState == null && _currentGamepadState == null)
                {
                    _lastGamepadState = _currentGamepadState = GamePad.GetState(_index);
                }
                else
                {
                    _lastGamepadState = _currentGamepadState;
                    _currentGamepadState = GamePad.GetState(_index);
                }
    #if (!XBOX)
                if (_lastKeyboardState == null && _currentKeyboardState == null)
                {
                    _lastKeyboardState = _currentKeyboardState = Keyboard.GetState();
                }
                else
                {
                    _lastKeyboardState = _currentKeyboardState;
                    _currentKeyboardState = Keyboard.GetState();
                }
                if (_lastMouseState == null && _currentMouseState == null)
                {
                    _lastMouseState = _currentMouseState = Mouse.GetState();
                }
                else
                {
                    _lastMouseState = _currentMouseState;
                    _currentMouseState = Mouse.GetState();
                }
    #endif
            }
    
            /// <summary>
            /// The previous state of the gamepad. 
            /// Exposed only for convenience.
            /// </summary>
            public GamePadState LastGamepadState
            {
                get { return _lastGamepadState; }
            }
            /// <summary>
            /// the current state of the gamepad.
            /// Exposed only for convenience.
            /// </summary>
            public GamePadState CurrentGamepadState
            {
                get { return _currentGamepadState; }
            }
            /// <summary>
            /// the index that is used to poll the gamepad. 
            /// </summary>
            public PlayerIndex Index
            {
                get { return _index; }
                set { 
                    _index = value;
                    if (refreshData)
                    {
                        Update();
                        Update();
                    }
                }
            }
    #if (!XBOX)
            /// <summary>
            /// The previous keyboard state.
            /// Exposed only for convenience.
            /// </summary>
            public KeyboardState LastKeyboardState
            {
                get { return _lastKeyboardState; }
            }
            /// <summary>
            /// The current state of the keyboard.
            /// Exposed only for convenience.
            /// </summary>
            public KeyboardState CurrentKeyboardState
            {
                get { return _currentKeyboardState; }
            }
            /// <summary>
            /// The previous mouse state.
            /// Exposed only for convenience.
            /// </summary>
            public MouseState LastMouseState
            {
                get { return _lastMouseState; }
            }
            /// <summary>
            /// The current state of the mouse.
            /// Exposed only for convenience.
            /// </summary>
            public MouseState CurrentMouseState
            {
                get { return _currentMouseState; }
            }
    #endif
            /// <summary>
            /// The current position of the left stick. 
            /// Y is automatically reversed for you.
            /// </summary>
            public Vector2 LeftStickPosition
            {
                get 
                { 
                    return new Vector2(
                        _currentGamepadState.ThumbSticks.Left.X, 
                        -CurrentGamepadState.ThumbSticks.Left.Y); 
                }
            }
            /// <summary>
            /// The current position of the right stick.
            /// Y is automatically reversed for you.
            /// </summary>
            public Vector2 RightStickPosition
            {
                get 
                { 
                    return new Vector2(
                        _currentGamepadState.ThumbSticks.Right.X, 
                        -_currentGamepadState.ThumbSticks.Right.Y); 
                }
            }
            /// <summary>
            /// The current velocity of the left stick.
            /// Y is automatically reversed for you.
            /// expressed as: 
            /// current stick position - last stick position.
            /// </summary>
            public Vector2 LeftStickVelocity
            {
                get 
                {
                    Vector2 temp =
                        _currentGamepadState.ThumbSticks.Left - 
                        _lastGamepadState.ThumbSticks.Left;
                    return new Vector2(temp.X, -temp.Y); 
                }
            }
            /// <summary>
            /// The current velocity of the right stick.
            /// Y is automatically reversed for you.
            /// expressed as: 
            /// current stick position - last stick position.
            /// </summary>
            public Vector2 RightStickVelocity
            {
                get
                {
                    Vector2 temp =
                        _currentGamepadState.ThumbSticks.Right -
                        _lastGamepadState.ThumbSticks.Right;
                    return new Vector2(temp.X, -temp.Y);
                }
            }
            /// <summary>
            /// the current position of the left trigger.
            /// </summary>
            public float LeftTriggerPosition
            {
                get { return _currentGamepadState.Triggers.Left; }
            }
            /// <summary>
            /// the current position of the right trigger.
            /// </summary>
            public float RightTriggerPosition
            {
                get { return _currentGamepadState.Triggers.Right; }
            }
            /// <summary>
            /// the velocity of the left trigger.
            /// expressed as: 
            /// current trigger position - last trigger position.
            /// </summary>
            public float LeftTriggerVelocity
            {
                get 
                { 
                    return 
                        _currentGamepadState.Triggers.Left - 
                        _lastGamepadState.Triggers.Left; 
                }
            }
            /// <summary>
            /// the velocity of the right trigger.
            /// expressed as: 
            /// current trigger position - last trigger position.
            /// </summary>
            public float RightTriggerVelocity
            {
                get 
                { 
                    return _currentGamepadState.Triggers.Right - 
                        _lastGamepadState.Triggers.Right; 
                }
            }
    #if (!XBOX)
            /// <summary>
            /// the current mouse position.
            /// </summary>
            public Vector2 MousePosition
            {
                get { return new Vector2(_currentMouseState.X, _currentMouseState.Y); }
            }
            /// <summary>
            /// the current mouse velocity.
            /// Expressed as: 
            /// current mouse position - last mouse position.
            /// </summary>
            public Vector2 MouseVelocity
            {
                get
                {
                    return (
                        new Vector2(_currentMouseState.X, _currentMouseState.Y) - 
                        new Vector2(_lastMouseState.X, _lastMouseState.Y)
                        );
                }
            }
            /// <summary>
            /// the current mouse scroll wheel position.
            /// See the Mouse's ScrollWheel property for details.
            /// </summary>
            public float MouseScrollWheelPosition
            {
                get 
                {
                    return _currentMouseState.ScrollWheelValue;
                }
            }
            /// <summary>
            /// the mouse scroll wheel velocity.
            /// Expressed as:
            /// current scroll wheel position - 
            /// the last scroll wheel position.
            /// </summary>
            public float MouseScrollWheelVelocity
            {
                get 
                {
                    return (_currentMouseState.ScrollWheelValue - _lastMouseState.ScrollWheelValue);
                }
            }
    #endif
            /// <summary>
            /// Used for debug purposes.
            /// Indicates if the user wants to exit immediately.
            /// </summary>
            public bool ExitRequested
            {
    #if (!XBOX)
                get
                {
                    return (
                        (IsCurPress(Buttons.Start) && 
                        IsCurPress(Buttons.Back)) ||
                        IsCurPress(Keys.Escape));
                }
    #else
                get { return (IsCurPress(Buttons.Start) && IsCurPress(Buttons.Back)); }
    #endif
            }
            /// <summary>
            /// Checks if the requested button is a new press.
            /// </summary>
            /// <param name="button">
            /// The button to check.
            /// </param>
            /// <returns>
            /// a bool indicating whether the selected button is being 
            /// pressed in the current state but not the last state.
            /// </returns>
            public bool IsNewPress(Buttons button)
            {
                return (
                    _lastGamepadState.IsButtonUp(button) && 
                    _currentGamepadState.IsButtonDown(button));
            }
            /// <summary>
            /// Checks if the requested button is a current press.
            /// </summary>
            /// <param name="button">
            /// the button to check.
            /// </param>
            /// <returns>
            /// a bool indicating whether the selected button is being 
            /// pressed in the current state and in the last state.
            /// </returns>
            public bool IsCurPress(Buttons button)
            {
                return (
                    _lastGamepadState.IsButtonDown(button) && 
                    _currentGamepadState.IsButtonDown(button));
            }
            /// <summary>
            /// Checks if the requested button is an old press.
            /// </summary>
            /// <param name="button">
            /// the button to check.
            /// </param>
            /// <returns>
            /// a bool indicating whether the selected button is not being
            /// pressed in the current state and is being pressed in the last state.
            /// </returns>
            public bool IsOldPress(Buttons button)
            {
                return (
                    _lastGamepadState.IsButtonDown(button) && 
                    _currentGamepadState.IsButtonUp(button));
            }
    #if (!XBOX)
            /// <summary>
            /// Checks if the requested key is a new press.
            /// </summary>
            /// <param name="key">
            /// the key to check.
            /// </param>
            /// <returns>
            /// a bool that indicates whether the selected key is being 
            /// pressed in the current state and not in the last state.
            /// </returns>
            public bool IsNewPress(Keys key)
            {
                return (
                    _lastKeyboardState.IsKeyUp(key) && 
                    _currentKeyboardState.IsKeyDown(key));
            }
            /// <summary>
            /// Checks if the requested key is a current press.
            /// </summary>
            /// <param name="key">
            /// the key to check.
            /// </param>
            /// <returns>
            /// a bool that indicates whether the selected key is being 
            /// pressed in the current state and in the last state.
            /// </returns>
            public bool IsCurPress(Keys key)
            {
                return (
                    _lastKeyboardState.IsKeyDown(key) &&
                    _currentKeyboardState.IsKeyDown(key));
            }
            /// <summary>
            /// Checks if the requested button is an old press.
            /// </summary>
            /// <param name="key">
            /// the key to check.
            /// </param>
            /// <returns>
            /// a bool indicating whether the selectde button is not being
            /// pressed in the current state and being pressed in the last state.
            /// </returns>
            public bool IsOldPress(Keys key)
            {
                return (
                    _lastKeyboardState.IsKeyDown(key) && 
                    _currentKeyboardState.IsKeyUp(key));
            }
            /// <summary>
            /// Checks if the requested mosue button is a new press.
            /// </summary>
            /// <param name="button">
            /// teh mouse button to check.
            /// </param>
            /// <returns>
            /// a bool indicating whether the selected mouse button is being
            /// pressed in the current state but not in the last state.
            /// </returns>
            public bool IsNewPress(MouseButtons button)
            {
                switch (button)
                {
                    case MouseButtons.LeftButton:
                        return (
                            _lastMouseState.LeftButton == ButtonState.Released &&
                            _currentMouseState.LeftButton == ButtonState.Pressed);
                    case MouseButtons.MiddleButton:
                        return (
                            _lastMouseState.MiddleButton == ButtonState.Released &&
                            _currentMouseState.MiddleButton == ButtonState.Pressed);
                    case MouseButtons.RightButton:
                        return (
                            _lastMouseState.RightButton == ButtonState.Released &&
                            _currentMouseState.RightButton == ButtonState.Pressed);
                    case MouseButtons.ExtraButton1:
                        return (
                            _lastMouseState.XButton1 == ButtonState.Released &&
                            _currentMouseState.XButton1 == ButtonState.Pressed);
                    case MouseButtons.ExtraButton2:
                        return (
                            _lastMouseState.XButton2 == ButtonState.Released &&
                            _currentMouseState.XButton2 == ButtonState.Pressed);
                    default:
                        return false;
                }
            }
            /// <summary>
            /// Checks if the requested mosue button is a current press.
            /// </summary>
            /// <param name="button">
            /// the mouse button to be checked.
            /// </param>
            /// <returns>
            /// a bool indicating whether the selected mouse button is being 
            /// pressed in the current state and in the last state.
            /// </returns>
            public bool IsCurPress(MouseButtons button)
            {
                switch (button)
                {
                    case MouseButtons.LeftButton:
                        return (
                            _lastMouseState.LeftButton == ButtonState.Pressed &&
                            _currentMouseState.LeftButton == ButtonState.Pressed);
                    case MouseButtons.MiddleButton:
                        return (
                            _lastMouseState.MiddleButton == ButtonState.Pressed &&
                            _currentMouseState.MiddleButton == ButtonState.Pressed);
                    case MouseButtons.RightButton:
                        return (
                            _lastMouseState.RightButton == ButtonState.Pressed &&
                            _currentMouseState.RightButton == ButtonState.Pressed);
                    case MouseButtons.ExtraButton1:
                        return (
                            _lastMouseState.XButton1 == ButtonState.Pressed &&
                            _currentMouseState.XButton1 == ButtonState.Pressed);
                    case MouseButtons.ExtraButton2:
                        return (
                            _lastMouseState.XButton2 == ButtonState.Pressed &&
                            _currentMouseState.XButton2 == ButtonState.Pressed);
                    default:
                        return false;
                }
            }
            /// <summary>
            /// Checks if the requested mosue button is an old press.
            /// </summary>
            /// <param name="button">
            /// the mouse button to check.
            /// </param>
            /// <returns>
            /// a bool indicating whether the selected mouse button is not being 
            /// pressed in the current state and is being pressed in the old state.
            /// </returns>
            public bool IsOldPress(MouseButtons button)
            {
                switch (button)
                {
                    case MouseButtons.LeftButton:
                        return (
                            _lastMouseState.LeftButton == ButtonState.Pressed &&
                            _currentMouseState.LeftButton == ButtonState.Released);
                    case MouseButtons.MiddleButton:
                        return (
                            _lastMouseState.MiddleButton == ButtonState.Pressed &&
                            _currentMouseState.MiddleButton == ButtonState.Released);
                    case MouseButtons.RightButton:
                        return (
                            _lastMouseState.RightButton == ButtonState.Pressed &&
                            _currentMouseState.RightButton == ButtonState.Released);
                    case MouseButtons.ExtraButton1:
                        return (
                            _lastMouseState.XButton1 == ButtonState.Pressed &&
                            _currentMouseState.XButton1 == ButtonState.Released);
                    case MouseButtons.ExtraButton2:
                        return (
                            _lastMouseState.XButton2 == ButtonState.Pressed &&
                            _currentMouseState.XButton2 == ButtonState.Released);
                    default:
                        return false;
                }
            }
    #endif
        }
    }
    

    Just copy it into a separate class fie and move it to your namespace, then declare one (inputHelper variable), initialize it in the initialiaze portion, and call inputHelper.Update() in your update loop before the update logic. Then whenever you need something related to input, just use the InputHelper! for instance, in your situation, you would use InputHelper.IsNewPress([type of input button/key here]) to check if you want to move the menu item down or up. For this example: inputHelper.IsNewPress(Keys.Down)

    0 讨论(0)
  • 2021-02-01 05:56

    I know this is old, but how about: Add a threadsafe dictionary:

    private ConcurrentDictionary<Keys, DateTime> _keyBounceDict = new ConcurrentDictionary<Keys, DateTime>();
    

    Then use this method to track the keys pressed and determine if there is a key bounce:

            ///////////////////////////////////////////////////////////////////////////////////////////
        /// IsNotKeyBounce - determines if a key is bouncing and therefore not valid within
        ///    a certain "delay" period
        ///////////////////////////////////////////////////////////////////////////////////////////
        private bool IsNotKeyBounce(Keys thekey, double delay)
        {
            bool OKtoPress = true;
            if (_keyBounceDict.ContainsKey(thekey))
            {
                TimeSpan ts = DateTime.Now - _keyBounceDict[thekey];
                if (ts.TotalMilliseconds < _tsKeyBounceTiming)
                {
                    OKtoPress = false;
                }
                else
                {
                    DateTime dummy;
                    _keyBounceDict.TryRemove(thekey, out dummy);
                }
            }
            else
            {
                _keyBounceDict.AddOrUpdate(thekey, DateTime.Now, (key, oldValue) => oldValue);
            }
            return OKtoPress;
        }
    

    Here is what I put in my Update method:

                if (Keyboard.GetState().IsKeyDown(Keys.W))
            {
                if (IsNotKeyBounce(Keys.W, 50.0)) _targetNew.Distance *= 1.1f;
            }
    

    I use 50 ms, but you could use whatever makes sense for your app or tie it to GameTime or whatever...

    0 讨论(0)
  • 2021-02-01 05:59

    You could store in integer value time from last key pressed (left,right...) and if this time is bigger than some limit you could poll for new key pressed. However this could be done only for menu, because in-game you would need that information immediately.

    0 讨论(0)
  • 2021-02-01 05:59

    Ranieri, what does that look like? I am having a hard time juggling these update cycles...

    Hrmmm...

    public static bool CheckKeyPress(Keys key)
    {
        return keyboardState.IsKeyUp(key) && lastKeyboardState.IsKeyDown(key);
    }
    

    SetStates() is private and it is called in the Update()

    private static void SetStates()
    {
        lastKeyboardState = keyboardState;
    
        keyboardState = Keyboard.GetState();
    }
    

    Here is the update...

    public sealed override void Update(GameTime gameTime)
    {
        // Called to set the states of the input devices
        SetStates();
        base.Update(gameTime);
    }
    

    I've tried adding extra checks..

    if (Xin.CheckKeyPress(Keys.Enter) ||
        Xin.CheckButtonPress(Buttons.A))
    {
        if (Xin.LastKeyboardState != Xin.KeyboardState ||
            Xin.LastGamePadState(PlayerIndex.One) != Xin.GamePadState(PlayerIndex.One))
        {
    

    doesn't seem to have any noticeable effects - I can't seem to slow down the menu confirmations,

    0 讨论(0)
  • 2021-02-01 06:04

    A nice way of dealing with this kind of thing is to store a counter for each key you're interested in, which you increment every frame if the key is down, and reset to 0 if it's up.

    The advantage of this is that you can then test for both the absolute state of the key (if the counter is non-zero the key is down) and also easily check if it's just been pressed this frame for menus and the like (counter is 1). Plus key repeat becomes easy (counter % repeat delay is zero).

    0 讨论(0)
  • 2021-02-01 06:04

    What you can also do is make yourself a functions combining KyeUp and KeyDown that tells you when the key has been pressed once, only in 1 loop of the update, so that it only works everytime you press the key again.

    0 讨论(0)
提交回复
热议问题