Потеря аргументов функции Canvas.coords
При первом запуске программы всё работает хорошо, но при попытке перезапуска происходит потеря аргументов функции .coords объекта canv класcа Canvas.
Чем это может быть вызвано и как это можно исправить или обойти?
Код, "перезапускающий" программу:
class Snake(object):
#****
def reset_snake(self):
for segment in self.segments:
canv.delete(segment.instance)
segments = [Segment(SEG_SIZE,SEG_SIZE),
Segment(SEG_SIZE*2,SEG_SIZE),
Segment(SEG_SIZE*3,SEG_SIZE)]
s = Snake(segments)
def new_game():
"""Очищает игровое поле, обнуляет счёт и перезапускает игру"""
#В разработке
#Должна вызываться кнопкой, размещённой на игровом поле
global IN_GAME
global apples
apples = 0
IN_GAME = True
s.reset_snake()
canv.delete(BLOCK)
create_block()
main()
Полный код:
from tkinter import *
import random
#Глобальные переменные:
WIDTH = 860
HEIGHT = 640
SEG_SIZE = 20
IN_GAME = True
apples = 0
#Вспомогательные функции:
def create_block():
"""создаёт блок 'еды' в случайной позиции на карте"""
global BLOCK
pos_x = SEG_SIZE * (random.randint(1, (WIDTH-SEG_SIZE)/SEG_SIZE))
pos_y = SEG_SIZE * (random.randint(1, (HEIGHT-SEG_SIZE)/SEG_SIZE))
#Блок-кружок красного цвета
BLOCK = canv.create_oval(pos_x, pos_y,pos_x + SEG_SIZE,
pos_y + SEG_SIZE, fill="red")
def main():
global IN_GAME
global apples
if IN_GAME:
#Двигаем змейку
s.move()
#Определяем координаты головы:
head_coords = canv.coords(s.segments[-1].instance)
x1, y1, x2, y2 = head_coords
#Столкновение с границами экрана:
if x1 < 0 or x2 > WIDTH or y1 < 0 or y2 > HEIGHT:
IN_GAME = False
#Поедание яблок:
elif head_coords == canv.coords(BLOCK):
s.add_segment()
canv.delete(BLOCK)
create_block()
apples = apples + 1
#Столкновение с блоком змеи:
else:
for index in range(len(s.segments)-1):
if canv.coords(s.segments[index].instance) == head_coords:
IN_GAME = False
#Движение змеи,чем меньше цифра-тем выше скорость:
root.after(110,main)
#Если не в игре, выводим сообщение о проигрыше:
else:
t = "ТЫ ПРОИГРАЛ!\nТвой счёт: " + str(apples)
canv.create_text(WIDTH/2, HEIGHT/2,
text=t,
font="Arial 20",
fill="#ff0000")
a = int(input("Начать новую игру? 0/1 >> "))
if a == 1:
new_game()
def new_game():
"""Очищает игровое поле, обнуляет счёт и перезапускает игру"""
#В разработке
#Должна вызываться кнопкой, размещённой на игровом поле
global IN_GAME
global apples
apples = 0
IN_GAME = True
s.reset_snake()
canv.delete(BLOCK)
create_block()
main()
class Segment(object):
def __init__(self, x, y):
self.instance = canv.create_rectangle(x, y,
x+SEG_SIZE, y+SEG_SIZE, fill='white')
class Snake(object):
def __init__(self, segments):
self.segments = segments
#Список доступных направлений движения:
self.mapping = {"Down": (0,1),"Up": (0,-1),
"Left": (-1,0),"Right": (1,0)}
"""Не допускать разворота змейки на 180 градусов!!!"""
#Изначально змейка движется вправо:
self.vector = self.mapping["Right"]
def move(self):
"""Двигает змейку в заданном направлении"""
#Перебираем все сегменты, кроме первого:
for index in range(len(self.segments)-1):
segment = self.segments[index].instance
x1, y1, x2, y2 = canv.coords(self.segments[index+1].instance)
#Задаём каждому сегменту позицию сегмента, стоящего следующим:
canv.coords(segment, x1, y1, x2, y2)
#Получаем координаты сегмента перед 'головой':
x1, y1, x2, y2 = canv.coords(self.segments[-2].instance)
#Помещаем голову в направлении вектора движения:
canv.coords(self.segments[-1].instance,
x1+self.vector[0]*SEG_SIZE,
y1+self.vector[1]*SEG_SIZE,
x2+self.vector[0]*SEG_SIZE,
y2+self.vector[1]*SEG_SIZE)
def change_direction(self, event):
"""Изменяет направление движения змейки"""
#'event' передаст символ нажатой клавиши.
#Если эта клавиша в списке доступных направлений,
#изменяем направление:
if event.keysym in self.mapping:
self.vector = self.mapping[event.keysym]
def add_segment(self):
"""Добавляет сегмент змейки"""
#Определяем последний сегмент
last_seg = canv.coords(self.segments[0].instance)
#Определяем координаты для следующиего сегмента:
x = last_seg[2] - SEG_SIZE
y = last_seg[3] - SEG_SIZE
#Добавляем ещё один сегмент в заданных координатах:
self.segments.insert(0, Segment(x,y))
def reset_snake(self):
for segment in self.segments:
canv.delete(segment.instance)
segments = [Segment(SEG_SIZE,SEG_SIZE),
Segment(SEG_SIZE*2,SEG_SIZE),
Segment(SEG_SIZE*3,SEG_SIZE)]
#Сама змейка:
s = Snake(segments)
root = Tk()
root.title("Змейка v 0.1.2")
#Игровое поле:
canv = Canvas(root,width=WIDTH, height=HEIGHT, bg='#005500')
canv.grid()
canv.focus_set()
#Создаём набор сегментов:
segments = [Segment(SEG_SIZE,SEG_SIZE),
Segment(SEG_SIZE*2,SEG_SIZE),
Segment(SEG_SIZE*3,SEG_SIZE)]
#Сама змейка:
s = Snake(segments)
#Реагируем на нажатие клавиш:
canv.bind("<KeyPress>", s.change_direction)
create_block()
main()
root.mainloop()
Полный текст ошибки:
Начать новую игру? 0/1 >> 1
Exception in Tkinter callback
Traceback (most recent call last):
File "H:\Программирование\lib\tkinter\__init__.py", line 1921, in __call__
return self.func(*args)
File "H:\Программирование\lib\tkinter\__init__.py", line 839, in callit
func(*args)
File "H:\Проекты_питон\Змейка\Snake1.1.py", line 58, in main
new_game()
File "H:\Проекты_питон\Змейка\Snake1.1.py", line 75, in new_game
main()
File "H:\Проекты_питон\Змейка\Snake1.1.py", line 27, in main
s.move()
File "H:\Проекты_питон\Змейка\Snake1.1.py", line 100, in move
x1, y1, x2, y2 = canv.coords(self.segments[index+1].instance)
ValueError: not enough values to unpack (expected 4, got 0)