Python Forum
[Tkinter] Snakegame is very laggy
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] Snakegame is very laggy
#1
Hi there! I am making a Python game at my school, and have basically made the whole game. I am very new at programming, so please be kind haha.
My problem is that, for each time the snake moves, it starts to lag progressively. The problem started, when I implemented the moveSnake function.

Link for my project: (it's in the Class_in_other_file, don't ask about the name haha)
https://github.com/Andersx2/Programmering-B.git
Thank you for your help.

Full code as a single file for testing - Yoriz
import random
import tkinter as tk

# from class_in_other_file._movement import Movement


class Movement:
    def __init__(self):
        self.rows = None
        self.cols = None

    def findSnakeHead(self):
        """ Finder hovedet af slangen via den maksimale værdi """
        self.rows = len(self.snakeBoard)
        self.cols = len(self.snakeBoard[0])

        for self.row in range(self.rows - 1):
            for self.col in range(self.cols - 1):
                if (
                    self.snakeBoard[self.row][self.col]
                    > self.snakeBoard[self._headRow][self._headCol]
                ):
                    self._headRow1 = self.row
                    self._headCol1 = self.col
        return self._headRow1, self._headCol1

    def removeTail(self):
        """ Subtraherer alle tal < 0 i hele talrækken og gentegner. """
        self.rows = len(self.snakeBoard)
        self.cols = len(self.snakeBoard[0])

        for self.row in range(self.rows):
            for self.col in range(self.cols):
                if self.snakeBoard[self.row][self.col] > 0:
                    self.snakeBoard[self.row][self.col] -= 1

    def moveSnake(self, drow, dcol):
        """ Flytter Snake i en ny retning. Tager en ny tillagt row/col værdi"""
        self._newHeadRow = self._headRow + drow
        self._newHeadCol = self._headCol + dcol
        self._snakeDRow = drow
        self._snakeDCol = dcol

        if (
            (self._newHeadRow < 0)
            or (self._newHeadRow >= self.rows)
            or (self._newHeadCol < 0)
            or (self._newHeadCol >= self.cols)
        ):
            # Løb ind i en væg
            self.gameOver()

            # Løb ind i sig selv
        elif self.snakeBoard[self._newHeadRow][self._newHeadCol] > 0:
            self.gameOver()

        elif self.snakeBoard[self._newHeadRow][self._newHeadCol] < 0:
            self.snakeBoard[self._newHeadRow][self._newHeadCol] = (
                self.snakeBoard[self._headRow][self._headCol] + 1
            )

            SnakeFood.placeFood(self)
            self.re_draw()

        else:
            print("fejl")
            self.snakeBoard[self._newHeadRow][self._newHeadCol] = (
                self.snakeBoard[self._headRow][self._headCol] + 1
            )

            Movement.removeTail(self)
            self.re_draw()
        self._headRow = self._newHeadRow
        self._headCol = self._newHeadCol


# from class_in_other_file._snakeFood import SnakeFood


class SnakeFood:
    def __init__(self, master, canvas):
        self._master = master
        self._c = canvas
        self.rows = None
        self.cols = None
        self.randomCol = 0
        self.randomRow = 0
        self.noFood = None

    def placeFood(self):
        self.noFood = True
        self.rows = len(self.snakeBoard)
        self.cols = len(self.snakeBoard[0])

        while True:
            self.randomRow = random.randint(0, self.rows - 1)
            self.randomCol = random.randint(0, self.cols - 1)
            if self.snakeBoard[self.randomRow][self.randomCol] == 0:
                self.snakeBoard[self.randomRow][self.randomCol] = -1
                print(self.snakeBoard[self.randomRow][self.randomCol])
                break


"""
Main
"""


