0

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

JRiggles
  • 4,847
  • 1
  • 12
  • 27
Robert
  • 3
  • 3
  • 2
    You shouldn't use `time.sleep` or `while True` loops when using `tkinter`. If you want a `tkinter` loop use something like [this](https://stackoverflow.com/a/459131/11106801) – TheLizzard Nov 28 '22 at 12:53
  • I tried to follow that but my game does not even run, and I don't think that would help with my problem right? – Robert Nov 28 '22 at 15:52

0 Answers0