Getting Started with 2D Games Using Tkinter (Part 9): Display a Counter

Published: (December 24, 2025 at 12:58 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

Display a Counter

In this article we add a counter that shows how many demons remain on the screen.

First, create a variable named counter to keep track of the remaining number of demons.

# Demon counter
counter = TOTAL_DEMONS

Each time a demon is captured we decrement the counter inside the on_mouse_clicked() function.
Since counter is a global variable, declare it with global.

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

Inside the update() function, draw the counter on the screen using the counter variable.

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

sprite.py

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  W: obj.set_x(0)
    if obj.y  H: obj.set_y(0)

Main script

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("", on_mouse_clicked)
root.bind("", on_mouse_moved)

cvs = tkinter.Canvas(width=W, height=H, bg="black")
cvs.pack()

init()
update()
root.mainloop()

Stay tuned!

Back to Blog

Related posts

Read more »