Wykrywanie „dowolnego naciśnięcia przycisku”

10

Próbuję pozwolić graczowi nacisnąć dowolny przycisk, aby przejść ze strony głównej. Udało mi się to zrobić, tworząc listę przycisków, przeglądając je i sprawdzając, czy jeden z nich nie działa; jednak wydaje mi się, że ten kod jest trochę brzydki i zastanawiam się, czy istnieje prostszy sposób na zrobienie tego, o czym po prostu nie myślę?

Oto mój wygląd teraz mojego kodu:

            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;
                }
            }
Logika
źródło
Osobiście wykonałbym dużą pętlę IF, zamiast tworzyć tablicę i zapętlać.
jgallant
@Jon Co to jest duża pętla IF i dlaczego miałaby być lepsza?
craftworkgames,
Uwielbiam wszystkie odpowiedzi na to pytanie. Myślę jednak, że @Katu ma „poprawną” odpowiedź.
Seth Battin

Odpowiedzi:

10

To powinno wystarczyć. Na końcu każdej pętli aktualizacji zapisz stan previousGamePadState. Następnie możesz je porównać. To szybki sposób na wykrycie zmian. Nie ma potrzeby zapętlania.

GamePadState.PacketNumber :

Za pomocą parametru PacketNumber można ustalić, czy zmienił się stan wejściowy. Jeśli wartość PacketNumber pozostaje taka sama między dwoma kolejnymi wywołaniami GetState, oznacza to, że dane wejściowe nie uległy zmianie.

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

EDYCJA: Zmieniono na metodę. Nie gwarantuje się, że będzie działał poprawnie, ale powinien działać. Ponadto, ponieważ to naprawdę wykrywa zmiany w danych wejściowych, więc jeśli użytkownik zwolni przycisk, widać to również z tym. Dodałem również, ifaby wykryć ruch kciuka, abyś mógł je przynajmniej zignorować.

Mam nadzieję, że to ci pomoże. Daj mi znać, jeśli to nie odpowiada Twoim potrzebom, jestem pewien, że możemy to rozwiązać.

Instrukcje : wykrywanie naciśnięcia przycisku kontrolera w tej ramce Właściwość GamePadState.PacketNumber

Katu
źródło
Istnieje analogiczny sposób na napisanie tego GamePadStatei enum Buttons, który jest bliższy kontekstowi, z którego korzysta OP.
Seth Battin
1
Nie powinienem nic odpowiadać przed poranną kawą :)
Katu 5'13
1
Teraz wykonuje swoją pracę i nie może być szybszy.
Katu
Whoa, zupełnie inna metoda i myślę, że masz rację, że jest najszybszy. Miły.
Seth Battin
Czy wykrywa tylko naciśnięcia przycisków, czy też wykrywa zwolnienia przycisków?
George Duckett,
1

Jeśli nie przeszkadza ci użycie Reflection, możesz użyć czegoś takiego: (być może nawet dokładnie tego):

        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;
        }
Pandacoder
źródło
1

Możesz ręcznie skonstruować pustąGamePadState , a następnie sprawdzić, czy jest (nie) równość z bieżącą rzeczywistą, którą pobierasz przez wywołanie 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.

}
Seth Battin
źródło
Nie mam pojęcia, czy to działa; Nigdy nie próbowałem tego zrobić. Daj mi znać, czy ci się uda.
Seth Battin
Sprytny pomysł, choć zadziała tylko wtedy, gdy GamePadState zastąpi Equals, co jest mało prawdopodobne. Najprawdopodobniej użyje równości referencyjnej, a zatem powyższego wyrażenia if nigdy nie oceni się jako prawdziwe.
craftworkgames
@craftworkgames Equalsjest inny; porównuje dwa odniesienia dla tego samego wystąpienia. Ale GamePadStateprzeciąża operator ==, aby porównać ich wartości, które podłączyłem w mojej odpowiedzi ( op_Equality).
Seth Battin
Właściwie nie zdawałem sobie sprawy, że GamePadState jest strukturą, która prawdopodobnie będzie działać. Technicznie jednak zachowanie Equals i == jest często takie samo, oczywiście zależy to od implementacji, ale wytyczne zalecają to w ten sposób. Jeśli naprawdę chcesz równości referencji, to również masz obiekt. RefefenceEquals msdn.microsoft.com/en-us/library/bsc2ak47.aspx
craftworkgames
Ach, masz rację, GamePadState jest typem wartości, więc nie ma znaczenia. Niezależnie od tego, == jest przeciążony, równie dobrze może go użyć IMO.
Seth Battin
1

Ponieważ Buttons jest enumaracją, możesz użyć metody Enum.GetValues ​​w następujący sposób:

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

foreach (var button in buttonList)
{
    if (GamePad.GetState(PlayerIndex.One).IsButtonDown(button))
        ExitMainMenu= true;
}
gry rzemieślnicze
źródło