Python tkinter snake game drawing lag

2019-08-13 03:22发布

#example snake snake = [[1, 2], [1, 3], [2, 3]]
def draw():
canvas.delete('all')
for segment in snake:
    y = segment[0] * 10
    x = segment[1] * 10
    canvas.create_rectangle(x, y, x + 10, y + 10, fill="red")
    canvas.update()

I have created a simple snake game in python using tkinter but the movement slows down rapidly when the snake array contains 30+ rectangles, so i was wondering is there a better way to do the drawing of the objects so it works faster instead of constantly calling this draw function?

Another possible issue is the inefficiency of the move functions:

def move_right(event):

global left, right, up, down
if right != True:
    left, right, up, down = False, True, False, False
    while right == True:
        if snake[0][1] >= snake[1][1]:
            for x in range(len(snake) - 1, 0, -1):
                snake[x] = snake[x - 1]
            snake[0] = [snake[0][0], snake[0][1] + 1]
            draw()
        time.sleep(0.05)

This my first actual game so don't kill me :(.

1条回答
祖国的老花朵
2楼-- · 2019-08-13 04:00

You don't have to delete all rectangles from canvas. You have to remove only last rectangle and add new head rectangle.

To add new x,y in snake list you don't have to move all elements - you need only snake.insert(0, [new_x, new_y])

You can use root.after instead of while loop and sleep

Example - without checking collisions

import tkinter as tk

# === constants ===

BLOCK_SIZE = 10
TIME = 50

# === functions ===

# create all rectangles on canvas
def create_snake(canvas, snake):
    snake_rect = []

    for x, y in snake:
        x1 = x * BLOCK_SIZE
        y1 = y * BLOCK_SIZE
        x2 = x1 + BLOCK_SIZE
        y2 = y1 + BLOCK_SIZE
        rect = canvas.create_rectangle(x1,y1,x2,y2, fill='red')
        snake_rect.append(rect)

    return snake_rect

# move snake - add first rectangle and remove last one
def move(canvas, snake, snake_rect, remove_last=True):

    # get head
    x, y = snake[0]

    # new head position
    if direction == 'up':
        y = y-1
    elif direction == 'down':
        y = y+1
    elif direction == 'left':
        x = x-1
    elif direction == 'right':
        x = x+1

    # add first - new head
    snake.insert(0, [x, y])

    x1 = x * BLOCK_SIZE
    y1 = y * BLOCK_SIZE
    x2 = x1 + BLOCK_SIZE
    y2 = y1 + BLOCK_SIZE
    rect = canvas.create_rectangle(x1,y1,x2,y2, fill='red')

    snake_rect.insert(0, rect)

    # remove last - tail (if snake doesn't eat 'apple')
    if remove_last:
        del snake[-1]

        canvas.delete(snake_rect[-1])
        del snake_rect[-1]

    # call `move` function again after TIME miliseconds
    root.after(TIME, move, canvas, snake, snake_rect)

# change direction                
def change_direction(new_direction):
    global direction

    #print(new_direction)

    if new_direction == 'left':
        if direction != 'right':
            direction = new_direction
    elif new_direction == 'right':
        if direction != 'left':
            direction = new_direction
    elif new_direction == 'up':
        if direction != 'down':
            direction = new_direction
    elif new_direction == 'down':
        if direction != 'up':
            direction = new_direction

# === main ===

direction = 'up'

# ---

root = tk.Tk()

canvas = tk.Canvas(root)
canvas.pack()

# create long (curved) snake
snake = [[x,25] for x in range(10,35)] + [[35, y] for y in range(25, 1, -1)] + [[x, 1] for x in range(35, 1, -1)]
snake_rect = create_snake(canvas, snake)

# call `move` function after TIME miliseconds
root.after(TIME, move, canvas, snake, snake_rect)

# bind arrows to change snake direction
root.bind('<Left>', lambda event:change_direction('left'))
root.bind('<Right>', lambda event:change_direction('right'))
root.bind('<Up>', lambda event:change_direction('up'))
root.bind('<Down>', lambda event:change_direction('down'))

# start program
root.mainloop()
查看更多
登录 后发表回答