C# zuletzt gedrückten Key löschen

Maxanier

Cadet 3rd Year
Registriert
Jan. 2011
Beiträge
44
Hallo

Ich habe ein Problem, ich erstelle gerade ein einfaches Spiel, und möchte das man per Klick auf Escape in einen Pause Screen kommt und von diesem mit einem weiteren Klick ins Hauptmenu kommt, jetzt ist aber das Problem, dass wenn man während des Spiels auf Escape drückt, er sofort im Pause Screen ist und sofort weiter ins Main Menu springt, weil es denkt, dass Escape immernoch gedrückt ist, habe es mal mit Thread.Sleep probiert hat aber auch nichts gebracht.
Es denkt also kurzeitig nach dem Loslassen immer noch die Taste ist gedrückt, wie kann man das umgehen?

Danke für eure Antworten.
Max
 
Mit welchem Event arbeitest du? KeyPress, KeyDown, KeyUp? (Ich bin mir nicht mehr sicher, ob sie genau so hießen, aber so ungefähr müsste es gewesen sein).

Eventuell kann man da was mit "e.Handled = true;" machen, aber ich denke auch, dass es besser wäre, deinen Code mal ausschnittweise zu sehen.
 
Code:
if (state == 0)
            {
                if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                {
                    //Gehe in den PAuse Screen                    
                    state = 2;
                }
                //Hier ist das eigentliche Spiel
                
            }
            if (state == 1)
            {
                if (GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Enter))
                {
                    //Starte das Spiel
                    state = 0;
                    this.Initialize();
                }
                if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                {
                    this.Exit();
                }

            }
            if (state == 2)
            {
                if (GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Enter))
                {
                    //Fortfahren
                    state = 0;
                }
                if (GamePad.GetState(PlayerIndex.One).Buttons.B == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.End))
                {
                    // Ins Mainmenü
                    state = 1;
                    
                }
            }
            if (state == 3)
            {
                if (GamePad.GetState(PlayerIndex.One).Buttons.B == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.End))
                {
                    state = 1;
                }

            }
Das ist ein Auschnitt aus der Update Schleife.
State 0 = Spiel
1= MainMenu
2= Pause
3=Gameover
Ich benutze XNA von Microsoft
 
Also in 0 arbeitest du mit KeyDown um in 2 zu kommen, wo dann das gleiche für End statt Escape passiert, alternativ müsste B auf dem Gamepad gedrückt sein. Versuch mal, aus der Pause raus nicht mit Keys.End, sondern mit einer anderen Taste zu arbeiten, nur um zu sehen, was dann passiert. Da B kaum gedrückt sein wird, kann es eigentlich nur an End liegen, auch wenn mich das wundern würde.
 
Da du die Lösung nicht kennst rate ich dir dringenst dich in die Thematik vernünftig einzulesen. Hier aber die Lösung:

Am Ende jedes Updates den keyboardState zwischenspeichern, damit du für das nächste Update ein "davor" hast.
Dann kannst du den Tastendruck so abfangen:

Code:
if(davor.IsKeyUp(Taste) && jetzt.IsKeyDown(Taste)
{
//Taste gerade erst runtergedrückt
}


...
davor=jetzt;

Analog dasselbe mit dem Gamepad machen.

Und NIEMALS Thread.Sleep() benutzen!!!
 
XNA managed das Ganze selber, also wann Update() und Draw() aufgerufen werden usw. Abgesehen davon, dass bei sowas Sleep() nie eine Lösung ist, ist es einfach Murks in einer Echtzeitanwendung wie dieser die Timesteps so durcheinanderzuwurschteln. XNA ist gerade dafür da, dass man sowas nicht machen muss, wenn es denn nötig ist.
 
AP Nova schrieb:
Warum nicht, was ist so böse daran?

Grundsätzliche Beantwortung der Frage: Thread.Sleep, lässt immer den Hauptthread schlafen gehen. Was dir bei GUI Programmierung und eigentlich generell immer, massiv um die Ohren fliegen kann und du dann so nette Sachen wie "Keine Rückmeldung" bei deinen Programmen bekommst.
 
Alternativ kannst du zumindest in VBA application.doevents nutzen, dürfte so etwas ähnliches auch in C# geben, oder?
 
Samurai76 schrieb:
Alternativ kannst du zumindest in VBA application.doevents nutzen, dürfte so etwas ähnliches auch in C# geben, oder?
Gibt es auch, aber wird Strengstens davon abgeraten soetwas zu tuen, weil man mal schnell die Kontrolle über die Events verlieren kann und es zu unkontrollierten Verhalten führen kann.
 
Dass Thread.Sleep() auf dem Haupt-/GUI-Thread nicht so sinnvoll ist, leuchtet mir ja noch ein, aber mal angenommen man arbeitet mit Threading, ist die Methode dann immer noch so verpönt?
 
AP Nova schrieb:
Dass Thread.Sleep() auf dem Haupt-/GUI-Thread nicht so sinnvoll ist, leuchtet mir ja noch ein, aber mal angenommen man arbeitet mit Threading, ist die Methode dann immer noch so verpönt?

Deine Aussage "man arbeitet mit Threading" ist mehr als allgemein.
Wenn du Multithreaded Anwendungen schreibst bist du nicht gezwungen mit Thread.Sleep zu arbeiten, macht man es nämlich ordentlich dann brauch man das nicht.
 
Warum wird davon denn auch strengstens abgeraten? Wenn ich ein sehr rechenintensives Programm schreibe,hatte ich oft das Problem, das selbst die GUI von meinem Programm nicht aktualisiert wurde. Und wenn mein Programm nur am rechnen ist und nie eine Wartezeit auf Nutzereingaben darin vorkommt (weil z.B nur der Status von der RS-232 dauerhaft abgefragt wird), dann habe ich quasi keine andere Möglichkeit, der GUI über diese Art Gelegenheit zum Aktualisieren zu geben. Und die in der Zwischenzeiot aufgelaufenen Events sollten meiner Meinung nach gepuffert werden und nach Rücksprung (abarbeitung aller bisher aufgelaufenen Events außerhalb des eigenen Programms) im eigenen Programm wieder abgearbeitet werden können.

Edit: Ok, der Tip von MS dazu ist, das man die Rechenintensiven Routinen auslagern soll in einen eigenen Thread. Da ich mich bisher aber weigerte, threaded Anwendungen gewollt zu schreiben, hatte ich das bisher für eine gute Methode gehalten, da ab VB >6.0 diese Methode nicht thread.sleep verwendet. Und in meinem letzten Projekt habe ich aus versehen mit mehreren Threads gearbeitet und weiß nun, wie ich die Probleme damit umgehe und Thread-übergreifend Daten austauschen kann. Könnte wahrscheinlich aus meinen alten Projekten dieses auch rausschmeißen. Aber sie laufen und machen keine Zicken. Kommt halt auf das Programm an, ob es funkioniert.
 
Zuletzt bearbeitet:
Warum sollte Thread.Sleep bitte den Hauptthread schlafen legen? Es legt den Thread schlafen, aus dem es aufgerufen wurde... oO
 
1668mib schrieb:
Warum sollte Thread.Sleep bitte den Hauptthread schlafen legen? Es legt den Thread schlafen, aus dem es aufgerufen wurde... oO

Joa das ist natürlich korrekt. Ich bezog mich jetzt mehr oder weniger auf das naive Beispiel in der GUI Entwicklung und die Fehlverwendung von Thread.Sleep. Aber Recht hast du natürlich.
 
Ok, also klar, wenn es vom Hauptthread aufgerufen wird legt es schon den schlafen ^^
 
Zurück
Oben