class SnakeGame:
    def __init__(self, master, canvas):
        self._master = master
        self._c = canvas
        self._title = "The Real Snake Game"

        self._headRow = 0
        self._headCol = 0

        self._newHeadRow = None
        self._newHeadCol = None
        # photo = tk.PhotoImage("/cross.gif")

        # BINDINGS
        self._master.bind("<Right>", lambda _: Movement.moveSnake(self, 0, 1))
        self._master.bind("<Left>", lambda _: Movement.moveSnake(self, 0, -1))
        self._master.bind("<Down>", lambda _: Movement.moveSnake(self, 1, 0))
        self._master.bind("<Up>", lambda _: Movement.moveSnake(self, -1, 0))
        self._master.bind("<r>", lambda _: self.load_game())
        self._master.bind("<q>", lambda _: window.destroy())

        # LOADER GAME
        self.load_game()

    def load_game(self):
        """ Sætter spillet op """
        self._master.title(self._title)
        self.load_board()
        self.re_draw()
        self.boardTimer()

    def re_draw(self):
        """ Opdaterer boardet """
        self._c.delete()
        self.draw_board()

    def load_board(self):
        """ starter boardet """
        self.isGameOver = False
        self.snakeBoard = [
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 2, 3, 4, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        ]

        SnakeFood.placeFood(self)
        """ Finder hovedet og gemmer det"""
        self._headRow, self._headCol = Movement.findSnakeHead(self)
        self._snakeDRow = -1
        self._snakeDCol = 0

    def draw_board(self):
        """ Kalder draw_cells for hver celle """
        self.rows = len(self.snakeBoard)
        self.cols = len(self.snakeBoard[0])

        for self.row in range(self.rows):
            for self.col in range(self.cols):
                self.draw_cells(self.row, self.col, self.snakeBoard)
                # print(str(self.row) + " " + str(self.col))

    def draw_cells(self, row, col, snakeBoard):
        """ Tegner seperat cellerne ud fra snakeBoardet """
        self.margen = 5
        self.cellsize = 30
        self.x1 = self.margen + col * self.cellsize  # x1
        self.x2 = self.x1 + self.cellsize  # x2
        self.y1 = self.margen + row * self.cellsize  # y1
        self.y2 = self.y1 + self.cellsize  # y2

        self._c.create_rectangle(
            self.x1, self.y1, self.x2, self.y2, fill="white", outline="black"
        )

        if snakeBoard[row][col] > 0:
            self._c.create_oval(self.x1, self.y1, self.x2, self.y2, fill="blue")

        elif snakeBoard[row][col] < 0:
            self._c.create_oval(self.x1, self.y1, self.x2, self.y2, fill="red")

    def boardTimer(self):
        self.delay = 200
        print("Før " + str(self.isGameOver))
        if not self.isGameOver:
            print("efter " + str(self.isGameOver))
            Movement.moveSnake(self, self._snakeDRow, self._snakeDCol)
            print(self._snakeDRow, self._snakeDCol)
            self.re_draw()
        self._c.after(self.delay, self.boardTimer)

    def gameOver(self):
        """ Slutter spillet og viser spilleren antal point opnået """
        # self._master.MessageBox.showinfo("Game Over")
        print("gameover")
        self.isGameOver = True
        self._c.create_text(155, 155, text="Game Over!", font=("Helvetica", 32, "bold"))


if __name__ == "__main__":
    """ Kører fra starten af """
    window = tk.Tk()
    c = tk.Canvas(window, width=310, height=310)
    c.pack()
    game = SnakeGame(window, c)

    window.mainloop()
Reply
#2
I haven't had a proper look yet but noticed you have not made instances of Movement or SnakeFood and have not passed into them snakeBoard
Reply
#3
I've found that I didn't delete the board correctly before updating it, which made a ton of graphics layers above each other.
Reply
#4
hello,
couple of my observations:
Add a frame.
class MySnake(Frame):
    def __init__(self, parent= None):
        self.parent= parent
        Frame.__init__(self, self.parent)
        self.pack(expand=YES, fill=BOTH)
eliminate the move class and use the Canvas.move(object, x,y)
def move_snake(self, x,y): #x left or right y up or down
    while True:
        self.canvas.move(self.snake_head,x,y)
        .....

try the canvas.update() instead of deleting and redrawing
self.canvas.update()
time.sleep(0.04)
make snake food a function instead of a class
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020