Seite 1 von 2
simpler Kopfrechner mit Pygame
Verfasst: Donnerstag 26. November 2020, 18:09
von Sam123
Hallo zusammen,
ich habe diesmal versucht, einen einfachen Kopfrechner mit Pygame darzustellen.
Hab schon folgendes Grundgerüst.
time.sleep(3) habe ich eingebaut, damit er nach der Eingabe und Bestätigung mit ENTER nicht sofort zur nächsten Aufgabe springt und man etwas länger die Ausgabe "richtig!" oder "falsch!" sehen kann. Das Problem ist, während er "schläft" nimmt er die Zeichen von der Tastatur auf, die dann bei der nächsten Aufgabe angezeigt werden. Woher kommt das? Ich dachte, die Zeichen von der Tastatur würden erst beim nächsten Schleifendurchlauf (der inneren while-Schleife) aufgenommen?
Vielen Dank im Voraus!
Code: Alles auswählen
import pygame, sys
from pygame.locals import *
import random
import time
pygame.init()
clock = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((1000, 300))
pygame.display.set_caption("Kopfrechner")
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
BLUE = (0, 0, 128)
fontObj = pygame.font.Font('freesansbold.ttf', 50)
while True:
zahl_1 = random.randint(1, 101)
zahl_2 = random.randint(1, 101)
ergebnis = zahl_1 + zahl_2
eingabe = ""
eingabe_abgeschlossen = False
while eingabe_abgeschlossen != True:
DISPLAYSURF.fill(WHITE)
anzeige = "{0} + {1} = ".format(zahl_1, zahl_2)
SurfaceObj_anzeige = fontObj.render(anzeige, True, GREEN, BLUE)
DISPLAYSURF.blit(SurfaceObj_anzeige, (200, 50))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
eingabe_abgeschlossen = True
if ergebnis == int(eingabe):
anzeige_richtig_falsch = fontObj.render("richtig!", True, GREEN, BLUE)
DISPLAYSURF.blit(anzeige_richtig_falsch, (600, 50))
else:
anzeige_richtig_falsch = fontObj.render("falsch!", True, GREEN, BLUE)
DISPLAYSURF.blit(anzeige_richtig_falsch, (600, 50))
elif event.key == pygame.K_BACKSPACE:
eingabe = eingabe[:-1]
else:
eingabe = eingabe + event.unicode
anzeige_eingabe = fontObj.render(eingabe, True, GREEN, BLUE)
DISPLAYSURF.blit(anzeige_eingabe, (450, 50))
pygame.display.flip()
clock.tick(30)
time.sleep(5)
Re: simpler Kopfrechner mit Pygame
Verfasst: Donnerstag 26. November 2020, 19:38
von poldi
Ich kenne Pygame nicht so genau aber meistens läuft die Peripherie wie Maus, Tastatur etc. im eigenen Thread.
Re: simpler Kopfrechner mit Pygame
Verfasst: Donnerstag 26. November 2020, 19:50
von __deets__
poldi hat geschrieben: ↑Donnerstag 26. November 2020, 19:38
Ich kenne Pygame nicht so genau aber meistens läuft die Peripherie wie Maus, Tastatur etc. im eigenen Thread.
Steile These, und genau andersherum verhält es sich. Ereignisse kommen üblicherweise nur im main Thread an. In dem auch die GUI läuft.
@sam123: pygame hat eine Event-queue, und darin laufen Ereignisse auf, während dein Programm was anderes macht. Es wäre ja sonst auch dramatisch wenn zb auf ein key press das key release nicht empfangen würde, weil du gerade etwas anderes machst. Wenn du Ereignisse für eine gewisse Zeit ignorieren willst, dann musst du sie so lange einfach wegwerfen, bis der Zeitpunkt gekommen ist, ab dem du sie wieder verarbeiten willst.
Re: simpler Kopfrechner mit Pygame
Verfasst: Donnerstag 26. November 2020, 20:37
von Sirius3
@Sam123: benutze keine *-Importe. Soweit ich das sehe, benutzt Du die auch gar nicht.
Nur Konstanten werden komplett gross geschrieben, DISPLAYSURF ist aber keine Konstante.
Variablennamen werden komplett klein geschrieben. Bei fontObj ist das Obj auch total nichtssagend, weil alles ein Objekt ist.
Definiere Funktionen. sys.exit hat in einem sauberen Programm nichts verloren, vor allem nicht so tief verschachtelt. Im Eventloop wird auch viel zu viel gemacht.
Statt einem time.sleep solltest Du einen event-Loop weiter laufen lassen, vor allem um auf QUIT reagieren zu können.
Code: Alles auswählen
import pygame
import random
import time
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
BLUE = (0, 0, 128)
def event_loop(eingabe):
for event in pygame.event.get():
if event.type == pygame.QUIT:
return eingabe, pygame.QUIT
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
return eingabe, pygame.K_RETURN
elif event.key == pygame.K_BACKSPACE:
eingabe = eingabe[:-1]
else:
eingabe = eingabe + event.unicode
return eingabe, None
def play_round(display):
zahl_1 = random.randint(1, 101)
zahl_2 = random.randint(1, 101)
ergebnis = zahl_1 + zahl_2
aufgabe = "{0} + {1} = ".format(zahl_1, zahl_2)
eingabe = ""
while True:
display.fill(WHITE)
text = font.render(aufgabe, True, GREEN, BLUE)
display.blit(text, (200, 50))
eingabe, status = event_loop(eingabe)
text = font.render(eingabe, True, GREEN, BLUE)
display.blit(text, (450, 50))
if status == pygame.K_RETURN:
text = "richtig!" if ergebnis == int(eingabe) else "falsch!"
text = font.render(text, True, GREEN, BLUE)
display.blit(text, (600, 50))
pygame.display.flip()
if status is not None:
return status
clock.tick(30)
def pause():
end = time.monotonic() + 5
while time.monotonic() < end:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return pygame.QUIT
clock.tick(30)
return None
def main():
pygame.init()
pygame.display.set_caption("Kopfrechner")
font = pygame.font.Font('freesansbold.ttf', 50)
clock = pygame.time.Clock()
display = pygame.display.set_mode((1000, 300))
while True:
status = play_round(display)
if status == pygame.QUIT:
break
status = plause()
if status == pygame.QUIT:
break
pygame.quit()
if __name__ == '__main__':
main()
Re: simpler Kopfrechner mit Pygame
Verfasst: Dienstag 1. Dezember 2020, 18:39
von Sam123
danke für die Tips und den ausführlichen Code!
Ich musste bei den Funktionen play_round() und pause() die Variablen font und clock mit übergeben. Sonst lief das Programm bei mir nicht.
Ich muss ehrlich sagen, das Verständnis für das Zusammenspiel ist noch nicht wirklich da. Bin nunmal Anfänger. Muss noch viel üben

