#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 :(.
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()