Skip to content Skip to sidebar Skip to footer

Waiting Without Freezing Everything

I am attempting to work on a victory statement. I want screen the flash Blue and Yellow rapidly but not too rapidly when the victory requirements are met which is for now left clic

Solution 1:

The problem is that you can´t get any events for the amount of time the game pauses when you use for instance the pygame.time.wait() or pygame.time.delay() functions of the PyGame time module.

To avoid this problem you could create your very own event which appears on the event queue every given number of milliseconds. You could use pygame.time.set_timer() to create an event:

import pygame    
pygame.init()

#color tupels
BLUE = (55,155,255)
YELLOW = (255,255,0)


#create a new event id called event_500ms
event_500ms = pygame.USEREVENT + 1#set timer event to appear on the event queue every 500 milliseconds
pygame.time.set_timer(event_500ms, 500)

screen = pygame.display.set_mode((800,800))

#global variable V for state-machine
V = 0whileTrue:
    #get events from the event queuefor ev in pygame.event.get():
        if ev.type == pygame.KEYDOWN and ev.key == pygame.K_ESCAPE:
                pygame.quit()
                exit()
        #left (ev.button == 3) mousbutton down -> set variable V = 1if ev.type == pygame.MOUSEBUTTONDOWN and ev.button == 3:
            V = 1#check for the event_500ms event    if ev.type == event_500ms:
            if V == 1:
                screen.fill(BLUE)
                V = 2elif V == 2:
                screen.fill(YELLOW)
                V = 0

            pygame.display.flip() #update whole screen

In this code we use a sort of a so-called state-machine with 3 different stages:

  1. Set V = 1, if a pygame.MOUSEBUTTONDOWN event accurse, (Next state: 2)
  2. Fill the screen blue and increment V, if variable V equals 1. (Next state: 3)
  3. Fill the screen yellow and rest V to 0, if variable V equals 2. (Next state: 1)

I hope this helps :)

Solution 2:

There a two solutions to you problem, which represents the both approaches you tried: Either you wait a specific time for your next tick or you do something each tick but then you have the problem that ticks are dependent on how fast the computer is (and other factors like programs running in the background). (With tick I refer to each run through your main loop, which you probably use.)

At the moment you say "okay, I want to change the background every fourth tick", with the problem that this might be every milisecond, or every second or whenever. So we need to not depend on the amount of ticks that happened but the amount of time. We can use time.perf_counter() to get the current time. This gives us:

#Initialize old_time somewhere
new_time = time.perf_counter()
if new_time - old_time > 0.05:
    change_background()
    old_time = new_time

Normally you don't want to do this for every thing that is time dependent. Instead as the first thing in your while loop calculate a delta time, often called dt

while True:
    dt = time.perf_counter() - old_time
    old_time = time.perf_counter()
    change_background(dt)

Then handle the dt the same way we handled it before:

def change_background(dt):
    cumulative_time += dt
    if cumulative_time > 0.05:
        #do things
        cumulative_time = 0

The other way would be to use some kind of sleep. As you already saw this will freeze the whole thread - but you can create more than one (of course you don't need to use threads, you could use processes or greenlets or all that other fancy multiprocessing stuff). The whole thing is a bit complicated, so I will not go into details here, but generally it is a good idea to have different threads for input and processing. The relative new asyncio module deals with exactly that kind of problem. There are also different solutions like greenlets or threads. Doing things asyncronuos can be confusing at the beginning, the first solution can take you relative far.

EDIT: My answer is independent of pygame, the events used in the other answer does this in the background for you. It is still a good idea to understand this delta time idea and to use it e.g. in physics computation. Generally being dependent on ticks (instead of time) is a bad idea and can give you unexpected behavior. It is said that the original space invaders did depend on ticks for their physics and graphics computations. Thus it sped up everytime you shoot enough enemies. This was an unexpected result (and then kept because it was a good mechanic to increase difficulty). The same problem is faced by emulators: Often old games (which depend on ticks and not on time) would run incredible fast because modern computers have much more processing power. An emulator has to take that into account and "slow processing down".

Solution 3:

Maybe you could try:

import timetime.sleep(5)

Post a Comment for "Waiting Without Freezing Everything"