Auf das Thema antworten  [ 3 Beiträge ] 
Klasse KeyEvents 
Autor Nachricht
Administrator
Benutzeravatar

Registriert: Sa 15. Dez 2012, 19:15
Beiträge: 137
Wohnort: Karlsruhe
Mit Zitat antworten
Hallo Leute!

XNA kennt als ButtonState nur Pressed und Released. Zwar ist dies für die Steuerung einer Figur in den meisten Fällen ausreichend, möchte man allerdings diese Information über ein Netzwerk übertragen, wäre es besser nur jeweils eine Nachricht senden zu müssen, wenn die Taste gerade gedrückt oder wieder losgelassen wurde, um Traffic und Laggs zu vermeiden. Schließlich muss diese Information so nicht 60 Mal in der Sekunde verschickt werden!

Dafür muss man sich allerdings eine eigene kleine Klasse zusammenbasteln. Eine, wie die Klasse KeyEvents.

Neue ButtonState
Für die Events KeyDown, KeyPressed, KeyRelease, KeyReleased habe ich ein neues Enum angelegt: Die JustStates. Um Verwirrung der Bezeichnung vorzubeugen habe ich folgende Werte gewählt:
Code:
public enum JustStates { Up, JustDown, Down, JustUp }

Der Standardwert ist somit Up (nicht gedrückt). Danach kommt JustDown (gerade gedrückt), Down (gedrückt) und JustUp (gerade losgelassen. Unter "gerade" verstehe ich: In diesem aktuellen, jetzigen Tick. Die Klasse muss nämlich über eine Methode in der Update-Methode unseres Spiels aufgerufen werden.

Zustands-Listen
Es gibt drei Listen in denen die aktuell gedrückten, gerade gedrückten und gerade losgelassenen Tasten gespeichert werden:
Code:
 
  internal static List<Keys> DownList = new List<Keys>(5);
  internal static List<Keys> JustDownList = new List<Keys>(5);
  internal static List<Keys> JustUpList = new List<Keys>(5);
 


Gespeicherten Zustand abrufen
Es handelt sich hierbei um keine statische Klasse, damit eine bestimmte Schreibform möglich wird. Darüber hinaus können aber auch statische Methoden verwendet werden:
Code:
 
        // Der Grund dafür, dass es keine statische Klasse ist. Mehr dazu im Beispiel
        internal JustStates this[Keys key]
        {
            get { return Exact(key); }
        }
        internal static JustStates Exact(Keys key)
        {
            if (JustUpList.Contains(key))
                return JustStates.JustUp;
            if (JustDownList.Contains(key))
                return JustStates.JustDown;
            if (DownList.Contains(key))
                return JustStates.Down;
            return JustStates.Up;
        }
        internal static bool Down(Keys key)
        {
            return DownList.Contains(key);
        }
        internal static bool JustUp(Keys key)
        {
            return JustUpList.Contains(key);
        }
        internal static bool JustDown(Keys key)
        {
            return JustDownList.Contains(key);
        }
        internal static bool Up(Keys key)
        {
            return !DownList.Contains(key);
        }
 


Update
Die Klasse hat eine Besonderheit: sie wird bei jedem Tick neu instanziiert und aktualisiert dabei seine Einträge. Wer ohne eine Instanz arbeiten möchte, der kann auch so auf die statische Methode Update zugreifen - muss dann aber auf eine besondere Schreibweise verzichten.
Code:
 
        // Konstruktor ruft das statische Update auf
        internal KeyEvents() { Update(); }
 
        // Die Listen werden neu gefüllt
        internal static void Update()
        {
            Keys[] pressed = Keyboard.GetState().GetPressedKeys();
           
            JustUpList.Clear();
            foreach(Keys key in DownList.ToArray())
                if (!pressed.Contains<Keys>(key)) { JustUpList.Add(key); DownList.Remove(key); }
 
            JustDownList.Clear();
            foreach (Keys key in pressed)
                if (!DownList.Contains(key)) { DownList.Add(key); JustDownList.Add(key); }
        }
 

Die Logik hinter diesem Code ist recht simple. Über KeyBoard.GetState().GetPressedKeys() bekommt man ein Keys-Array zurück mit den momentan gedrückten Tasten. Dann wird die Liste mit den gerade gedrückten Tasten geleert und überprüft, ob die Tasten, die als gedrückt gespeichert sind, noch immer gedrückt werden. Wenn nicht, dann wird die Taste der Liste der gerade gedrückten Tasten hinzugefügt und aus der Liste der gedrückten Tasten gelöscht. Damit ich hier mit foreach arbeiten kann, muss ich bei dieser Schleife zunächst eine flache Kopie der Liste der gedrückten Tasten machen. Sonst müsste ich hinterher das Löschen in einem weiteren Schritt durchführen, weil die Zahl der Aufzählung sich während dem Durchlauf nicht verändern darf.

Danach wird die Liste der gerade gedrückten Tasten gelöscht und geprüft, ob alle Tasten, die momentan gedrückt sind, sich auch in der Liste der gedrückten Tasten befinden. Ist das nicht der Fall, werden sie der Liste der gedrückten und der gerade gedrückten Tasten hinzugefügt.


Anwendungsbeispiele
Konkret habe ich in meinem aktuellen EnergyBowl-Projekt in der Methode Update folgenden Code (Ausschnitt):
Code:
 
 protected override void Update(GameTime gameTime)
    {
      KeyEvents keyEvents = new KeyEvents();
 
      if (KeyEvents.JustDown(Keys.Escape)) { GameState.UnloadContent(); GameState = GameStates.Neuigkeiten; GameState.LoadContent(); }
      if (KeyEvents.JustDown(Keys.Space)) { GameState.UnloadContent(); GameState = GameStates.Einzelspieler; GameState.LoadContent(); }
      else if (KeyEvents.JustUp(Keys.Space)) { GameState.UnloadContent(); GameState = GameStates.Neuigkeiten; GameState.LoadContent(); }
 
      base.Update(gameTime);
  }
 

Zu dem GameState komme ich in einem anderem Beitrag ausführlicher zu sprechen. In diesem Ausschnitt ist nur interessant, dass ich eine Instanz von der Klasse KeyEvents erzeuge und damit die statische Methode Update der Klasse aufrufe (siehe oben). Da ich hier momentan die instanzierte keyEvents nicht verwende, könnte ich auch einfach KeyEvents.Update() aufrufen.

Allerdings gibt es noch eine Alternative zu den statischen Methoden, die nur von der Schreibweise eben anders ist:
Code:
 
  if (keyEvents[Keys.Escape] == JustState.JustDown) { GameState.UnloadContent(); GameState = GameStates.Neuigkeiten; GameState.LoadContent(); }
 

Ich wollte einfach unbedingt einmal die Indexes benutzen ;)

Schöne Grüße,
Magony

_________________
Bei Fragen, Lob, Kritik, Vorschläge, hilfreiche Hinweise oder Alternativvorschläge: Beitrag, neues Thema oder PN.
Für Dinge die diskutiert werden sollten, bitte neues Thema im jeweiligen Forum.
Wenn du nicht weißt wohin: Forum Unsortiert.


Fr 22. Mär 2013, 10:24
Diesen Beitrag melden
Profil Website besuchen
Administrator
Benutzeravatar

Registriert: Sa 15. Dez 2012, 19:15
Beiträge: 137
Wohnort: Karlsruhe
Mit Zitat antworten
Hier kann die komplette Klasse heruntergeladen werden:

http://download.magony.org/?file=csharp/XNA/KeyEvents/KeyEvents.zip

_________________
Bei Fragen, Lob, Kritik, Vorschläge, hilfreiche Hinweise oder Alternativvorschläge: Beitrag, neues Thema oder PN.
Für Dinge die diskutiert werden sollten, bitte neues Thema im jeweiligen Forum.
Wenn du nicht weißt wohin: Forum Unsortiert.


Mi 27. Mär 2013, 14:40
Diesen Beitrag melden
Profil Website besuchen
Administrator
Benutzeravatar

Registriert: Sa 15. Dez 2012, 19:15
Beiträge: 137
Wohnort: Karlsruhe
Mit Zitat antworten
Hallo Leute!

In diesem Thread biete ich euch die Bibliothek magonyORG.Input als OpenSource mit einer kleinem Testumgebung und einem Beispiel an. Sie beinhaltet sowohl die MouseEvents als auch die KeyEvents und den Button. Außerdem bietet sie weitere Verbesserungen und wird auch in Zukunft weiterentwickelt.

Schöne Grüße,
Magony

_________________
Bei Fragen, Lob, Kritik, Vorschläge, hilfreiche Hinweise oder Alternativvorschläge: Beitrag, neues Thema oder PN.
Für Dinge die diskutiert werden sollten, bitte neues Thema im jeweiligen Forum.
Wenn du nicht weißt wohin: Forum Unsortiert.


Sa 28. Sep 2013, 14:38
Diesen Beitrag melden
Profil Website besuchen
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Auf das Thema antworten   [ 3 Beiträge ] 

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast


Du darfst neue Themen in diesem Forum erstellen.
Du darfst Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software
Deutsche Übersetzung durch phpBB.de

Impressum