Getting Started with 2D Games Using Tkinter (Part x): Keeping Sprites Inside the Screen
In this article, we will improve our game so that sprites cannot leave the game screen.
By checking sprite coordinates, we can keep them inside the visible area.
Improving the DemonSprite Class
First, we will enhance the DemonSprite class by adding two new methods: set_x() and set_y().
These methods allow us to directly modify the sprite’s x and y coordinates.
When a sprite goes outside the screen, we will use these methods to reposition it.
# sprite.py (excerpt)
def set_x(self, x):
self.x = x # change x coordinate
def set_y(self, y):
self.y = y # change y coordinate
Implementing Screen Boundary Checks
Next, we will add a new function called overlap_area() in main.py.
This function checks whether a sprite has moved outside the screen.
It receives a sprite object as an argument and performs four checks:
- If the
xcoordinate is smaller than0(left edge), move it toW(right edge) - If the
xcoordinate is larger thanW(right edge), move it to0(left edge) - Apply the same logic to the
ycoordinate using0andH
# main.py (excerpt)
def overlap_area(obj):
if obj.x < 0:
obj.set_x(W) # move to the right edge
if W < obj.x:
obj.set_x(0) # move to the left edge
if obj.y < 0:
obj.set_y(H)
if H < obj.y:
obj.set_y(0)
We use the overlap_area() function inside the update() function.
# main.py (excerpt)
# demon group
for demon in demons:
overlap_area(demon) # screen boundary check
demon.update(cvs)
With this logic in place, sprites are now confined within the game screen.
When a sprite exits on the right side, it reappears on the left, and vice versa.
Complete Code
Below is the complete code with all features implemented so far.
# sprite.py (complete)
import math
import random
import tkinter
# Demon sprite class
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
# draw a circle
self.oval = cvs.create_oval(
x - r, y - r,
x + r, y + r,
fill="white", width=0
)
def update(self, cvs):
# update position
self.x = self.x + self.vx
self.y = 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
)
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)
# main.py (complete)
import math
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 = []
def init():
""" initialization """
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 i in range(TOTAL_DEMONS):
x = random.random() * W
y = random.random() * H
demon = sprite.DemonSprite(cvs, x, y, 20)
spd = random.randint(1, 4)
deg = random.randint(0, 360)
demon.move(spd, deg)
demons.append(demon)
def update():
""" update loop """
cvs.delete("hud")
msg = "x:{}, y:{}".format(mx, my)
cvs.create_text(
mx, my,
text=msg,
fill="white",
font=FONT,
tag="hud"
)
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 W < obj.x:
obj.set_x(0)
if obj.y < 0:
obj.set_y(H)
if H < obj.y:
obj.set_y(0)
def on_mouse_clicked(e):
print("Clicked:", e.x, e.y)
def on_mouse_moved(e):
global mx, my
mx, my = e.x, e.y
# Tkinter setup
root = tkinter.Tk()
root.title("Hello, Tkinter!!")
root.resizable(False, False)
root.bind("<Button>", on_mouse_clicked)
root.bind("<Motion>", on_mouse_moved)
# Canvas
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 learn how to stop sprites by clicking on them.
Stay tuned!

Top comments (0)