Pygame zeit abwarten ohne das alles stoppt

Hier werden alle anderen GUI-Toolkits sowie Spezial-Toolkits wie Spiele-Engines behandelt.
cool_brick24
User
Beiträge: 30
Registriert: Montag 10. September 2018, 12:45

Donnerstag 8. November 2018, 15:48

Hallo liebes Python Forum:

Ich programmiere mit Python ein Spiel mit PyGame und will bestimmte Materialien mit einer verzögerung spawnen lassen. Mir sind die Module

Code: Alles auswählen

 clock, delay und time 
bereits bekannt, aber das Problem ist, wenn ich diese Module benutze friert das Programm ein, d.h. in der Sekunde die gewartet wird kann ich nichts machen. Die Sachen sollen aber nebenher spawnen. Währendessen möchte ich einfach das sich die Figur noch bewegen kann.

Im Klartext:
Ich brauche ein Delay für mein mainloop der nicht alles stoppt bis dieser Delay vorbei ist.
Ich hoffe ihr könnt mir helfen.

mfg
-cool_brick24

PS: Ich denke, das gehört zum Forum-Abteil Sonstige weil es um Pygame geht :D
Benutzeravatar
ThomasL
User
Beiträge: 424
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Donnerstag 8. November 2018, 15:55

cool_brick24 hat geschrieben:
Donnerstag 8. November 2018, 15:48
Ich brauche ein Delay für mein mainloop der nicht alles stoppt bis dieser Delay vorbei ist.
Ja, diesen "Delay" musst du selber programmieren.
Ich würde das eher eine "zeigesteuerte Eventverwaltung" nennen, wobei die Events aktionsabhängig, zufällig oder zeitlich gesteuert auftreten können.
Edit: Habe mal schnell das hier gegoogelt: https://de.wikipedia.org/wiki/Ereignis_ ... rammierung
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
cool_brick24
User
Beiträge: 30
Registriert: Montag 10. September 2018, 12:45

Donnerstag 8. November 2018, 16:19

Also benutzte ich z.b. eine Python Datei mit einem Delay, und wenn dieser rum ist, sendet diese ein Signal an mein Spiel?
Benutzeravatar
ThomasL
User
Beiträge: 424
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Donnerstag 8. November 2018, 16:26

Wenn du mit "Python Datei mit einem Delay" Code meinst, der durch deine Mainloop aufgerufen wird
und z.B. die Zeit misst, die seit einer Aktion im Spiel vergangen ist, dann kann ich das mit Ja beantworten.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
__deets__
User
Beiträge: 4028
Registriert: Mittwoch 14. Oktober 2015, 14:29

Donnerstag 8. November 2018, 16:29

@ThomasL: man *kann* das so machen, wuerde ich aber in pygame bzw. generell bei einem Spiel nicht tun.

@cool_brick24: das vorgehen einer Game-Engine ist ueblicherweise immer gleich:

Code: Alles auswählen

while spiel_ist_am_laufen_am_sein:
         zeit_vergangen = bestimme_vergangene_zeit()
         for ding in alle_dinge_die_in_deinem_spiel_irgendwas_tun:
               ding.update_dich(zeit_vergangen)
         male_alle_dinge()
Das ist in pygame im Grunde auch schon so gedacht. Und damit programmiert sich dein delay ganz einfach: wenn eines deiner Dinge etwas in einer Sekunde tun soll, dann kommt es auf diese Idee in einem update. Dann merkt es sich einfach die Ist-Zeit, addiert eine Sekunde darauf, und in den danach folgenden updates (ca 30 bei 30 FPS) prueft es einfach, ob die zielzeit schon erreicht ist. Wenn nicht, dann tut es halt nix.

Der Grund, warum man das so und nicht wie von Thomas angesprochen tut, ist ganz einfach: Spiele haben eingentlich immer eine konstant verfliessende Zeit. Darum hat man einen solchen mainloop, und kann da immer pruefen, wie weit die Zeit verflossen ist. Desktop Programme hingegen muessen immer nur was tun, wenn der User oder zB das IO-Subsystem was getan hat. Die Maus gedrueckt, ein Netzwerkpaket bekommen, etc.
Benutzeravatar
ThomasL
User
Beiträge: 424
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Donnerstag 8. November 2018, 16:34

__deets__ hat geschrieben:
Donnerstag 8. November 2018, 16:29
Spiele haben eingentlich immer eine konstant verfliessende Zeit. Darum hat man einen solchen mainloop, und kann da immer pruefen, wie weit die Zeit verflossen ist. Desktop Programme hingegen muessen immer nur was tun, wenn der User oder zB das IO-Subsystem was getan hat. Die Maus gedrueckt, ein Netzwerkpaket bekommen, etc.
Zeige mir die Stelle, wo ich etwas geschrieben habe, was dem widerspricht.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
__deets__
User
Beiträge: 4028
Registriert: Mittwoch 14. Oktober 2015, 14:29

Donnerstag 8. November 2018, 16:58

Aus dem von dir zitierten Artikel:

"""
Ein Ansatz, um diese Problemsituation effizienter zu lösen, ist die ereignisorientierte Programmierung, die auf einer Inversion of Control basiert. D. h., es wird nicht mehr im Haupt-Kontrollfluss auf das Eintreten des Ereignisses gewartet (der Hauptkontrollfluss hat die Kontrolle), sondern dem Ereignis wird ein eigener Kontrollfluss zugeordnet (häufig realisiert als Thread), der eigenständig beim Eintreten des Ereignisses aktiv wird und Einfluss auf den Hauptkontrollfluss nehmen kann. (siehe parallele Programmierung)"""

Da man in pygame eben das genau NICHT macht, sonder brav seinen mainloop selbst treibt, mit sleeps um die FPS konstant zu halten, aber ansonsten genau NICHT auf events reagiert (die kommen nur in Form von externen Systemen wie input ins Spiel, und werden fuer den Programmierer transparent gechached & dann angeboten, wenn er oder sie POLLT) widerspricht das dem, wie man in pygame arbeitet, und wie die meisten Spiele arbeiten.

Natuerlich kannst du eine (timer)ereignisbasierte Abstraktion auf einen solchen selbst-getriebenen Loop aufsetzen. Darum schrieb ich auch "man *kann* das so machen". Macht man halt ueblicherweise nicht. Aus schon genannten Gruenden. Wie haette ich das denn deiner Meinung nach anders ausdruecken sollen, damit du dich nicht gleich angemacht fuehlst? Nur mal so aus Interesse.
Benutzeravatar
ThomasL
User
Beiträge: 424
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Donnerstag 8. November 2018, 17:04

@cool_brick24
Schau mal hier bei Packt rein https://mapt.packtpub.com/free-trial-14-days/

Hier findest du einen Kurs und zwei Bücher zu deiner Thematik.
www.packtpub.com/game-development?searc ... =Available

Innerhalb der ersten 14 Tage nach Anmeldung kannst du diese ausprobieren.
Wenn du danach kein Geld bezahlen willst, musst du dein Abo vorher kündigen.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
__deets__
User
Beiträge: 4028
Registriert: Mittwoch 14. Oktober 2015, 14:29

Donnerstag 8. November 2018, 17:28

cool_brick24 hat geschrieben:
Donnerstag 8. November 2018, 16:19
Also benutzte ich z.b. eine Python Datei mit einem Delay, und wenn dieser rum ist, sendet diese ein Signal an mein Spiel?
Nein. Theoretisch kann man das machen, weil pygame custom events kennt, und das ist ein Mechanismus, den man manchmal benutzen muss, wenn man mit anderen Systemen die Threads benutzen zusammen arbeiten muss. ZB GPIO Eingaben bei einem Raspberry PI.

Aber Code der Form

Code: Alles auswählen

tuwas()
delay(10) # hier steht der Code dann 10 Sekunden
schick_ein_signal()
funktioniert nicht. Und auch die oben angesprochene theoretische Moeglichkeit fuehrt auch nur dazu, dass du in deiner Hauptschleife bekommst, und dann rausfinden musst, wer das denn eigentlich bekommen soll. Und es gibt auch nur eine begrenzte Anzahl von solchen Events, aber potentiell viel mehr Dinge in deinem Spiel, die auf irgendwas warten. Und nebenlaeufige Progarmmierung mit Threads hat auch noch eine ganze Reihe anderer Tuecken, das will man also nicht.

