Zwei Tasten gleichzeitig abfragen, wie geht das?

Anfängerfragen zum Programmieren mit PureBasic.
OlderCoder
Beiträge: 109
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von OlderCoder »

Auf die Gefahr hin, dass wir uns missverstehen bzw. ich Dich, meine eigentlichen Probleme entstehen genau dadurch, dass ich die Tasteneingaben in jeder "Spielrunde" einmalig brauche.
Und genau damit kämpfe ich noch.
Es ist möglich, dass ich mit Deiner Herangehensweise hier andere Möglichkeiten habe, und dann letztlich diese Probleme schneller vom Tisch sind. Aber dann muss ich sie auch wieder allein lösen. Denn das ist ja nicht Bestandteil Deines Codes.
So habe ich jetzt Möglichkeit 1, in meinem eigenen Programm mein Problem zu lösen, mit oder ohne Eure Hilfe, und Möglichkeit 2, mir Deinen Weg zu erarbeiten, und dann dort das Problem mit der schrittweisen Eingabe zu lösen.
Möglichkeit 1 ist für mich verlockender, weil ich das Gefühl habe, dass ich hier meinem Ziel deutlich näher bin.
Sollte ich aber mit meinem Programm letztlich scheitern, dann versuch ich es gerne nochmal mit Deiner Methode.
Vielleicht entstehen meine Probleme durch diese Eventschlange. Und die gibt es bei Dir vermutlich nicht, das könnte helfen.

Meiner Meinung nach ist das Reduzieren auf das Grundproblem zielführender.
So viele Posts inzwischen, und mir scheint es noch nicht gelungen zu sein, mich ausreichend verständlich zu machen, bei aller Mühe.

Gruß OlderCoder
OlderCoder
Beiträge: 109
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von OlderCoder »

Nur wie ich bei Deinem Code die Tastenwiederholung abschalte, sodass die Spielfigur nur genau einen Bewegungsschritt macht, egal wie lange man auf den Tasten ist, ist mir noch völlig unklar. Ich muss erst mal verstehen, wie hier aus 4 Tasten 8 Bewegungsrichtungen werden.

Edit: Ich habs versucht. Strukturen verstehe ich nur oberflächlich, das ist mir zu kompliziert. (Deshalb bin ich ja auch im Anfängerforum, aber vermutlich bin ich der Anfänger unter den Anfängern...)
OlderCoder
Beiträge: 109
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von OlderCoder »

@Mijikai:

Ich hab in Deinen Code mal hier etwas eingefügt, um die Eingabe auf eine Bewegung zu reduzieren.

Code: Alles auswählen

If StartDrawing(ScreenOutput())
            Circle(x,y,5)
            
            Repeat
            Until GetAsyncKeyState_(#VK_W)=0 And GetAsyncKeyState_(#VK_A)=0 And GetAsyncKeyState_(#VK_S)=0 And GetAsyncKeyState_(#VK_D)=0  
            
            StopDrawing()
          EndIf
Die Absicht war, nach der Ausgabe der Spielfigur zu warten, bis garantiert keine Taste mehr gedrückt ist.
Das funktioniert grundsätzlich, allerdings sehr schlecht.
Häufig wird ein Tastendruck gar nicht angenommen, oder aber nur einer bei zwei Tasten.
Warum.. keine Ahnung.
Wie ich es sonst machen soll, weiß ich auch nicht. Mit KeyReleased hat ich auch mal etwas versucht, das ist dann auch gescheitert.
ST4242
Beiträge: 42
Registriert: 29.10.2011 16:54

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von ST4242 »

Hallo,

ich habe einen vorhergehenden Code eine anderen noch mal etwas überarbeiten.
So scheint es jetzt sauber zu gehen.

Code: Alles auswählen

EnableExplicit

Procedure KeyPressed(_code_)
  ProcedureReturn  (GetAsyncKeyState_(_code_) & $8000)
EndProcedure

Procedure.i Main()
  Protected exit.i
  Protected x.f
  Protected y.f
  Protected mx.f
  Protected my.f
  Protected WarTastenDruck
  Debug "Start"
  If InitSprite()
    If OpenWindow(0,0,0,960,600,#Null$,#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget)
      If OpenWindowedScreen(WindowID(0),0,0,960,600)
        SetFrameRate(60)
        x = 480
        y = 320
        Repeat
          Repeat
            Select WindowEvent()
              Case #PB_Event_CloseWindow
                exit = #True
              Case #Null
                Break
            EndSelect
          ForEver
          mx = 0.0
          my = 0.0
          If WarTastenDruck
              Repeat ; nur ausführen wenn wirlich ein Tastendruck erfolgte
                Delay(1)
              Until GetAsyncKeyState_(#VK_W)=0 And GetAsyncKeyState_(#VK_A)=0 And GetAsyncKeyState_(#VK_S)=0 And GetAsyncKeyState_(#VK_D)=0  
              WarTastenDruck=0
            EndIf
            
          If KeyPressed(#VK_W) Or KeyPressed(#VK_A) Or  KeyPressed(#VK_S) Or  KeyPressed(#VK_D)
            Debug "Taste erkannt"
            
            Delay(100) ; zur sicherheits müssen die Tasten solange gedrückt gehalten werden, so das auch doppelt eingaben gut abgefangen werden
            If KeyPressed(#VK_W) Or KeyPressed(#VK_A) Or  KeyPressed(#VK_S) Or  KeyPressed(#VK_D)
              Debug "Taste bestätigt"
              WarTastenDruck=#True
              ; nur durchlaufen wenn die Tasten 100 ms gehalten wurden
              If KeyPressed(#VK_W)
                my - 10.0
              EndIf
              If KeyPressed(#VK_A)
                mx - 10.0
              EndIf
              If KeyPressed(#VK_S)
                my + 10.0
              EndIf
              If KeyPressed(#VK_D)
                mx + 10.0
              EndIf
                Else
              Debug "abgebrochen"
            EndIf
            
            
          EndIf 
              
              ;Die diagonale Bewegung ist immer schneller, daher sollte hier noch ein ein Faktor einfließen!
              ;           If mx And my
              ;             mx * 0.6;<- Faktor (hier frei gewählt)
              ;             my * 0.6
              ;           EndIf
              x + mx
              y + my
              
              ClearScreen($0)
              If StartDrawing(ScreenOutput())
                Circle(x,y,5)
                DrawText(x,y+20,Str(x)+","+Str(y))
                StopDrawing()
                
              EndIf
              FlipBuffers()
            
         
        Until exit
      EndIf
      CloseWindow(0)  
    EndIf  
  EndIf
  ProcedureReturn #Null
EndProcedure

Main()

End
Grüße
OlderCoder
Beiträge: 109
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von OlderCoder »

Das ist schon seltsam hier. Ich fliege schon nach relativ kurzer Zeit aus diesem Forum. Will ich nach einer Stunde oder so etwas posten oder klicke nur einen Link an, kommt plötzlich wieder die Anmeldemaske (mit Warnung des Firefox, dass meine Daten von jedem einsehbar sind), und ich muss mich schon wieder einloggen. Das ist mir woanders noch nie passiert.

Vielen lieben Dank, ST4242.
Ich hab Deinen Code gleich mal getestet. Er scheint genau das zu tun, was mir die ganze Zeit bisher nicht gelungen ist. Ich hab alle 8 Bewegungsrichtungen getestet und keine Fehler feststellen können. Und mit jeder Tastenaktion genau eine kurze Bewegung. Auch gut, die Bewegung findet nicht erst bei Loslassen der Tasten statt, wie das bei mir gewesen wäre. Ich weiß noch nicht, wie Du es gemacht hast, aber das werde ich herausfinden.
Auf jeden Fall toll!
Jetzt arbeite ich mich mal durch den Code und passe es dann an, damit ich es für mich weiterverwenden kann.
Vermutlich lässt sich das nicht auf die Event-Methode übertragen, die mir lieber wäre, weil ich sie gewohnt bin, aber alles lässt sich lernen.
Und falls es irgendwo klemmen sollte, melde ich mich wieder.
Dankeschön!

Gruß OlderCoder

Edit: Zu meiner Schande muss ich gestehen, dass ich erst jetzt merke, dass KeyPressed kein PB-Befehl, sondern eine Prozedur ist, hinter der wieder GetAsyncKeyState steckt. Vermutlich hab ich oben deshalb den einen oder anderen Müll geschrieben. :shock: :) .
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von mk-soft »

Räume deinen Firefox cache auf und ändern den Link zu Forum

https://www.purebasic.fr/german
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
OlderCoder
Beiträge: 109
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von OlderCoder »

Vielen Dank, mk-soft.
Mit Deinem Link ist die Verbindung jetzt verschlüsselt.
Den Cache hab ich auch mal gelöscht.
Mal sehen, was es bringt.
OlderCoder
Beiträge: 109
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von OlderCoder »

@ST4242 :

Ich habe mich jetzt dann doch für meine Code-Variante entschieden. Jetzt weiß ich ja, warum es bei mir Probleme gab. Ich habe zur Tastatur-Abfrage GetAsyncKeyState_ und MenuEvent() zusammen verwendet, und das schafft offensichtlich ein Stück weit Chaos.
Nachdem ich nur noch GetAsyncKeyState_ verwende, gibt es keine Probleme mehr.
Allerdings muss man dann noch den Fokus des Fensters überprüfen, wenn man verhindern will, dass das Spiel weiter auf Eingaben reagiert, auch wenn es z.B. minimiert oder hinter anderen Fenstern verdeckt ist.

Dein Code hat den Vorteil, dass die Reaktion auf die Eingabe nach kurzer Verzögerung kommt. Der Nachteil ist allerdings, dass es möglich ist, dass man eine falsche Eingabe machen kann, wenn man mit der zweiten Taste aus Versehen länger wartet, als die Verzögerung dauert. Und wählt man deshalb die Verzögerung länger, stört sie spürbar.

Mein Code hat den Vorteil, dass eine Falsch-Eingabe unmöglich ist, aber den Nachteil, das die Spielreaktion erst passiert, wenn man alle Tasten loslässt. Da letzteres in diesem Spiel deutlich weniger problematisch ist als eine Falscheingabe, habe ich mich für meinen Code umentschieden.

Allerdings hatte ich bemerkt, dass ab und zu keine Tasten angenommen werden. Schuld scheint eventID = WaitWindowEvent() zu sein. In den Klammern hatte ich anfangs 20, und je höher ich den Wert gewählt habe, desto seltener sind die Tastaturausfälle passiert. Also hab ich den Wert gleich ganz entfernt. Es scheint bisher keine negativen Folgen zu haben. Aber ich weiß zwar, dass das der Timeout-Wert ist, verstehe aber trotzdem nicht so ganz, was das für Auswirkungen hat.

Hier mal der Code, wieder etwas meiner Art angepasst, und er hat als einzige Rückmeldung für die Eingabe bisher das Debug-Fenster. Vielleicht poste ich demnächst mal eine einfache erste Version des fertigen Spiels.

Code: Alles auswählen

; Abfrage 8 Richtungen

;{ Variablen
EnableExplicit

Global x.b                   ; enthält die gewünschte Bewegung des Spielers in X-Richtung
Global y.b                   ; enthält die gewünschte Bewegung des Spielers in Y-Richtung
Global eventID               ; Event-Variable
;}

;{ Prozeduren
Procedure Key(_code_)               ; vereinfacht die Tastaturabfrage
  ProcedureReturn  (GetAsyncKeyState_(_code_) & $8000)
EndProcedure
Procedure fenster()
  If Not OpenWindow(0,0,0,960,600,#Null$,#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget)
    Debug "Konnte Fenster nicht öffnen!"
    End
  EndIf  
EndProcedure  
;}

; Fokus verarbeiten!

; Hauptprogramm

fenster()

Repeat 
  eventID = WaitWindowEvent()
  Select eventID
  Case #PB_Event_CloseWindow                            
    End
  EndSelect 
  
  x=0 : y=0                ; Bewegungsvariablen zurücksetzen
  If Key(#VK_W)            ; eine der WASD-Tasten gedrückt? 
    y-1                    ; Dann Bewegungsvariablen entsprechend verändern  
  ElseIf Key(#VK_A)
    x-1
  ElseIf Key(#VK_S)
    y+1
  ElseIf Key(#VK_D)
    x+1
  EndIf

  ;Gedrückte Tasten auf zusätzlich gedrückte Nachbartasten überprüfen
  If y=-1                                      ; Falls W gedrückt wurd
    Repeat                                     ; Solange warten 
    Until GetAsyncKeyState_(#VK_W)=0 Or Key(#VK_D) Or Key(#VK_A) ; bis entweder W losgelassen oder D oder A gedrückt worden ist
    If Key(#VK_D)                              ; wenn zusätzlich D gedrückt wurde
      x+1
    ElseIf Key(#VK_A)                          ; wenn zusätzlich A gedrückt wurde
      x-1
    EndIf 
  ElseIf x=1                                   ; Falls D gedrückt wurd
    Repeat                                     ; Solange warten 
    Until GetAsyncKeyState_(#VK_D)=0 Or Key(#VK_W) Or Key(#VK_S) ; bis entweder D losgelassen oder W oder S gedrückt worden ist
    If Key(#VK_W)                              ; wenn zusätzlich W gedrückt wurde
      y-1
    ElseIf Key(#VK_S)                          ; wenn zusätzlich S gedrückt wurde
      y+1
    EndIf  
  ElseIf y=1                                   ; Falls S gedrückt wurd
    Repeat                                     ; Solange warten 
    Until GetAsyncKeyState_(#VK_S)=0 Or Key(#VK_D) Or Key(#VK_A) ; bis entweder S losgelassen oder D oder A gedrückt worden ist
    If Key(#VK_D)                              ; wenn zusätzlich D gedrückt wurde
      x+1
    ElseIf Key(#VK_A)                          ; wenn zusätzlich A gedrückt wurde
      x-1
    EndIf  
  ElseIf x=-1                                   ; Falls A gedrückt wurde
    Repeat                                     ; Solange warten 
    Until GetAsyncKeyState_(#VK_A)=0 Or Key(#VK_S) Or Key(#VK_W) ; bis entweder A losgelassen oder S oder W gedrückt worden ist
    If Key(#VK_S)                              ; wenn zusätzlich S gedrückt wurde
      y+1
    ElseIf Key(#VK_W)                          ; wenn zusätzlich W gedrückt wurde
      y-1
    EndIf  
  EndIf  
     
  Repeat  
    Delay(1)       ;  dann warten, bis alle Tasten losgelassen wurden
  Until GetAsyncKeyState_(#VK_W)=0 And GetAsyncKeyState_(#VK_A)=0 And GetAsyncKeyState_(#VK_S)=0 And GetAsyncKeyState_(#VK_D)=0  
    
  If x<>0 Or y<>0 ; wenn irgendeine Bewegung stattfand
    Debug Str(x)+"    "+Str(y)   ; stellvertretend bisher einzige Spielreaktion auf die Bewegungseingabe!         
  EndIf
    
ForEver
Gruß OlderCoder
Benutzeravatar
HeX0R
Beiträge: 2954
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win10 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2
Kontaktdaten:

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von HeX0R »

Du willst also Deine CPU kochen, wenn einer länger auf ne Taste drückt?
OlderCoder
Beiträge: 109
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von OlderCoder »

Ok HeXOR, das war lustig :) .
Ein Blick auf den Taskmanager hat mir gezeigt, dass Deine Bemerkung nicht ganz fehl am Platz ist. die PureBasic_Compilation1.exe geht bei mir immerhin bis auf über 16% CPU-Auslastung. Das muss bei einem solchen winzigen Programm nicht sein.
Jetzt habe ich eine Idee gehabt, auch ohne Deinen bisher nicht mitgelieferten sachdienlichen Hinweis, und in die Warteschleifen auf das Loslassen der Tasten ein Delay(1) eingebaut, wie es ja woanders auch schon gemacht worden ist (das hätte mir auffallen können).
Und siehe da, der Spuk ist weg.
Zufrieden?
Daraus sollte ich wohl lernen, dass man in Schleifen, die nur abwarten, immer ein Delay einbaut, weil sonst die Schleife mit maximaler Geschwindigkeit läuft, was unnötig ist und Leistung frisst.Genauso sinnfrei, wie wenn jemand sein Spiel mit 1000fps laufen lässt....

Mit den Dingen, die ich über PureBasic nicht weiß, könnte man ein dickeres Buch schreiben, als wenn man ein Handbuch über PureBasic schreiben wollte.
Antworten