I am trying to create a game that is similar to piano tiles and I am having issue with animating the game and event loop at the same time. I am trying to split the event loop that check for the KeyPress and the game animation so that it will be smooth and not slow down when I spam a keybind. Can I check if there's a way for me to use asyncio on the event loop so that the animation will not slow down? Thank you.
game.py
import threading
import tkinter
import main
import time
from playsound import playsound
def open_file(music_file):
"""Open a music file."""
with open(music_file, 'r') as file:
return file.read()
class Game:
def __init__(self, root):
self.game_menu_sc = None
self.place_to_hit = []
self.lines = []
self.number_of_keys = 12
self.items = None
self.points = 0
self.root = root
self.clickable_area = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5, 'g': 6, 'h': 7, 'i': 8, 'j': 9, 'k': 10, 'l': 11}
def game_screen(self):
"""Create the game screen of the application."""
for widget in self.root.winfo_children():
widget.destroy()
game_menu_sc = tkinter.Canvas(self.root)
game_menu_sc.configure(bg='white')
screen_width, screen_height = main.get_screen_size(self.root)
width, height = main.scale_to_screen_size(screen_width, screen_height)
game_menu_sc.bind('<KeyPress>', self.keyup)
game_menu_sc.place(width=width, height=height)
game_menu_sc.focus_set()
for i in range(self.number_of_keys):
line = game_menu_sc.create_line(i * int(width / self.number_of_keys), 0,
i * int(width / self.number_of_keys), height, fill='black')
self.lines.append(line)
place_to_hit = game_menu_sc.create_rectangle(i * int(width / self.number_of_keys), int(height - 50),
i * int(width / self.number_of_keys) + int(
width / self.number_of_keys), int(height), fill='black')
self.place_to_hit.append(place_to_hit)
self.game_menu_sc = game_menu_sc
self.animate_game(game_menu_sc, width)
return True
def animate_game(self, canvas, width):
"""Animate the game."""
self.items = self.play_music('music1.txt', width)
while True:
for item in self.items:
canvas.move(item, 0, 1)
canvas.update()
time.sleep(0.01)
if not self.items:
print('points {}'.format(self.points))
break
def keyup(self, event):
"""Handle keyup events."""
list_of_keycodes = [65, 83, 68, 70, 71, 72, 74, 75, 76, 186, 222, 13]
for index, keycode in enumerate(list_of_keycodes):
if keycode == event.keycode:
threading.Thread(target=playsound, args=(f'assets/{index + 1 }.wav',), daemon=True).start()
# winsound.PlaySound(f'assets/{index + 1}.wav', winsound.SND_FILENAME | winsound.SND_ASYNC)
if self.get_collision(index):
self.points += 1
print('collision')
def get_collision(self, index):
"""Check if there is a collision and remove the object if there's a collision."""
p = self.game_menu_sc.coords(self.place_to_hit[index])
collision = self.game_menu_sc.find_overlapping(p[0], p[1], p[2], p[3])
collision = list(collision)
collision_new = list(collision)
for item in collision_new:
if item in self.place_to_hit or item in self.lines:
collision.remove(item)
if len(collision) != 0:
self.items.remove(collision[0])
self.game_menu_sc.delete(collision[0])
return True
else:
return False
def play_music(self, music_file, width):
"""Create the rectangles based on the music file."""
music = open_file(music_file)
notes = music.split(',')
list_of_items = []
for note in notes:
index, keys = note.split(':')
for items in keys:
i = self.clickable_area[items]
rectangles = self.create_rectangle(i * int(width / self.number_of_keys) + 1, -float(index) * 50,
i * int(width / self.number_of_keys) +
int(width / self.number_of_keys) - 1, -float(index) * 50 + 50)
list_of_items.append(rectangles)
return list_of_items
def create_rectangle(self, x1, y1, x2, y2):
"""Create rectangles."""
place_to_hit = self.game_menu_sc.create_rectangle(x1, y1, x2, y2, fill='black')
return place_to_hit
music1.txt
1:a,2:b,3:ab,4:df,5:dl,6:ab,7:ah,8:hj,8:la,9:ga,10:la,11:fd
I have tried using asyncio and followed the solution https://stackoverflow.com/a/47896365/18043570 but I could not even load into the game as I get this error
DeprecationWarning: There is no current event loop
loop = asyncio.get_event_loop()
I have seen multiple solution on how to run both tkinter and an additional function not related to tkinter using asyncio, but I could not find anything related to the event loops