Ein Spawnpoint, der zB immer alle paar Minuten ein neues Monster erzeugt, wird einfach als Spielobjekt angelegt, und regelmaessig aufgerufen. Wenn es Zeit ist, ein neues Monster zu erschaffen, tut er das. Mehr muss man dazu nicht machen.
cool_brick24
User
Beiträge: 30
Registriert: Montag 10. September 2018, 12:45

Freitag 9. November 2018, 15:39

Okay. Danke für die Antwort. Jetzt hab ich noch eine Frage zu diesem Projekt (Das Thema hier im Forum gehört zum Projekt):

Mir wird das gemalte nicht angezeigt. D.h. ich lasse meinen Spieler malen, update den Bildschirm und lösche ihn danach wieder(Steht im Mainloop). Reintheoretisch müsste das klappen, aber mir wird nur ein schwarzer Bildschirm angezeigt. Hier mein Code:

Code: Alles auswählen



#Imports
import pygame
import sys
import random


#Initsalisiere Pygame
pygame.init()
#Breite, höhe des Fensters
(width, height) = (750, 750)
screen = pygame.display.set_mode((width, height))
#Titel
pygame.display.set_caption("Game...")
pygame.display.flip()




#Timer
clock = pygame.time.Clock()

#Variablen

#Mitte
middle = (int(width / 2), int(height / 2))

#Farben
#Sky
blue = (0, 30, 255)

#PlayerColors
red = (255, 0, 0)
green = (0, 255, 0)
yellow = (255, 242, 0)
white = (255, 255, 255)




#Runde vorbei
end = False

#Leben
lives = 10

#Materialien
iron = 0
gold = 0
diamond = 0
smaragd = 0

#Player1
def drawP1(position, size, color):
     pygame.draw.circle(screen, (color), position, size)

#Funktionen
def exit():
     pygame.quit()
     sys.exit()





###########-
#Arbeitsplatz##
###########-




#Mainloop
while end == True:

     for event in pygame.event.get():
          if event.type == pygame.QUIT:
               end = True
               pygame.quit()
               sys.exit()

          elif event.type == pygame.KEYDOWN:
               if event.key == pygame.K_ESCAPE:
                    end = True
                    pygame.quit()
                    sys.exit()

     drawP1(middle, 15, green)
     
     pygame.display.update()

     screen.fill(blue)
          
     

Und zu ThomasL: Ich will mir kein Kurs/Buch kaufen oder nur 14 Tage kostenlos ansehen. Momentan habe ich schon einen Kurs, der aber nicht über so etwas informiert.


mfg


-cool_brick24
Benutzeravatar
__blackjack__
User
Beiträge: 1599
Registriert: Samstag 2. Juni 2018, 10:21

Freitag 9. November 2018, 16:20

@cool_brick24: Das Programm beendet sich sofort wieder weil `end` auf `False` gesetzt wird, die Hauptschleife aber die Bedingung ``while end == True:`` hat. Was wenn man es liest schon total falsch klingt.

Auf literale `True`/`False`-Werte sollte man sowieso nicht explizit testen, denn man hat ja schon einen Wahrheitswert, durch den Vergleich bekommt man ja nur wieder einen Wahrheitswert, und zwar entweder den, den man sowieso schon hatte – da kann man den auch gleich nehmen, oder das Gegenteil davon – dafür gibt es ``not``. Also entweder ``while end:`` oder ``while not end:``. Wobei man `end` in Deinem Code überhaupt gar nicht braucht, denn das wird nie auf einen anderen Wert gesetzt der danach auch tatsächlich irgendwo benutzt würde, denn an den Stellen wo Du `end` einen neuen Wert zuweist, wird das Programm kurz darauf durch ein `sys.exit()` beendet.

*Das* allerdings ist auch wieder etwas fragwürdig, denn man sollte `sys.exit()` nur verwenden wenn man es auch tatsächlich braucht, also wenn man explizit einen Rückgabecode an den Aufrufer des Programms kommunizieren will. In den allermeisten anderen Fällen, und IMHO auch hier, ist das eher ein Versuch sich um einen sauberen Programmablauf zu kümmern und mit diesem Hack eine Abkürzung zu nehmen.

