Seite 1 von 1
getkey() funktion
Verfasst: Dienstag 30. März 2021, 11:09
von G-Rizzle
Hi,
aus einem Tutorial habe ich die Funktion, um kontinuierlichen Tastendruck zu prüfen. Die Funktion sieht folgend aus:
Code: Alles auswählen
def getKey(keyName):
ans = False
for event in pygame.event.get():
pass
keyInput = pygame.key.get_pressed()
myKey = getattr(pygame,'K_{}'.format(keyName))
if keyInput[myKey]:
ans = True
return ans
es funktioniert wie gewollt. ABER: was genau bringt die for schleife? also warum wird durch sämtliche events geloopt und dann nichts damit gemacht? wenn ich die auskommentiere funktioniert es nicht mehr
Danke!
Re: getkey() funktion
Verfasst: Dienstag 30. März 2021, 11:45
von __blackjack__
@G-Rizzle: Durch die Schleife werden die Ereignisse intern verarbeitet und die Datenstruktur die von `get_pressed()` zurückgegeben wird aktualisiert. Dafür gibt es aber auch die `pump()`-Funktion. Dann braucht man keine Schleife schreiben die im eigenen Code dann nichts macht.
Die Namen in dem Codeschnippsel sind auch nicht gut. Mal davon abgesehen, dass sie sich nicht an die Konventionen bei der Schreibweise halten (klein_mit_unterstrichen) sind bis auf `event` und `keyName` auch alle Namen inhaltlich verbesserungswürdig.
`getKey()` holt gar keine Taste sondern beantwortet die Frage ob eine gegebene Taste gedrückt ist oder nicht.
`ans` ist eine kryptische Abkürzung. Der Name wird auch viel zu früh an einen Wert gebunden und letztlich braucht man den Namen auch überhaupt gar nicht, denn der Wert entspricht dem Wert von ``keyInput[myKey]`` — *das* wäre einfach das Ergebnis der Funktion.
`keyInput` hiesse besser `pressed_keys` ö.ä.
Bei `myKey` ist ein unnützes `my` im Namen.
Letztlich lässt sich der Funktionskörper auf folgenden Zweizeiler eindampfen:
Code: Alles auswählen
def is_key_pressed(key_name):
pygame.event.pump()
return pygame.key.get_pressed()[getattr(pygame, "K_" + key_name)]
Re: getkey() funktion
Verfasst: Dienstag 30. März 2021, 11:58
von Sirius3
Irgendwo müssen ja die Events verarbeitet werden.
Die for-Schleife ist unnötig, aber der get-Aufruf ist wichtig.
Funktionsnamen schreibt man wie Variablennamen komplett klein. Das my bei myKey ist völlig nichtssagend und kann weg. keyName sollte sowieso nicht so übergeben werden, sondern direkt das pygame.K_X-Attribut. Das kennst Du ja beim Aufruf der Funktion schon.
Variablen definiert man dann, wenn man sie braucht und nicht 5 Zeilen vorher.
Code: Alles auswählen
def get_key(key_code):
_= pygame.event.get()
key_input = pygame.key.get_pressed()
ans = False
if key_input[key_code]:
ans = True
return ans
Es ist aber überraschend, wenn in irgendeiner tief verschachtelten Funktion die Events gelesen werden.
Das muß irgendwo in der Hauptschleife passieren. Wenn man nur ein bool setzt, braucht man kein if.
Bleibt also:
Code: Alles auswählen
def get_key(key_code):
key_input = pygame.key.get_pressed()
return bool(key_input[key_code])
Re: getkey() funktion
Verfasst: Dienstag 30. März 2021, 12:04
von G-Rizzle
danke für deine ausführliche antwort! habe es verstanden. namen wurden so im tutorial vorgegeben, für mein projekt ändere ich eh nochmal alles.
weitere frage (dazu hole ich etwas aus):
ich programmiere die steuerung einer tello drohne in python. ich möchte, dass die drohne startet, wenn ich space >3 sekunden halte. dazu wird, sobald space gedrückt wird, eine liste in jedem loop um die momentane sekundenzeit erweitert. wenn die letzte sekundenzeit nicht mehr mit der vorletzten sekundenzeit in der liste übereinstimmt, bedeutet das, dass eine sekunde vergangen ist. somit wird der sekundenzähler um 1 erhöht. wenn ich space <3 sekunden loslasse, soll der interne sekundenzaehler wieder auf 0 gehen. an sich funktioniert es, nur werden sekundenzaehler und drueckzeiten nicht wieder auf 0, bzw [0, 0] gesetzt wenn ich space loslasse (trotz des keyup events). findet hier wer meinen fehler?
DANKE!!!
mein code:
Code: Alles auswählen
def getKey(keyName):
ans = False
for event in pygame.event.get():
pass
keyInput = pygame.key.get_pressed()
myKey = getattr(pygame,'K_{}'.format(keyName))
if keyInput[myKey]:
ans = True
return ans
def steuern(drone, drueckzeiten, sekundenzaehler):
# starten, landen
if getKey("SPACE") == True and drone.is_flying == False:
drueckzeiten.append(datetime.now().second)
letzteZeit = drueckzeiten[-1]
vorletzteZeit = drueckzeiten[-2]
if letzteZeit != vorletzteZeit:
sekundenzaehler += 1
if sekundenzaehler > 3:
drone.is_flying = True
sekundenzaehler = 0
drueckzeiten = [0, 0]
for event in pygame.event.get():
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
print('losgelassen')
sekundenzaehler = 0
drueckdauer = [0, 0]
steuern_return = {'drueckzeiten': drueckzeiten, 'sekundenzaehler': sekundenzaehler}
print(steuern_return)
return steuern_return
class Tello():
def __init__(self, is_flying):
self.is_flying = is_flying
def main():
steuerung_return = {'drueckzeiten': [0, 0], 'sekundenzaehler': 0}
pygame.init()
fensterBreite = 1500
fensterHoehe = 1000
screen = pygame.display.set_mode((fensterBreite, fensterHoehe))
pygame.display.set_caption("Tello Controll")
drone = Tello(False)
while True:
steuerung_return = steuern(drone, steuerung_return['drueckzeiten'], steuerung_return['sekundenzaehler'])
if __name__ == '__main__':
main()
Re: getkey() funktion
Verfasst: Dienstag 30. März 2021, 12:13
von Sirius3
Da ist ja das von mir beschriebene Problem, dass wenn einmal die Events abgearbeitet sind, dann gibt es in der zweiten for-Schleife keine mehr, oder umgekehrt.
Und in Deinem anderen Thread hatte ich ja schon geschrieben, dass Du einmal auf KEYDOWN und einmal auf KEYUP hören mußt.
Statt hier Wörterbucher als Datenspeicher zu benutzen, nimm besser eine Klasse, oder wenn es so wenig ist, dann kann man es gleich ins Hauptprogramm packen.
Code: Alles auswählen
FENSTER_BREITE = 1500
FENSTER_HOEHE = 1000
class Tello():
def __init__(self, is_flying):
self.is_flying = is_flying
def main():
pygame.init()
screen = pygame.display.set_mode((FENSTER_BREITE, FENSTER_HOEHE))
pygame.display.set_caption("Tello Controll")
drone = Tello(False)
space_down_time = None
while True:
current_time = time.monotonic()
# starten, landen
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
print('gedrückt')
space_down_time = current_time
elif event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
print('losgelassen')
space_down_time = None
if space_down_time is not None and space_down_time - current_time > 3:
drone.is_flying = True
space_down_time = None
if __name__ == '__main__':
main()
Re: getkey() funktion
Verfasst: Dienstag 30. März 2021, 13:07
von G-Rizzle
Sirius3 hat geschrieben: Dienstag 30. März 2021, 12:13
Da ist ja das von mir beschriebene Problem, dass wenn einmal die Events abgearbeitet sind, dann gibt es in der zweiten for-Schleife keine mehr, oder umgekehrt.
Und in Deinem anderen Thread hatte ich ja schon geschrieben, dass Du einmal auf KEYDOWN und einmal auf KEYUP hören mußt.
Statt hier Wörterbucher als Datenspeicher zu benutzen, nimm besser eine Klasse, oder wenn es so wenig ist, dann kann man es gleich ins Hauptprogramm packen.
Code: Alles auswählen
FENSTER_BREITE = 1500
FENSTER_HOEHE = 1000
class Tello():
def __init__(self, is_flying):
self.is_flying = is_flying
def main():
pygame.init()
screen = pygame.display.set_mode((FENSTER_BREITE, FENSTER_HOEHE))
pygame.display.set_caption("Tello Controll")
drone = Tello(False)
space_down_time = None
while True:
current_time = time.monotonic()
# starten, landen
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
print('gedrückt')
space_down_time = current_time
elif event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
print('losgelassen')
space_down_time = None
if space_down_time is not None and space_down_time - current_time > 3:
drone.is_flying = True
space_down_time = None
if __name__ == '__main__':
main()
merci für deinen vorschlag.
ins hauptprogramm würde ich das ungern packen, da dies noch deutlich erweitert werden soll.
ich bin info-fremd und habe vor kurzer zeit erst von oo-programmierung erfahren. bin also ganz neu. verstehe hier den sinn nicht ganz, das dafür oo zu programmieren. klasse "tastatur" mit einzelnen tasten instanzieren, welche als attribute "gedrückt" usw haben? oder wie schlägst du das vor?
Re: getkey() funktion
Verfasst: Dienstag 30. März 2021, 13:57
von Sirius3
Wenn Du komplexere Dinge machst, darfst Du halt doch nur ein Event-Schleife haben.
Für jede Funktionalität, die sich ja den früheren Zustand merken muß, brauchst Du eine Klasse.
So könnte das mit der Klasse aussehen, die dann auf Events horcht:
Code: Alles auswählen
FENSTER_BREITE = 1500
FENSTER_HOEHE = 1000
class Tello():
def __init__(self, is_flying):
self.is_flying = is_flying
self.space_down_time = None
def process_event(self, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
print('gedrückt')
self.space_down_time = time.monotonic()
elif event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
print('losgelassen')
self.space_down_time = None
def do_tick(self):
if not self.is_flying:
if self.space_down_time is not None and self.space_down_time - time.monotonic() > 3:
self.is_flying = True
self.space_down_time = None
def main():
pygame.init()
screen = pygame.display.set_mode((FENSTER_BREITE, FENSTER_HOEHE))
pygame.display.set_caption("Tello Controll")
drone = Tello(False)
while True:
for event in pygame.event.get():
drone.process_event(event)
drone.do_tick()
if __name__ == '__main__':
main()