11
\$\begingroup\$

I'm trying to allow the player to press any button to continue from the main page. I was able to do this by making a List of Buttons and looping through these and checking for one of them being down; however, I feel like this code is kind of ugly and wonder if there's a simpler way to do it that I'm just not thinking of?

Here's my what my code looks like now:

            if (GamePad.GetState(PlayerIndex.One).IsConnected)
            {
                var buttonList = new List<Buttons>()
                {
                    {Buttons.A},
                    {Buttons.B},
                    {Buttons.Y},
                    {Buttons.X},
                    {Buttons.Start},
                    {Buttons.Back},
                    {Buttons.RightShoulder},
                    {Buttons.LeftShoulder},
                    {Buttons.RightTrigger},
                    {Buttons.LeftTrigger}
                };

                foreach (var button in buttonList)
                {
                    if (GamePad.GetState(PlayerIndex.One).IsButtonDown(button))
                        ExitMainMenu= true;
                }
            }
\$\endgroup\$
3
  • \$\begingroup\$ I'd personally just do a big IF loop, as opposed to creating an array and looping. \$\endgroup\$
    – jgallant
    Commented Aug 5, 2013 at 3:03
  • \$\begingroup\$ @Jon What is a big IF loop and why would it be better? \$\endgroup\$ Commented Aug 5, 2013 at 5:16
  • \$\begingroup\$ I love all the response this question is getting. I think @Katu got the "correct" answer though. \$\endgroup\$ Commented Aug 5, 2013 at 5:48

5 Answers 5

11
\$\begingroup\$

This should do the job. In the end of every update loop, save state of previousGamePadState. Then you can compare em. This is fast way to detect changes. No need to loop.

GamePadState.PacketNumber:

You can use PacketNumber to determine whether input state has changed. If the value of PacketNumber remains the same between two sequential calls to GetState, then there has been no change in input.

public bool HasInputChanged(GamePadState previousGamePadState, bool ignoreThumbsticks)
{ 
    GamePadState currentState = GamePad.GetState( PlayerIndex.One );
    if ((currentState.IsConnected) && (currentState.PacketNumber != previousGamePadState.PacketNumber))
    {
        //ignore thumbstick movement
        if ((ignoreThumbsticks == true) && ((currentState.ThumbSticks.Left.Length() != previousGamePadState.ThumbSticks.Left.Length() )&&(currentState.ThumbSticks.Right.Length() != previousGamePadState.ThumbSticks.Right.Length()) ))
            return false;
        return true
    }
    return false;
}

EDIT: Changed to method. It's not guaranteed to work right as is, but should work. Also, because this really detects changes in input, so if user releases button, it is seen with this also. I also added if to detect thumbstick movement, so you can ignore those at least.

Hope this helps you. Let me know, if it does not suit your needs, I'm sure we can work this out.

How to: Detect Whether a Controller Button Has Been Pressed This Frame GamePadState.PacketNumber Property

\$\endgroup\$
9
  • \$\begingroup\$ There's an analogous way to write this for GamePadState and enum Buttons, which is closer to the context the OP seems to be using. \$\endgroup\$ Commented Aug 5, 2013 at 5:13
  • 1
    \$\begingroup\$ Should not answer anything before morning coffee :) \$\endgroup\$
    – Katu
    Commented Aug 5, 2013 at 5:20
  • 1
    \$\begingroup\$ Now it does the job and it can't get any faster than this. \$\endgroup\$
    – Katu
    Commented Aug 5, 2013 at 5:27
  • \$\begingroup\$ Whoa, totally different method, and I think you're right about it being the fastest. Nice. \$\endgroup\$ Commented Aug 5, 2013 at 5:29
  • \$\begingroup\$ Does that detect only button presses, or does it also detect button releases? \$\endgroup\$ Commented Aug 5, 2013 at 6:44
2
\$\begingroup\$

You could manually construct an empty GamePadState, and then check it for (in)equality with the current real one, which you fetch by calling GamePad.GetState.

playerInput = GamePad.GetState(PlayerIndex.One);  
emptyInput = new GamePadState(Vector2.Zero, Vector2.Zero, 0, 0);
if (playerInput != emptyInput){

    // yay!!!!, a button push!
    // 
    // P.S., remember to allow any PlayerIndex to take control of the the game 
    // from the main menu.  It sucks when you pick up controller2 and it doesn't work.

}
\$\endgroup\$
5
  • \$\begingroup\$ I have no idea if this works; I have never tried to do it. Let me know if it works out for you. \$\endgroup\$ Commented Aug 5, 2013 at 4:32
  • \$\begingroup\$ Clever idea, although it will only work if GamePadState overrides Equals which is unlikely. Most likely, it will use reference equality and therefore the above if statement will never evaluate to true. \$\endgroup\$ Commented Aug 5, 2013 at 5:13
  • \$\begingroup\$ @craftworkgames Equals is different; it compares two references for being the same instance. But GamePadState does overload the == operator to compare their values, which I linked to in my answer (op_Equality). \$\endgroup\$ Commented Aug 5, 2013 at 5:15
  • \$\begingroup\$ Actually I didn't realize GamePadState was a struct it probably would work. Technically though, the behavior of Equals and == is often the same, of course, it depends on the implementation but the guidelines recommend it this way. If you truely want reference equality you there's also object.ReferenceEquals msdn.microsoft.com/en-us/library/bsc2ak47.aspx \$\endgroup\$ Commented Aug 5, 2013 at 5:40
  • \$\begingroup\$ Ah you're right, GamePadState is a value-type, so it's not relevant. Regardless, == is overloaded, might as well use it IMO. \$\endgroup\$ Commented Aug 5, 2013 at 5:45
1
\$\begingroup\$

If you don't mind the use of Reflection, you can use something sort of like this (possibly even this exactly):

        var properties = typeof(GamePadButtons).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        foreach (var property in properties)
        {
            var value = property.GetValue(GamePad.GetState(PlayerIndex.One).Buttons);
            if (value is ButtonState && (ButtonState)value == ButtonState.Pressed)
                ExitMainMenu = true;
        }
\$\endgroup\$
1
\$\begingroup\$

Since Buttons is an enumaration you can use the Enum.GetValues method like this:

var buttonList = (Buttons[])Enum.GetValues(typeof(Buttons));

foreach (var button in buttonList)
{
    if (GamePad.GetState(PlayerIndex.One).IsButtonDown(button))
        ExitMainMenu= true;
}
\$\endgroup\$
0
\$\begingroup\$

Riffing off @Katu's original answer, this seems fastest/cleanest. Just check for GamePad input. Done.

    bool GamePadInputChanged(GamePadState previousGamePadState)
    {
        var currentState = GamePad.GetState(PlayerIndex.One);
        return currentState.IsConnected && currentState.PacketNumber != previousGamePadState.PacketNumber;
    }
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .