Zwei Tasten gleichzeitig abfragen, wie geht das?

Anfängerfragen zum Programmieren mit PureBasic.
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von GPI »

ein paar Änderungen:

bei

Code: Alles auswählen

; Hauptprogramm
würd ich ein paar Variablen definieren

Code: Alles auswählen

; Hauptprogramm
define quit.l = #false ; Soll das Programm sich beenden?
define PressedLeft.l = #false ; ist "Links" bereits gedrückt 
define PressedRight.l = #false 
define PressedUp.l = #false 
define PressedDown.l = #false 
Die Event-Schleife würde ich anders gestallten, also statt

Code: Alles auswählen

eventID = WaitWindowEvent()
  Select eventID
  Case #PB_Event_CloseWindow                            
    End
  EndSelect 
würde ich umschreiben zu

Code: Alles auswählen

repeat
  eventID = WindowEvent() ; ist ein Event vorhanden, wenn nein, nicht drauf warten, sondern 0 zurückgeben.
  Select eventID
  Case #PB_Event_CloseWindow                            
    Quit = #true
  case 0 ; kein Event
    break ; repeat-schleife verlassen
  EndSelect 
forever
Es kann mehr als ein Event anliegen, so werden alle abgearbeitet, was die Reaktionsfähigkeit deines Programms (Fenster schließen etc. ).
Das END hab ich rausgenommen und durch eine Variable ersetzt. END beendet dein Program sofort. Du kannst dann nichts mehr abspeichern etc. Ein End würde ich vermeiden bzw. erst wirklich am Schluss machen. Du musst ja bspw. reservierten Speicher, Bilder, Sounddateien etc. freigeben. Klar sollte bei End auch alles erfolgen, aber gewöhn dir an, das du Sachen freigibst, wenn du sie nicht mehr brauchst.
Statt WaitWindowEvent() erfolgt jetzt ein WindowEvent(). Das wartet nicht, gibt aber eine Null zurück, wenn kein Event mehr anliegt.
Die ganze Eventschleife abzuarbeiten dauert in der Regel unter einer Millisekunde. Die Zeit hast du!

statt

Code: Alles auswählen

  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
Hier gefallen mir persönlich ein paar Sachen nicht. Durch ElseIF ist es nicht mehr möglich zwei Tasten gleichzeitig zu drücken bzw. abzufragen.
Zum anderen würde ich hier mit den "pressed"-Variablen überprüfen, ob die Taste schon gedrückt wurde, wenn ja, wird sie ignoriert.
Also bspw. so:

Code: Alles auswählen

  x=0 : y=0                ; Bewegungsvariablen zurücksetzen
  If Key(#VK_W)            ; eine der WASD-Tasten gedrückt? 
    If pressedUp = #false ; war nicht gedürckt
      y-1                    ; Dann Bewegungsvariablen entsprechend verändern  
    endif
    pressedUp = #true ; merken
  else
    pressedUp = #false; wurde losgelassen
  endif

  If Key(#VK_A)
    if not pressedLeft ; geht auch mit not, eigentlich auch eleganter
      x-1
    endif
    pressedLeft = #true
  else
    pressedLeft = #false
  endif

  If Key(#VK_S)
    if not pressedDown
      y+1
    endif
    pressedDown = #true
  else
    pressedDown = #false
  endif

  If Key(#VK_D)
    if not pressedRight
      x+1
    endif
    pressedRight = #true
  else
    pressedRight = #false
  EndIf
der folgende Code ist jetzt überflüssig. Ist auch viel zu kompliziert, du testest ja alle querverweise - unnötig:
Zudem hast du einen Denkfehler drin. Wenn du dir deine alte Tastenabfrage anschaust. Du hast immer Elseif drin, wenn du "W" und "S" gleichzeitig drückst, dann wird nur W abgearbeitet. Du hättest also bei deinen Fällen den Fall Beim testen auf X = -1 nicht mehr auf "W" testen müssen, weil der Fall nie eintreten kann.

Code: Alles auswählen

;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  
Und richtig kritisch ist der folgende Code:

Code: Alles auswählen

  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  
Ist pures Gift! - wie du schon gemerkt hast, der erzeugt eine Auslastung - UND dein Programm reagiert nicht mehr, halte die Tasten gedrückt und klick mal in das Fenster mit der Maus rein - Windows wird melden, dass das Programm nicht mehr reagiert.
Bau *niemals* solche Schleifen. Das konnte man bei den alten Heimcomputer (C64, Atari St, Amiga) etc. machen, du arbeitest in einen Multitasking-System. Entsprechend musst du sicherstellen, das die die Event-Schleife zuverlässig regelmäßig ausgeführt wird.
Löschen. Ist auch nicht mehr notwendig, wir haben das ja jetzt über die Pressed-Variablen gelöst.

Ich weis nicht genau was du programmieren willst. Aber eventuell sollen eine Gegner-KI auch reagieren können, wenn der Spieler nichts macht. Oder du möchtest eine "Idle-Animation" bei der Spielfigur abspielen, damit es nicht so statisch wirkt. Mit so einer "warte bis die Taste losgelassen wird"-Halb-Endlosschleife unmöglich.

achja, natürlich müssen wir noch:

Code: Alles auswählen

ForEver
durch ein

Code: Alles auswählen

until quit 
; alles freigeben, was du so gemacht hast, Hiscoreliste speicher etc.
end ; hier ist es richtig :)
ersetzen - sonst beendet sich das Programm nicht.

Ich hätte eine Übungsaufgabe für dich:
Momentan ist es so, das du die Taste einmal drückst und die Figur nur einmal bewegt wird.
Ändere es so ab, das wenn man die Taste gedrückt hält, alle 500 Millisekunden die Figur sich weiter bewegt.
Diese 500 Millisekunden sollen natürlich wieder von vorne beginnen, wenn man die Taste loslässt und wieder drückt.
Und beachten für jede Taste getrennt. Also bspw rechts halten, soll in 500ms immer nach rechts gehen, aber du willst zwischendrin mal nach oben drücken können. Oder auch oben halten - und dann mit einen unabhängigen 500ms-Timer die tasten wiederholen.
Es gibt eine Funktion in PureBasic, mit der du die vergangene Zeit in Millisekunden rausfinden kannst. Such die mal und schau dir auch das Beispiel in der Anleitung dazu an.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
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 »

OlderCoder hat geschrieben: 05.07.2021 17:04 Ok HeXOR, das war lustig :) .
Jetzt habe ich eine Idee gehabt, auch ohne Deinen bisher nicht mitgelieferten sachdienlichen Hinweis, [...]
Aha, es war also kein sachdienlicher Hinweis, Dich auf ein Leistungsproblem aufmerksam zu machen?
Ich bin nun mal kein Freund von vorgekauten Antworten, Programmieren bedeutet in erster Linie sich Dinge selbst zu erarbeiten.
Und offensichtlich hast Du ja auch selbst entdeckt, worauf ich Dich (nicht) hingewiesen habe.
Na dann... Ziel erfüllt.
OlderCoder
Beiträge: 109
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von OlderCoder »

@HeXOR:
Stimmt, ich habe es selbst gefunden, aber das war eher ein Zufall, da hätte ich auch länger suchen können. Und da ich inzwischen eh schon ziemlich lange mit der Fehlersuche beschäftigt bin (weil ich häufig viele Fehler einbaue, Grund siehe unten), hätte man das in diesem Fall abkürzen können. Selbst erarbeiten muss man sich beim Programmieren sowieso ständig etwas. Besonders wenn der Wissensstand wieder einmal nicht so ohne weiteres zum Ziel passt.
Ich melde mich hier nur, wenn ich auch nach längerer Zeit gegen eine Wand laufe und keinen Plan habe. Deshalb hatte ich diesen Thread gestartet.

@GPI:
Vielen Dank für Deine große Mühe, die Du Dir gemacht hast. Ich werd mir das mal anschauen. Da kann ich sicher viel daraus lernen. Und das werde ich auch versuchen.

Ein bisschen zum Verständnis:
Ich bin leider in den letzten Jahren umständebedingt ein Mensch geworden, der am liebsten mit seinem gewohnten begrenztem Werkzeug arbeitet, weil jede Erweiterung der Möglichkeiten gleichzeitig häufig auch eine Verkomplizierung für mich bedeutet, und Kompliziertes macht meinem MS-belastetem Kopf Stress, und der ist nicht gut.(Ich hab deshalb auch einen Umschulungsversuch zum Fachinformatiker vor 16 Jahren letztlich aufgeben müssen). Deshalb ist Übersichtlichkeit im Code für mich immens wichtig.
So halte ich - als gutes Beispiel - seit vielen Jahren ziemlich verkrampft daran fest, fast ausschließlich globale Variablen zu verwenden. Das hat garantiert Nachteile, aber alles andere stört mein Gefühl der Übersichtlichkeit. Variablen, die überall im Programm bekannt sind, kann ich jederzeit verwenden. Nur als Beispiel. Das ist natürlich Kindergartenprogrammieren, das ist mir klar...
Und für meinen Code schäme ich mich deshalb auch ein wenig. Dass der hier an vielen Stellen ein Kopfschütteln hervorrufen muss, war mir auch klar.

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 »

@GPI:
Jetzt eine Rückmeldung zu ein paar Punkten.

Mein End mitten im Programm ist schlampig, ich weiß. Reine Bequemlichkeit. Ich hab das aber auch schon anders gemacht. Wenn ich davor noch etwas abspeichern oder eine Sicherheitsabfrage brauche, füge ich die sowieso ein, oder baue es wieder um. Aber in diesem Zusammenhang erschien mir das nicht so wichtig. Dass noch andere Ereignisse eintreten können und auch werden, davon gehe ich auch aus.

Dass ich am Ende keinen Speicher für irgendetwas freigebe ist reine Faulheit meinerseits, verbunden mit der fehlenden Überzeugung, dass es auch Nachteile haben kann. Ordentlich ist es sicher nicht. Bisher hab ich das immer nur gemacht, wenn ich zusätzliche Fenster usw. geöffnet hatte.

Und jetzt mal grundsätzlich zu dem Spiel, das es werden soll.
https://www.myabandonware.com/game/daleks-284/play-284
Bitte zu diesem Zweck mal den Link mit dem Online-DOS-Emulator mit Daleks anklicken. Dann wird sicher klar, was ich machen möchte. Ich weiß, die Online-Version ist optisch ausgesprochen hässlich, das kann man aber deutlich schöner machen und auch viele zusätzliche Ideen einbauen.
Das Spiel hat eher Ähnlichkeit mit einem Brettspiel. Es gibt KEINE dynamischen Elemente, und das liebe und will ich auch so in diesem Fall! Absolut stressfrei, man kann in aller Ruhe überlegen, wenn man will.
Die Gegner bewegen sich nach genau einer Spielerbewegung auch genau EINMAL, und alles innerhalb des Spielfeldrasters. Danach wartet das Spiel auf den nächsten Zug des Spielers! Es ist grundsätzlich ein sehr minimalistisches Spiel, nicht vergleichbar mit dem, was heutzutage mindestens üblich ist. Das ist mir aber egal :)

Dadurch, dass ich - anders als in der Online-Version darauf bestanden habe, dass der Spieler sich in 8 anstatt in 4 Richtungen bewegen kann (das bietet mehr Möglichkeiten, besonders wenn es abschaltbar ist), dafür aber nur die WASD-Tasten zur Verfügung hat, entstehen spezielle Probleme, die ich vor dem Thread nicht lösen konnte. Auf jeden Fall war es schwieriger, als ich gedacht hatte.
Das Programm muss ja einzelne Tasten genauso annehmen wie zwei Tasten gleichzeitig, das aber praktisch rundenbasiert.
Und der Thread ist nicht zuletzt deshalb inzwischen auch so lang geworden, weil ich viele Vorschläge bekommen habe, die aber häufig genau diese Probleme gar nicht gelöst haben. Es kamen einige Vorschläge, aber die sind oft am Grundprinzip oder -Problem vorbeigegangen.
Trotzdem haben sie mir geholfen, das Problem zu lösen.
(Ich hatte in der Tastenabfrage GetAsyncKeyState_ und MenuEvents gemischt, das konnte wohl nicht gutgehen, jedenfalls dann nicht, wenn man keine Ahnung hat wie ich.)

Aber dann kam ein Vorschlag von ST4242, der mir ganz gut gefallen hatte (siehe Seite 3). Er hatte aber den Nachteil, dass es zeitabhängig war bei der Eingabe, ob die Tasten wie gewünscht erkannt wurden.
Was bei meiner eigenen Version schließlich nicht so war, sodass ich diese dann verwendet habe. (Die Reaktion auf die Eingabe erfolgt aber erst nach dem Loslassen, aber das nehme ich inkauf. Es geht nicht anders.)

Wenn ich mir jetzt eine Version mit Deinen Vorschlägen aufbauen würde, könnte es dann nicht sein, dass ich wieder eine Version bekomme, die den Schritt-für-Schritt-Ablauf gar nicht unterstützen würde? Leider kann ich nicht so ohne weiteres erkennen, ob das mit Deiner Methode so wirklich klappt. Dazu tue ich mich beim Code-Lesen zu schwer.

Und meine Abfrage macht genau das, was sie soll.

Code: Alles auswählen

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
Das hier hab ich ganz bewusst so gemacht. Vorher waren das einzelne If-EndIf-Abfragen, die mehrere Tastendrücke zugelassen haben. Mit der Folge, dass es gar nicht richtig funktioniert hat, weil häufig Tasten mehrfach erkannt worden sind. Aber in einem Eingabe-Zeitfenster soll ja exakt immer genau eine Eingabe erfolgen, sonst ist das Spiel nicht spielbar. Und dann muss man eine einzelne Taste eindeutig von zwei unterscheiden können. Egal wie lange man die Tasten drückt.
Es kann übrigens jede Doppelbetätigung auf zwei Arten erfolgen. Z.B. bei AD. Erst das A, dann das D, oder erst das D, dann das A, das Steuerergebnis ist dasselbe, aber der Ablauf bei der Erkennung ein anderer. Ich muss beide Fälle überprüfen. Daher der Aufwand. Ob Du möglicherweise trotzdem Recht hast und ich es unnötig kompliziert gemacht habe, könnte mir am ehesten ein funktionsfähiges Beispiel zeigen, das möglichst genau das macht, was meine Version auch tut.

Und das hier

Code: Alles auswählen

 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
war tatsächlich ungesund für den Rechner, wie HeXOR auch erkannt hatte. Aber das war so, als noch kein Delay(1) drin war! (CPU-Auslastung bis 16%). Mit dem Delay aber ist alles gut, keine Auffälligkeiten im Taskmanager.
Warum soll ich das dann ändern?

Ich bin aber trotzdem neugierig, wie die Abfrage mit Deiner Methode laufen würde. Ich weiß nur nicht, ob ich momentan die Zeit habe, eine weitere Version damit aufzubauen. Ich bin langsam in solchen Dingen.
Ganz sicher ist meine Methode alles andere als optimal, das kann ich mir bei meinem geringen Wissensstand nicht vorstellen.
Nur bin ich eigentlich froh, dass es überhaupt läuft. Aktuell hab ich andere Probleme, die die Verschmelzung der Roboter bei gegenseitiger Kollision betrifft, aber das bekomme ich mit einiger Hartnäckigkeit auch noch gebacken.

AddWindowTimer hab ich auch schon des öfteren verwendet. Sowas könnte man natürlich hier auch als Variante einbauen, aber damit ändert sich die Spielcharakteristik erheblich. Da hatte ich zu Amiga-Zeiten mal eine Version gebastelt. (Ich hatte damals das GFA-Basic) Vor gefühlten 100 Jahren....

LG und Danke OlderCoder
Zuletzt geändert von OlderCoder am 06.07.2021 15:30, insgesamt 1-mal geändert.
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von GPI »

OlderCoder hat geschrieben: 06.07.2021 13:54 war tatsächlich ungesund für den Rechner, wie HeXOR auch erkannt hatte. Aber das war so, als noch kein Delay(1) drin war! (CPU-Auslastung bis 16%). Mit dem Delay aber ist alles gut, keine Auffälligkeiten im Taskmanager.
Warum soll ich das dann ändern?
Es ist weiterhin ungesund. Mit den Delay gibts du zwar CPU-Resourcen frei, aber ein Windows-Programm muss regelmäßig die Ereignisse abarbeiten, die WIndows verschickt, ansonsten kann es passieren, das WIndows denkt, das Programm hat sich aufgehangen.
Drück und halte mal die Tasten und klick dann mal in das Fenster mit der Maus rein, verschieb es, etc.

Meine Variante geht da anders vor, es führt Variablen ein, die sich merken, das die Taste gedrückt wurde. Ich nutze sie aktuell, damit nur der aller erste Tastendruck identifiziert wird. Du kannst es aber auch ändern, das es erst reagiert, wenn die Tasten losgelassen werden (Wenn die Taste nicht gedrückt ist, aber die Variable noch auf "war gedrückt") ändern.

Wenn dir die Diagonalen so wichtig sind, würde es sich anbieten, auf den Nummerblock auszuweichen, 7=links/oben, 8= oben, 9= rechts/oben, 4=links, 5=runter, 6=rechts, 1=links/unten, 2=unten, 3=rechts/unten. - dann hast du für jede Richtung eine eindeutige Taste.

oder du machst ein "zwei-Tasten-System" mit asdw bewegst du einen Cursor, wo es hingehen soll und mit space/enter dann bestätigen. Dann muss man die Tasten auch nicht gedrückt halten etc.
Weil es kann sehr schnell passieren, das beim drücken von zwei Tasten der Zeitunterschied zwischen beiden Tasten so ungünstig kommt, das es nicht als eine Taste erkannt wird. Oder du Spieler hast, die aufgrund körperlichen Einschränkungen nicht so einfach die Tasten drücken können.
Wenn du schon ein rundenbasiertes Spiel hast, könntest du auf solche Bedürfnisse eingehen.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
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, das mit dem Fenster stimmt tatsächlich, es lässt sich nicht mehr verschieben. Nun hab ich allerdings kaum je das Bedürfnis, während des Spielens gleichzeitig mit dem Rechner etwas anderes zu tun, und das Spielefenster verschieben erst recht nicht (und es lässt sich ja normal verschieben, wenn ich nicht gerade die Tasten drücke) - aber wer weiß, wo sich das noch auswirkt, wo es dann klemmt.

Ich hatte vor Jahren schon mal versucht, dieses Spiel umzusetzen, ebenfalls mit 8 Richtungen, und hab vermutlich wirklich den Nummernblock dafür verwendet.
Ich hab damals Konstanten wie #PB_Shortcut_Pad3 verwendet. Ich hab mich danach blöd gesucht, aber im ganzen weiten Internet und auch nicht in der PureBasic-Hilfe wird beschrieben, welche Tasten das sind (immer wieder aufgelistet ja, aber nicht erklärt). Ich vermute aber mal stark, dass sind die Zahlentasten des Nummernblocks.
Irgendwie funktioniert das mit dem Nummernblock aber nicht mehr, egal ob ich die Num-Taste drücke oder nicht. Es rührt sich nichts.
Also hab ich aufgegeben, in die Richtung zu arbeiten, zumal ich von vielen Spielen - besonders Minecraft - sowieso die WASD-Tasten als selbstverständlich verwende. Also mussten es diese sein.
Ein Zweitastensystem ist zu wenig intuitiv, zu sperrig, würde mich stören.
Die Erkennung einzelner oder zweier Tasten tut bei mir jedenfalls bisher 100% zuverlässig. Ganz egal wie lang ich jede einzelne Taste drücke.
Aber ganz offensichtlich ist es ein wenig tricky, so etwas umzusetzen. Schwieriger jedenfalls, als würde man sich im Spiel kontinuierlich bewegen wollen.
Da das Spiel grundsätzlich ausschließlich für mich gedacht war (ich werde kaum jemals etwas produzieren, dass für andere unterhaltsam oder nützlich genug sein wird), muss ich mir auch keine Gedanken darüber machen, ob es bei anderen Probleme geben könnte oder nicht. (Ich hab auch keine Freunde oder so, die damit etwas anfangen könnten.)
Aber die gibt es bei der Eingabe bisher ja auch nicht mehr.

Bleibt nur noch das Problem, dass Windows über meine Tastaturabfrage etwas "stolpert". Da ich bisher dadurch aber keine Probleme habe (und wenn das Fenster keinen Fokus hat, ist die Abfrage deaktiviert, das hilft), ist das evtl. erst mal verschmerzbar.

Ich hatte anfangs auch 4 Variablen für die Tasten, die sich gemerkt haben, ob die Taste schon einmal gedrückt war, hab diese aber dann wieder entfernt, weil ich gemerkt habe, dass ich mit X und Y (das hab ich erst später eingebaut) diese Ereignisse auch gut zwischenspeichern kann und dann gleich Variablen habe, die ich gut weiterverwenden kann. Es ist kein Zufall, dass es ist, wie es ist. Dafür hab ich zu oft daran herumgedocktert.
Aber bekanntlich führen oft viele Wege zum Ziel.

Ich fürchte, ich komme hier etwas beratungsresistent rüber, aber ich hab mir Mühe gegeben, zu begründen, wenn ich etwas nicht ändern möchte. Und ich hoffe, dass ich es merke, wenn eine Änderung aber notwendig und richtig ist. Es geht mir nicht darum, wer Recht hat, sondern dass mein Spiel läuft, wie ich das möchte, ohne dass ich unnötig Arbeit damit habe.
Axolotl
Beiträge: 146
Registriert: 31.12.2008 16:34

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von Axolotl »

Ohne jetzt tiefer in diesen Thread einzusteigen. Hier ein kleiner Hinweis aus meiner Vergangenheit: :wink:
"Mehrere" Tasten gleichzeitig kann manchmal schon an der Tastatur scheitern. Stichwort N-Key Rollover (NKRO).
Tastaturen welche die Taster in einer Matrix abfragen können nicht alle Tast-Kombinationen erkennen.
Das es auch Einschränkungen beim USB Interface gibt, habe ich auch schon mal irgendwo gelesen. :oops:
Mostly running PureBasic <latest stable version and current alpha/beta> (x64) on Windows 11 Home
OlderCoder
Beiträge: 109
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von OlderCoder »

Interessant, Axolotl. Ich dachte, solche Probleme gehören heutzutage längst der Vergangenheit an. Aber meine Tastatur dürfte hier eher keine Probleme haben. Ich kann mich auch in Minecraft schräg bewegen und gleichzeitig noch andere Funktionen mit anderen Tasten auslösen, und auch in meinem Code hier funktioneren 2 Tasten gleichzeitig, und mehr brauch ich ja auch nicht.(Ich könnte ja mal spaßeshalber testen, wieviele Tasten gleichzeitig machbar sind. Mit PB ja kein großer Akt.)

Ich kann mir recht gut vorstellen, wie blöd es sein muss, in Jemanden's Code herumzuschauen, in dem kaum irgendetwas so ist, wie man es normalerweise selbst machen würde. Wie soll man damit umgehen? Was kann man tolerieren, wo übt man Kritik? Sicher nicht einfach.
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 »

Wenn ich dieses Daleks mit der Aufgabenstellung vergleiche, suchst Du doch einfach nur sowas hier, oder?

Code: Alles auswählen

EnableExplicit

OpenWindow(1, 200, 200, 800, 600, "Test")
InitSprite()
InitKeyboard()
OpenWindowedScreen(WindowID(1), 0, 0, 800, 600)
CreateSprite(0, 20, 20)
If StartDrawing(SpriteOutput(0))
	Box(0, 0, 20, 20, RGB(255, 0, 155))
	Box(5, 5, 10, 10, RGB(155, 0, 255))
	StopDrawing()
EndIf

Define x, y, KPA, KPD, KPW, KPS, xAdd, yAdd, Timeout, WaitUntilKeysReleased
x    = 50
y    = 50

Repeat
	Repeat
		Select WindowEvent()
			Case #PB_Event_CloseWindow
				Break 2
			Case 0
				Break
		EndSelect
	ForEver

	If ExamineKeyboard()
		KPA = KeyboardPushed(#PB_Key_A)
		KPD = KeyboardPushed(#PB_Key_D)
		KPW = KeyboardPushed(#PB_Key_W)
		KPS = KeyboardPushed(#PB_Key_S)

		If WaitUntilKeysReleased
			If KPA = 0 And KPD = 0 And KPW = 0 And KPS = 0
				WaitUntilKeysReleased = 0
			EndIf
		Else
			If KPA
				xAdd = - 20
				If x + xAdd < 0 : xAdd = 0 : EndIf
			ElseIf KPD
				xAdd = 20
				If x + xAdd > 799 : xAdd = 0 : EndIf
			EndIf
			If KPW
				yAdd = - 20
				If y + yAdd < 0 : yAdd = 0 : EndIf
			ElseIf KPS
				yAdd = 20
				If y + yAdd > 599 : yAdd = 0 : EndIf
			EndIf
			If KeyboardReleased(#PB_Key_A) Or KeyboardReleased(#PB_Key_D) Or KeyboardReleased(#PB_Key_W) Or KeyboardReleased(#PB_Key_S)
				;Zug beenden
				x + xAdd
				y + yAdd
				xAdd                  = 0
				yAdd                  = 0
				WaitUntilKeysReleased = #True
			EndIf
		EndIf
	EndIf

	FlipBuffers()
	ClearScreen(RGB(0, 0, 0))
	DisplaySprite(0, x, y)
ForEver
Zuletzt geändert von HeX0R am 06.07.2021 20:59, insgesamt 3-mal geändert.
OlderCoder
Beiträge: 109
Registriert: 18.03.2013 12:30
Wohnort: Bayerland
Kontaktdaten:

Re: Zwei Tasten gleichzeitig abfragen, wie geht das?

Beitrag von OlderCoder »

Danke Dir HeXOR. Ich konnte jetzt gerade nur einen kurzen Blick drauf werfen, da ich gleich meine Frau von der Arbeit abholen muss.
Ja das ist grundsätzlich das, was ich meine.
Leider muss man bei Dir darauf achten, dass man bei zwei Tasten diese nicht in einem zu großen zeitlichen Abstand loslässt, sonst wird die zuletzt losgelassene Taste nochmal als Eingabe gewertet. Das mag mit etwas Vorsicht vielleicht fast nie passieren. (Mir ist es allerdings beim Testen ein paar Mal passiert, ohne dass ich es darauf angelegt hatte.)
Passiert es aber doch, dann rennt man schnell mal in einen Roboter, von denen in höheren Leveln immer mehr auf dem Spielfeld sind.
Und daher ist das für mich ein Ausschlusskriterium.
(In meiner Lösung passiert das nicht. Auch wenn man nur eine Taste länger gedrückt hält und dann loslässt, gibt es keine zusätzliche Eingabe)
Aber es ist interessant, wie viele Lösungsansätze hier möglich sind. Und dabei hab ich Dein Verfahren auf die Schnelle noch nicht einmal verstanden.
Aber es sieht wieder ganz anders aus. Und es ist ausgesprochen kompakt. Aber vielleicht teilweise auch deshalb, weil das beschriebene Problem nicht ausgeschlossen wurde.
Antworten