PyGame Custom Event
Event is send only when you use pgame.event.post(my_event)
If you post it only once then you get it only once.
Class Player
could post event I'm dead
and mainloop would end the game.
You can post custom events either manually with pygame.event.post
, as shown in your example.
Also, you can use pygame.time.set_timer
to post a custom event at specific time intervalls. Here's a little example I wrote for another question, where custom events are used to move objects and to control a reload timeout:
import pygame
# you'll be able to shoot every 450ms
RELOAD_SPEED = 450
# the foes move every 1000ms sideways and every 3500ms down
MOVE_SIDE = 1000
MOVE_DOWN = 3500
screen = pygame.display.set_mode((300, 200))
clock = pygame.time.Clock()
pygame.display.set_caption("Micro Invader")
# create a bunch of events
move_side_event = pygame.USEREVENT + 1
move_down_event = pygame.USEREVENT + 2
reloaded_event = pygame.USEREVENT + 3
move_left, reloaded = True, True
invaders, colors, shots = [], [] ,[]
for x in range(15, 300, 15):
for y in range(10, 100, 15):
invaders.append(pygame.Rect(x, y, 7, 7))
colors.append(((x * 0.7) % 256, (y * 2.4) % 256))
# set timer for the movement events
pygame.time.set_timer(move_side_event, MOVE_SIDE)
pygame.time.set_timer(move_down_event, MOVE_DOWN)
player = pygame.Rect(150, 180, 10, 7)
while True:
clock.tick(40)
if pygame.event.get(pygame.QUIT): break
for e in pygame.event.get():
if e.type == move_side_event:
for invader in invaders:
invader.move_ip((-10 if move_left else 10, 0))
move_left = not move_left
elif e.type == move_down_event:
for invader in invaders:
invader.move_ip(0, 10)
elif e.type == reloaded_event:
# when the reload timer runs out, reset it
reloaded = True
pygame.time.set_timer(reloaded_event, 0)
for shot in shots[:]:
shot.move_ip((0, -4))
if not screen.get_rect().contains(shot):
shots.remove(shot)
else:
hit = False
for invader in invaders[:]:
if invader.colliderect(shot):
hit = True
i = invaders.index(invader)
del colors[i]
del invaders[i]
if hit:
shots.remove(shot)
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]: player.move_ip((-4, 0))
if pressed[pygame.K_RIGHT]: player.move_ip((4, 0))
if pressed[pygame.K_SPACE]:
if reloaded:
shots.append(player.copy())
reloaded = False
# when shooting, create a timeout of RELOAD_SPEED
pygame.time.set_timer(reloaded_event, RELOAD_SPEED)
player.clamp_ip(screen.get_rect())
screen.fill((0, 0, 0))
for invader, (a, b) in zip(invaders, colors):
pygame.draw.rect(screen, (150, a, b), invader)
for shot in shots:
pygame.draw.rect(screen, (255, 180, 0), shot)
pygame.draw.rect(screen, (180, 180, 180), player)
pygame.display.flip()
Can't I just "give in" the suitable conditions for posting the event, so that it can generate it automatically then ? I think that way it'd be more practical ...
Implementing such a function is quite easy. Just create a list of conditions and events and check every condition in your main loop:
conditions = [ # blink if player is outside screen
(lambda: not s_r.contains(player), pygame.event.Event(E_OUTSIDE)),
# if mouse if over player then grow and shrink player
(lambda: player.collidepoint(pygame.mouse.get_pos()), pygame.event.Event(E_MOUSE))]
while True:
# generate events from conditions
map(pygame.event.post, [e for (c, e) in conditions if c()])
for event in pygame.event.get():
...
Here's the full example:
import pygame
pygame.init()
screen = pygame.display.set_mode((300, 300))
s_r = screen.get_rect()
player = pygame.Rect((100, 100, 50, 50))
timer = pygame.time.Clock()
flash = 0
grow = True
color = pygame.color.Color('Black')
E_OUTSIDE = pygame.USEREVENT + 1
E_MOUSE = pygame.USEREVENT + 2
conditions = [ # blink if player is outside screen
(lambda: not s_r.contains(player), pygame.event.Event(E_OUTSIDE)),
# if mouse if over player then grow and shrink player
(lambda: player.collidepoint(pygame.mouse.get_pos()), pygame.event.Event(E_MOUSE))]
while True:
# generate events from conditions
map(pygame.event.post, [e for (c, e) in conditions if c()])
for event in pygame.event.get():
if event.type == pygame.QUIT:
raise
elif event.type == E_OUTSIDE and not flash:
flash = 5
elif event.type == E_MOUSE:
if grow:
player.inflate_ip(4, 4)
grow = player.width < 75
else:
player.inflate_ip(-4, -4)
grow = player.width < 50
flash = max(flash - 1, 0)
if flash % 2:
color = pygame.color.Color('White')
pressed = pygame.key.get_pressed()
l, r, u, d = map(lambda x: x*4, [pressed[k] for k in pygame.K_a, pygame.K_d, pygame.K_w, pygame.K_s])
player.move_ip((-l + r, -u + d))
screen.fill(color)
color = pygame.color.Color('Black')
pygame.draw.rect(screen, pygame.color.Color('Grey'), player)
pygame.display.flip()
timer.tick(25)
You can compare events with "==". The compared events must be exactly the same with their attirubutes to be equal
Event1=pygame.event.Event(pygame.USEREVENT, attr1='Event1')
Event2=pygame.event.Event(pygame.USEREVENT, attr1='Event2')
Throw events
pygame.event.post(Event1)
pygame.event.post(Event2)
Main loop
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
break
if event== Event1:
print("event1")
elif event == Event2:
print("event2")