I start writing this answer yesterday but meanwhile you resolve your problem :) But I put my code and maybe it will useful for someone. It shows how to use scheduler
and animate
BTW: I speak Polish but I renamed all variables to English (and convert text) because it is preferred - see more in PEP 8 -- Style Guide for Python Code
The main problem is that you use sleep()
which blocks all code and it can't other elements.
In games and GUI framework you shouldn't use sleep()
and long running code - it may need to special non-blocking functions for sleep - like pygame.time.get_ticks()
- or it needs to run code in separated thread (but it can give other problems).
I never before used pgzero
but I created code (without sleep
) which moves fly randomly using small steps x += random.randint(-5, 5)
y += random.randint(-5, 5)
. I used Clock.scheduler()
instead of sleep
to restart/respawn fly few seconds after die.
In this version fly make many small random moves.
import pgzrun
from pgzero.builtins import Actor, animate, keys
import random
import time
import os
# --- constants ---
WIDTH = 800
HEIGHT = 600
TITLE = 'KILL FLY!'
#ICON = 'data/fly.png'
# --- functions ---
def killed_fly():
screen.draw.text('Fly killed!', (280, 350), color=(255,0 ,0), fontsize=60, alpha=0.8)
def draw_score():
screen.draw.text('Killed:', (5,10), color=(0, 128, 128))
screen.draw.text(str(killed), (100,10), color=(0, 128, 0))
screen.draw.text('Missed:', (5,30), color=(0, 128, 128))
screen.draw.text(str(missed), (100,30), color=(0, 128, 0))
def respawn():
fly.x = random.randint(150, WIDTH-150)
fly.y = random.randint(100, HEIGHT-100)
fly.life = True
fly.image = 'fly'
def on_mouse_down(pos):
global killed
global missed
if fly.collidepoint(pos):
killed += 1
fly.life = False
fly.image = 'fly-swatter'
clock.schedule(respawn, 1.0)
else:
missed += 1
def update():
if fly.life:
fly.x += random.randint(-5, 5)
fly.y += random.randint(-5, 5)
# keep inside window
if fly.left < 0:
fly.left = 0
elif fly.right > WIDTH:
fly.right = WIDTH
if fly.top < 0:
fly.top = 0
elif fly.bottom > HEIGHT:
fly.bottom = HEIGHT
def draw():
background.draw()
fly.draw()
draw_score()
if not fly.life:
killed_fly()
# --- main ---
killed = 0
missed = 0
background = Actor('background')
fly = Actor('fly')
#fly.speed = 2
respawn() # (re)set some values at start
pgzrun.go()
Next I created version which uses animate()
to move fly and I don't need code in update()
. Function animate()
uses on_finished=...
to run this function again so it make next move.
import os
import random
import pgzrun
from pgzero.builtins import Actor, animate, keys
# --- constants ---
WIDTH = 512
HEIGHT = 512
TITLE = 'KILL FLY!'
#ICON = 'data/fly.png'
# --- functions ---
def killed_fly():
text_killed = screen.draw.text('Fly killed!', (280, 350), color=(255,0 ,0), fontsize=60, alpha=0.8)
def draw_score():
screen.draw.text('Killed:', (5,10), color=(0, 128, 128))
screen.draw.text(str(killed), (100,10), color=(0, 128, 0))
screen.draw.text('Missed:', (5,30), color=(0, 128, 128))
screen.draw.text(str(missed), (100,30), color=(0, 128, 0))
def respawn():
"""reset some values before every respawn"""
fly.x = random.randint(150, WIDTH-150)
fly.y = random.randint(100, HEIGHT-100)
fly.life = True
fly.image = 'fly'
animate_fly()
def animate_fly():
global anim
new_x = random.randint(5, WIDTH-5)
new_y = random.randint(5, HEIGHT-5)
anim = animate(fly, pos=(new_x, new_y), duration=3, on_finished=animate_fly)
def on_mouse_down(pos):
global killed
global missed
if fly.collidepoint(pos):
if anim:
anim.stop()
killed += 1
fly.life = False
fly.image = 'fly-swatter'
clock.schedule(respawn, 1.0)
else:
missed += 1
def update():
pass
def draw():
background.draw()
fly.draw()
draw_score()
if not fly.life:
killed_fly()
# --- main ---
killed = 0
missed = 0
anim = None
background = Actor('background')
fly = Actor('fly')
fly.speed = 2
respawn() # st
pgzrun.go()
EDIT:
Version which uses clock.scheduler
to change level every 5 seconds. It adds new fly to list and update speed for all flies.
To make it simpler I created class Fly(Actor)
to have all properties and functions inside class.
import os
import random
import pgzrun
from pgzero.builtins import Actor, animate, keys
# --- constants ---
WIDTH = 512
HEIGHT = 512
TITLE = 'KILL FLY!'
# --- classes ---
class Fly(Actor):
def __init__(self, *args, speed=2, **kwargs):
super().__init__(*args, **kwargs)
self.speed = speed
self.reset()
def reset(self):
"""reset some values before every respawn"""
self.x = random.randint(150, WIDTH-150)
self.y = random.randint(100, HEIGHT-100)
self.life = True
self.image = 'fly'
self.animate()
def animate(self):
new_x = random.randint(5, WIDTH-5)
new_y = random.randint(5, HEIGHT-5)
distance = self.distance_to((new_x, new_y))
duration = (distance/self.speed)/50
self.anim = animate(self, pos=(new_x, new_y), duration=duration, on_finished=self.animate)
def check_collision(self, pos):
if self.collidepoint(pos) and self.life:
if self.anim:
self.anim.stop()
self.life = False
self.image = 'fly-swatter'
clock.schedule(self.reset, 1.0)
return True
else:
return False
# --- functions ---
def killed_fly():
screen.draw.text('Fly killed!', (280, 350), color=(255,0 ,0), fontsize=60, alpha=0.8)
def draw_score():
screen.draw.text('Killed:', (5,10), color=(0, 128, 128))
screen.draw.text(str(killed), (100,10), color=(0, 128, 0))
screen.draw.text('Missed:', (5,30), color=(0, 128, 128))
screen.draw.text(str(missed), (100,30), color=(0, 128, 0))
screen.draw.text('Level:', (WIDTH-105,10), color=(0, 128, 128))
screen.draw.text(str(level), (WIDTH-45,10), color=(0, 128, 0))
def on_mouse_down(pos):
global killed
global missed
hit = False
for fly in flies:
if fly.check_collision(pos):
killed += 1
hit = True
if not hit:
missed += 1
#def on_key_down(key):
# global paused
#
# if key == keys.SPACE:
# paused = not paused
def update():
pass
def draw():
background.draw()
for fly in flies:
fly.draw()
draw_score()
#if paused:
# screen.draw.text('PAUSE', center=(WIDTH//2, HEIGHT//2), color=(0, 0, 0), fontsize=150)
#if not fly.life:
# killed_fly()
def level_up():
global level
global speed
# level number
level += 1
# bigger speed for flies
speed += .5
# add new fly with new speed (it will automaticaly run `animate` with this speed
flies.append(Fly('fly', speed=speed))
# change speed for other flies
for fly in flies:
fly.speed = speed
# run it again after 5 seconds
clock.schedule(level_up, 5.0)
# --- main ---
#paused = False
level = 1 # current level
speed = 2 # current speed
killed = 0
missed = 0
background = Actor('background')
# create list with only one fly
flies = [
Fly('fly'),
]
# update level after 5 seconds
clock.schedule(level_up, 5.0)
pgzrun.go()
BTW: I tried to add function Pause
when you press Space
but it seems animate()
doesn't have method to pause it - it would need to create own animate()
.

(recorded with OBS and converted to animated .gif
with ffmpeg
Images for those who want to run it.
images/background.png

(image Lenna from Wikipedia)
images/fly.png

images/fly-swatter.png

(fly
created as .svg
in free Inkscape and exported to .png
)