Re: simpler Kopfrechner mit Pygame
Verfasst: Mittwoch 2. Dezember 2020, 20:41
von Sam123
Hallo zusammen.
Ich versuche mit sehr einfachen Beispielen den obigen Code zu verstehen.
Das Beispiel unten läuft auch, aber das Problem ist, ich kann das Fenster nicht schließen, zum Beenden.
Die Zeile mit pygame.quit() wird bei Pycharm auch mit anderer Farbe hinterlegt angezeigt und Pycharm sagt auch "this code is unreachable".
Woran liegt das?
Code: Alles auswählen
import pygame
import random
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
BLUE = (0, 0, 128)
def schreibe_zahl(font, display, clock):
x_Koord_text = random.randint(50, 100)
y_Koord_text = random.randint(50, 100)
zufallszahl = random.randint(1, 10)
display.fill(WHITE)
pygame.draw.rect(display, BLUE, (50, 50, 100, 100), 3)
text_zufallszahl = font.render(str(zufallszahl), True, GREEN, BLUE)
display.blit(text_zufallszahl, (x_Koord_text, y_Koord_text))
pygame.display.flip()
clock.tick(5)
def main():
pygame.init()
pygame.display.set_caption("Zufallszahl")
font = pygame.font.Font('freesansbold.ttf', 50)
clock = pygame.time.Clock()
display = pygame.display.set_mode((1000, 300))
while True:
schreibe_zahl(font, display, clock)
for event in pygame.event.get():
if event.type == pygame.QUIT:
break
pygame.quit()
if __name__ == '__main__':
main()
Re: simpler Kopfrechner mit Pygame
Verfasst: Mittwoch 2. Dezember 2020, 20:56
von __blackjack__
@Sam123: Mit ``break`` wird die Schleife abgebrochen in der das steht. Das ist die ``for``-Schleife, nicht die ``while``-Schleife.
Re: simpler Kopfrechner mit Pygame
Verfasst: Donnerstag 3. Dezember 2020, 11:51
von Sam123
Mist, war ja total offensichtlich

