Display a Counter
In this article, we will display a counter that shows how many demons remain on the screen.
1. Prepare a Counter Variable
First, create a variable named counter to keep track of the remaining number of demons.
# main.py (excerpt)
# Demon counter
counter = TOTAL_DEMONS
2. Decrease the Counter
Each time a demon is captured, we decrement the counter inside the on_mouse_clicked() function.
Since counter is a global variable, don’t forget to declare it using global.
# main.py (excerpt)
def on_mouse_clicked(e):
global counter
# Demon group
for demon in demons:
if demon.is_inside(e.x, e.y):
if demon.is_dead():
continue
demon.die(cvs)
counter = counter - 1 # Decrease demon counter
break
3. Display the Counter
Inside the update() function, draw the counter on the screen using the counter variable.
# main.py (excerpt)
def update():
""" Update function """
cvs.delete("hud")
# Draw mouse coordinates
msg = "x:{}, y:{}".format(mx, my)
cvs.create_text(
mx, my,
text=msg,
fill="white",
font=FONT,
tag="hud"
)
# Draw demon counter
msg = "Remaining Demons: {}".format(counter)
cvs.create_text(
20, 20,
text=msg,
fill="white",
font=FONT,
tag="hud",
anchor="nw"
)
# Demon group
for demon in demons:
overlap_area(demon) # Screen wrap check
demon.update(cvs)
root.after(F_INTERVAL, update)
After implementing this, the number of remaining demons will be displayed on the screen.
Complete Code
Below is the complete code with the counter feature implemented.
# sprite.py (complete code)
import math
import random
import tkinter
class DemonSprite:
def __init__(self, cvs, x, y, r):
self.x = x
self.y = y
self.r = r
self.vx = 0
self.vy = 0
self.dead = False
# Circle for collision detection
self.oval = cvs.create_oval(
x - r, y - r, x + r, y + r,
fill="white", width=0
)
# Random demon type: r, g, b
self.type = random.choice(("r", "g", "b"))
file_alive = f"images/dmn_alive_{self.type}.png"
self.photo_alive = tkinter.PhotoImage(file=file_alive)
file_dead = f"images/dmn_dead_{self.type}.png"
self.photo_dead = tkinter.PhotoImage(file=file_dead)
self.image = cvs.create_image(x, y, image=self.photo_alive)
def update(self, cvs):
self.x += self.vx
self.y += self.vy
# Update circle position
cvs.coords(
self.oval,
self.x - self.r, self.y - self.r,
self.x + self.r, self.y + self.r
)
# Update image position
cvs.coords(self.image, self.x, self.y)
def set_x(self, x):
self.x = x
def set_y(self, y):
self.y = y
def move(self, spd, deg):
radian = deg * math.pi / 180
self.vx = spd * math.cos(radian)
self.vy = spd * math.sin(radian)
def stop(self):
self.move(0, 0)
def die(self, cvs):
self.dead = True
self.stop()
cvs.itemconfig(self.oval, fill="red")
cvs.itemconfig(self.image, image=self.photo_dead)
def is_dead(self):
return self.dead
def is_inside(self, x, y):
dx = (self.x - x) ** 2
dy = (self.y - y) ** 2
dist = (dx + dy) ** 0.5
return dist < self.r
# main.py (complete code)
import random
import sprite
import tkinter
W, H = 480, 320
F_RATE = 30
F_INTERVAL = int(1000 / F_RATE)
FONT = ("Arial", 16)
mx, my = 0, 0
bg_photo, bg_image = None, None
TOTAL_DEMONS = 10
demons = []
# Demon counter
counter = TOTAL_DEMONS
def init():
global bg_photo, bg_image
bg_photo = tkinter.PhotoImage(file="images/bg_jigoku.png")
bg_image = cvs.create_image(W / 2, H / 2, image=bg_photo)
# Create demon sprites
for _ in range(TOTAL_DEMONS):
x = random.random() * W
y = random.random() * H
demon = sprite.DemonSprite(cvs, x, y, 20)
demon.move(random.randint(1, 4), random.randint(0, 360))
demons.append(demon)
def update():
cvs.delete("hud")
# Draw mouse position
msg = "x:{}, y:{}".format(mx, my)
cvs.create_text(mx, my, text=msg, fill="white", font=FONT, tag="hud")
# Draw demon counter
msg = "Remaining Demons: {}".format(counter)
cvs.create_text(20, 20, text=msg, fill="white", font=FONT, tag="hud", anchor="nw")
for demon in demons:
overlap_area(demon)
demon.update(cvs)
root.after(F_INTERVAL, update)
def overlap_area(obj):
if obj.x < 0: obj.set_x(W)
if obj.x > W: obj.set_x(0)
if obj.y < 0: obj.set_y(H)
if obj.y > H: obj.set_y(0)
def on_mouse_clicked(e):
global counter
for demon in demons:
if demon.is_inside(e.x, e.y):
if demon.is_dead():
continue
demon.die(cvs)
counter -= 1
break
def on_mouse_moved(e):
global mx, my
mx, my = e.x, e.y
root = tkinter.Tk()
root.title("Hello, Tkinter!!")
root.resizable(False, False)
root.bind("<Button>", on_mouse_clicked)
root.bind("<Motion>", on_mouse_moved)
cvs = tkinter.Canvas(width=W, height=H, bg="black")
cvs.pack()
init()
update()
root.mainloop()
What’s Next?
Thank you for reading!
In the next article, we will display the remaining time on the screen.
Stay tuned!

Top comments (0)