Code: Alles auswählen

    **** COMMODORE 64 BASIC V2 ****
 64K RAM SYSTEM  38911 BASIC BYTES FREE
   CYBERPUNX RETRO REPLAY 64KB - 3.8P
READY.
█
Benutzeravatar
ThomasL
User
Beiträge: 424
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Freitag 9. November 2018, 16:29

cool_brick24 hat geschrieben:
Freitag 9. November 2018, 15:39
Und zu ThomasL: Ich will mir kein Kurs/Buch kaufen oder nur 14 Tage kostenlos ansehen. Momentan habe ich schon einen Kurs, der aber nicht über so etwas informiert.
Du möchtest dich also nicht kostenlos fortbilden aber unsere Hilfe kostenlos in Anspruch nehmen :?:
Schade.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
Benutzeravatar
__blackjack__
User
Beiträge: 1599
Registriert: Samstag 2. Juni 2018, 10:21

Freitag 9. November 2018, 19:22

@cool_brick24: Was ist das denn für ein Kurs der nicht über die absolut grundlegende Verwendung der Bibliothek informiert?

Code: Alles auswählen

    **** COMMODORE 64 BASIC V2 ****
 64K RAM SYSTEM  38911 BASIC BYTES FREE
   CYBERPUNX RETRO REPLAY 64KB - 3.8P
READY.
█
cool_brick24
User
Beiträge: 30
Registriert: Montag 10. September 2018, 12:45

Freitag 9. November 2018, 21:55

@_blackjack_ Udemy. Python Boot camp
cool_brick24
User
Beiträge: 30
Registriert: Montag 10. September 2018, 12:45

Freitag 9. November 2018, 22:13

Hab jetzt noch eine frage, nachdem ich den Code überarbeitet hatte:

Wieso flackern meine gemalten Linien?:

Code: Alles auswählen


#PyBedwars - by cool_brick24
#Minecraft Hypixel Bedwars in Python neu erstellt.

#Ideen:

'''
-Andere Texturen etc.
-Unsichtbaren 1 Pixel breiten Balken runter laufen lassen, und wenn dieser unten ist, spawnt dieser wieder oben und ein Eisen wird generiert. Somite kann ich die Pixel anzahl(Wie viele er nach unten gehen soll),
-bestimmen und dies als Zeit benutzten ohne das mein Programm stoppt!



'''





#Imports
import pygame
import sys
import random


#Initsalisiere Pygame
pygame.init()
#Breite, höhe des Fensters
(width, height) = (750, 750)
screen = pygame.display.set_mode((width, height))
#Titel
pygame.display.set_caption("PyBedwars - V 1.0 - by Cool_brick24")
pygame.display.flip()




#Timer
clock = pygame.time.Clock()

#Variablen

#BlockAuswahlLinien
blockSelectionX = [50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750]
blockSelectionY = [50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750]
for i in range(1, 15):
     posLXS = (int(blockSelectionX[i]), int (blockSelectionY[1]))
     posLXE = (int(blockSelectionX[i]), int (blockSelectionY[14]))

#temporär
temp = 0

#Mitte
middle = (int(width / 2), int(height / 2))

#Farben
#Sky
blue = (0, 30, 255)

#PlayerColors
red = (255, 0, 0)
green = (0, 255, 0)
yellow = (255, 242, 0)
white = (255, 255, 255)

#Andere Farben
black = (0, 0, 0)



#Leben
lives = 10

#Materialien
iron = 0
gold = 0
diamond = 0
smaragd = 0



#Player1
def drawP1(position, size, color):
     pygame.draw.circle(screen, (color), position, size)


     
     

#Funktionen
def exit():
     pygame.quit()
     sys.exit()





###########-
#Arbeitsplatz##
###########-




#Mainloop
while True:

     for event in pygame.event.get():
          if event.type == pygame.QUIT:
               pygame.quit()
               sys.exit()

          elif event.type == pygame.KEYDOWN:
               if event.key == pygame.K_ESCAPE:
                    pygame.quit()
                    sys.exit()


      
          for i in range(1, 15):
               pygame.draw.line(screen, (black), posLXS, posLXE)

     drawP1(middle, 15, green)
     
     pygame.display.update()

     screen.fill(blue)


mdg
-cool_brick24
Antworten