Re: simpler Kopfrechner mit Pygame
Verfasst: Donnerstag 3. Dezember 2020, 13:58
von Sam123
Wenn ich die beiden Funktionen schreibe_zahl und zeichne_kreis im unteren Beispiel einzeln aufrufe, d.h. die andere jeweils auskommentiere, laufen die "Animationen" unterschiedlich schnell ab. Wenn beide Funktionen da sind, dann laufen beide Animationen langsam. Ist auch irgedwie veständlich, dass die langsamere Funktion die schnellere abbremst. Aber geht es irgendwie gleichzeitig mit unterschiedlichen Geschwindigkeiten?
Code: Alles auswählen
import pygame
import random
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
BLUE = (0, 0, 128)
RED = (255,0,0)
YELLOW = (255,255,0)
def schreibe_zahl(font, display, clock):
x_Koord = random.randint(50, 100)
y_Koord = random.randint(50, 100)
zufallszahl = random.randint(1, 10)
pygame.draw.rect(display, WHITE, (50, 50, 100, 100))
pygame.draw.rect(display, BLUE, (50, 50, 100, 100),1)
text_zufallszahl = font.render(str(zufallszahl), True, GREEN, BLUE)
display.blit(text_zufallszahl, (x_Koord, y_Koord))
pygame.display.flip()
clock.tick(5)
def zeichne_kreis(display, clock):
x_Koord = random.randint(200, 300)
y_Koord = random.randint(50, 150)
farbenliste = [GREEN, BLUE, RED, YELLOW]
zufallzahl_farbe = random.randint(0,3)
farbe = farbenliste[zufallzahl_farbe]
pygame.draw.circle(display, farbe, (x_Koord, y_Koord), 10)
pygame.display.flip()
clock.tick(300)
def main():
pygame.init()
pygame.display.set_caption("Zufallszahl")
font = pygame.font.Font('freesansbold.ttf', 40)
clock = pygame.time.Clock()
display = pygame.display.set_mode((1000, 300))
display.fill(WHITE)
status = None
while status != pygame.QUIT:
schreibe_zahl(font, display, clock)
zeichne_kreis(display,clock)
for event in pygame.event.get():
if event.type == pygame.QUIT:
status = pygame.QUIT
pygame.quit()
if __name__ == '__main__':
main()
Noch eine Frage: Warum färbt er den Code jezt nur zweifarbig ein?
Re: simpler Kopfrechner mit Pygame
Verfasst: Donnerstag 3. Dezember 2020, 20:29
von Sirius3
Natürlich darf es pro while-Schleifendurchgang nur ein display.flip und nur ein clock.tick geben.
Und wenn man etwas langsameres haben will, dann darf man die eine Sache nur alle 60 Durchläufe aktualisieren.
Re: simpler Kopfrechner mit Pygame
Verfasst: Donnerstag 3. Dezember 2020, 20:31
von Domroon
@Sam123: ich bin mir unsicher ob ich Deine Frage richtig verstanden habe. Ich würde die Framerate fest vorgeben. Das heißt clock.tick(zahl) muss aus den beiden Funktionen gelöscht werden und stattdessen in der while-Schleife von der main - Funktion eingesetzt werden. Damit z.B. die Zahlen langsamer als die Kreise gezeichnet werden, gebe ich hier vor, dass die Zahlen nur jedes 20. Frame gezeichnet werden sollen:
Code: Alles auswählen
import pygame
import random
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
BLUE = (0, 0, 128)
RED = (255,0,0)
YELLOW = (255,255,0)
def schreibe_zahl(font, display, clock):
x_Koord = random.randint(50, 100)
y_Koord = random.randint(50, 100)
zufallszahl = random.randint(1, 10)
pygame.draw.rect(display, WHITE, (50, 50, 100, 100))
pygame.draw.rect(display, BLUE, (50, 50, 100, 100),1)
text_zufallszahl = font.render(str(zufallszahl), True, GREEN, BLUE)
display.blit(text_zufallszahl, (x_Koord, y_Koord))
pygame.display.flip()
def zeichne_kreis(display, clock):
x_Koord = random.randint(200, 300)
y_Koord = random.randint(50, 150)
farbenliste = [GREEN, BLUE, RED, YELLOW]
zufallzahl_farbe = random.randint(0,3)
farbe = farbenliste[zufallzahl_farbe]
pygame.draw.circle(display, farbe, (x_Koord, y_Koord), 10)
pygame.display.flip()
def main():
pygame.init()
pygame.display.set_caption("Zufallszahl")
font = pygame.font.Font('freesansbold.ttf', 40)
clock = pygame.time.Clock()
display = pygame.display.set_mode((1000, 300))
display.fill(WHITE)
speed = 60
zaehler = 0
status = None
while status != pygame.QUIT:
clock.tick(speed)
if zaehler == (20 or 40 or 60):
schreibe_zahl(font, display, clock)
zeichne_kreis(display,clock)
zaehler += 1
if zaehler == 60:
zaehler = 0
for event in pygame.event.get():
if event.type == pygame.QUIT:
status = pygame.QUIT
pygame.quit()
if __name__ == '__main__':
main()
Re: simpler Kopfrechner mit Pygame
Verfasst: Donnerstag 3. Dezember 2020, 20:32
von Domroon
ja genau, das display.flip() sollte auch in die main-funktion wandern

habe ich oben jetzt nicht berücksichtigt
Re: simpler Kopfrechner mit Pygame
Verfasst: Donnerstag 3. Dezember 2020, 21:49
von Sirius3
@Domroon: or funktioniert nicht so, wie Du hoffst. Hast Du Dir mal das Ergebnis des Ausdrucks (20 or 40 or 60) angeschaut? Dafür gibt es den in-Operator. Zudem wird zaehler bei der Abfrage niemals 60.
Re: simpler Kopfrechner mit Pygame
Verfasst: Freitag 4. Dezember 2020, 06:04
von Domroon
@Sirius3: ich habe den von mit modifizierten Code vor dem posten getestet und er funktioniert wie beschrieben
Es geht sicherlich deutlich eleganter, aber das ist die Änderung die mir eingefallen ist.
Der Zähler wird 60. Bei jedem Durchlauf der while-Schleife erhöhe ich "zaehler" um einen:
Code: Alles auswählen
while status != pygame.QUIT:
clock.tick(speed)
if zaehler == (20 or 40 or 60):
schreibe_zahl(font, display, clock)
zeichne_kreis(display,clock)
zaehler += 1
if zaehler == 60:
zaehler = 0
Re: simpler Kopfrechner mit Pygame
Verfasst: Freitag 4. Dezember 2020, 07:40
von Sirius3
Beim Programmierern gibt es so oft den Fall, dass etwas scheinbar funktioniert und trotzdem falsch ist. Lass dir mal zaehler ausgeben:
Code: Alles auswählen
while status != pygame.QUIT:
clock.tick(speed)
if zaehler == (20 or 40 or 60):
print(zaehler)
schreibe_zahl(font, display, clock)
zeichne_kreis(display,clock)
zaehler += 1
if zaehler == 60:
zaehler = 0
Re: simpler Kopfrechner mit Pygame
Verfasst: Freitag 4. Dezember 2020, 11:41
von Sam123
Super, danke! Läuft jetzt genau wie ich wollte.
Code: Alles auswählen
while_zaehler = 0
while status != pygame.QUIT:
clock.tick(300)
zeichne_kreis(display, clock)
while_zaehler += 1
if while_zaehler in [10, 20, 100]:
print(while_zaehler)
schreibe_zahl(font, display, clock)
if while_zaehler == 100:
while_zaehler = 0
Re: simpler Kopfrechner mit Pygame
Verfasst: Freitag 4. Dezember 2020, 11:44
von Domroon
@Sirius3: Okay Fehler erkannt

"Or" hat wirklich nicht funktioniert und 60 wurde auch nie erreicht. Folgende main Funktion habe ich nun korrigiert:
Code: Alles auswählen
def main():
pygame.init()
pygame.display.set_caption("Zufallszahl")
font = pygame.font.Font('freesansbold.ttf', 40)
clock = pygame.time.Clock()
display = pygame.display.set_mode((1000, 300))
display.fill(WHITE)
speed = 60
zaehler = 0
status = None
while status != pygame.QUIT:
clock.tick(speed)
zwanzigste = [20, 40, 60]
if zaehler in zwanzigste:
print(zaehler)
schreibe_zahl(font, display, clock)
zeichne_kreis(display,clock)
zaehler += 1
if zaehler > 60:
zaehler = 0
for event in pygame.event.get():
if event.type == pygame.QUIT:
status = pygame.QUIT
pygame.quit()
if __name__ == '__main__':
main()
Danke Sirius3

Re: simpler Kopfrechner mit Pygame
Verfasst: Freitag 4. Dezember 2020, 11:45
von Domroon
@Sam123: Super freut mich

Re: simpler Kopfrechner mit Pygame
Verfasst: Freitag 4. Dezember 2020, 11:57
von Sirius3
@Domroon: damit läuft jetzt der Zähler jetzt unrund, zwischen Frame 20 und 40, bzw. 40 und 60 liegen jeweils 20 Frames, zwischen 60 und 20 aber 21.
Re: simpler Kopfrechner mit Pygame
Verfasst: Freitag 4. Dezember 2020, 14:00
von Domroon
@Sirius: Ach stimmt

Okay dann müsste ich doch einfach nur den Zähler anstatt auf 0 dann auf 1 setzen. Denn bislang habe ich die Null mitgezählt
Code: Alles auswählen
speed = 60
zaehler = 1
status = None
while status != pygame.QUIT:
clock.tick(speed)
print(zaehler)
zwanzigste = [20, 40, 60]
if zaehler in zwanzigste:
schreibe_zahl(font, display, clock)
zeichne_kreis(display,clock)
zaehler += 1
if zaehler > 60:
zaehler = 1