@grzegorz

Баг со змейкой на Python + tkinter, как решить проблему с добавлением сегмента?

Здравствуйте.
Написал тривиальную змейку на Python, вроде все ок, кроме такого бага:

Когда "голова" змеи кушает первое яблоко, добавляеться новый сегмент, но его координаты соответствуют координатам "головы", в итоге я получаю, что есть два сегмента с одними и теме же координатами. При добавлении следующих сегментов все ок, не могу понять в чем проблема.

Прикрепляю ниже полный код.

from tkinter import *
    import random,shelve
    # import shelve for saving highscore

    class Game:
    # BASIC VARIABLES
    width = 700
    height = 500
    apple_size = 20
    field_color = 'black'
    score_1 = 0
    highscore = shelve.open('highscore')['highscore']
    segments = []

    # VARIABLES  AND FUNCTIONS FOR CHANGING DIRECTION
    move_left = -apple_size, 0
    move_right = apple_size, 0
    move_top = 0, -apple_size
    move_down = 0, apple_size
    direction = move_right

    def __init__(self):
        #PLAY
        self.root = Tk()
        self.root.title('Snake')
        self.field = Canvas(self.root, width=self.width, height=self.height, bg=self.field_color)
        self.field.pack()
        self.field.focus_set()
        self.score = Label(self.root, text='Your score: {}. Best score: {}'.format(self.score_1, self.highscore))
        self.score.pack(side='bottom', anchor='w')

    def change_top(self):
        self.direction = self.move_top

    def change_down(self):
        self.direction = self.move_down

    def change_left(self):
        self.direction = self.move_left

    def change_right(self):
        self.direction = self.move_right

    def create_segment(self):
        b =  self.field.coords(self.segments[0])[:]
        if self.direction == self.move_right:
            for x in (0, 2):
                b[x]-=20
        elif self.direction == self.move_down:
            for x in(1,3):
                b[x]-=20
        elif self.direction == self.move_top:
            for x in(1,3):
                b[x]+=20
        else:
            for x in (0, 2):
                b[x]+=20
        new_segment=self.field.create_rectangle(*b, fill='white')
        self.segments.insert(0,new_segment)

    def game_over(self):
        if self.score_1 > self.highscore:
            shelve.open('highscore')['highscore'] = self.score_1
        self.field.create_text(self.width / 2, self.height / 2, text="GAME OVER!", font="Helvetica 20", fill="white")
        self.field.after(1500, lambda: self.root.quit())

    def create_apple(self):
        self.posx = random.randint(1,self.width/self.apple_size-1)*self.apple_size
        self.posy = random.randint(1,self.height/self.apple_size-1)*self.apple_size
        for x in range(len(self.segments)):
            if [self.posx,self.posy,self.posx+self.apple_size,self.posy+self.apple_size] ==\
                self.field.coords(self.segments[x]):
                self.create_apple()
        self.apple = self.field.create_rectangle(self.posx,self.posy,self.posx+self.apple_size,self.posy+self.apple_size,fill = 'red')

    def create_snake(self):
        self.snake = self.field.create_rectangle(20,20,40,40,fill = 'blue')
        self.segments.append(self.snake)
        def start(): #MOVING
            for x in range(len(self.segments)):
                self.a = self.field.coords(self.segments[x-1])
                print(len(self.segments))
                self.a[0]+=self.direction[0]
                self.a[1]+=self.direction[1]
                self.a[2]=self.a[0]+self.apple_size
                self.a[3]=self.a[1]+self.apple_size
                if x == 0:
                    self.field.coords(self.segments[x-1], self.a )
                else:
                    self.field.coords(self.segments[x-1],*self.field.coords(self.segments[x]))
            if self.field.coords(self.segments[-1]) == self.field.coords(self.apple): # IF SNAKE'S EATEN AN APPLE
                self.score_1+=1
                self.score.config(text = 'Your score: {}. Best score: {}'.format(self.score_1,self.highscore))
                self.field.delete(self.apple)
                self.create_apple()
                self.create_segment()
            if self.field.coords(self.segments[-1])[0] == 0 or self.field.coords(self.segments[-1])[0] == self.width or\
            self.field.coords(self.segments[-1])[1] == self.height or self.field.coords(self.segments[-1])[1] == 0: # IF SNAKE'S RUN INTO WALL
                self.game_over()
            for x in range(2, len(self.segments)): # SELF-EATING
                if self.field.coords(self.segments[0]) == self.field.coords(self.segments[x]):
                    self.game_over()
            self.field.after(200,start)
        return  start()

    def lets_play(self): #START
        self.create_apple()
        self.create_snake()
        self.root.mainloop()

    if __name__ == '__main__':
    game = Game()
    game.field.bind('<Up>', lambda x: game.change_top())
    game.field.bind('<Down>', lambda x: game.change_down())
    game.field.bind('<Left>', lambda x: game.change_left())
    game.field.bind('<Right>', lambda x: game.change_right())
    game.lets_play()
  • Вопрос задан
  • 582 просмотра
Пригласить эксперта
Ответы на вопрос 1
@isisTance
Python, C#, C++, HTML, CSS, backend developer.
Попробуйте создать переменную с количеством сегментов, а также переменную с координатами головы. Потом легкие вычисления:
newBlockX = headX + blocksCount * 20
newBlockY = headY + blocksCount * 20

Вроде у Вас высота и ширина сегмента = 20? Если нет - то вместо 20 поставьте правильное значение. Должно работать. Сам, когда делал змейку делал так.
З.Ы. По-моему змейку делать на ООП не надо, только сегменты. Не более...
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы