1

Everything works properly after compiling this code up until the point where I try to extend my snake; however, when I do, the snake detaches from the body and the extend function fails, as shown in the picture below. how can I attach the new segment to body so that it updates score and body of snake will increase its segment as well Snake body detach with body

  from turtle import Screen
    from food import Food
    from snakee import Snake
    from score import Score
    
    screen=Screen()
    screen.setup(600,600)
    screen.bgcolor("black")
    screen.title("Snake game")
    screen.tracer(0)
    
    snake=Snake()
    food=Food()
    score=Score()
    
    screen.listen()
    screen.onkey(snake.up,"Up")
    screen.onkey(snake.down,"Down")
    screen.onkey(snake.right,"Right")
    screen.onkey(snake.left,"Left")
    
    game_is_on = True
    while game_is_on:
        screen.update()
        time.sleep(0.1)
        snake.move()
    
        if snake.head.distance(food) < 15:
            food.refresh()
            snake.extend()
            score.increse_score()
        if snake.head.xcor()>280 or snake.head.xcor() < -280 or snake.head.ycor()>280 or snake.head.ycor()<-280:
            game_is_on=False
            score.over()
    
    
    
    
    
    screen.exitonclick()

Score.py

from turtle import Turtle
class Score(Turtle):
    def __init__(self):
        super().__init__()
        self.score = 0
        self.hideturtle()
        self.color("white")
        self.penup()
        self.goto(0,250)
        self.update()

    def update(self):
        self.write(f"score:{self.score}", align="center",font=("Ariel",24,"normal"))

    def over(self):
        self.goto(0,0)
        self.write(f"GAME OVER", align="center",font=("Ariel",24,"normal"))

    def increse_score(self):
        self.score+=1
        self.clear()
        self.update()

Snake.py

from turtle import Turtle,Screen
screen=Screen()
START_POSI = [(0, 0), (-20, 0), (-40, 0)]
MOVE_DIS=20
UP=90
DOWN=270
LEFT=180
RIGHT=0
class Snake:
    def __init__(self):
        self.segment=[]
        self.create_snake()
        self.head=self.segment[0]


    def create_snake(self):
        for position in START_POSI:
            self.add_segment(position)

    def add_segment(self, position):
        new_segment = Turtle("square")
        new_segment.color("white")
        new_segment.penup()
        new_segment.goto(position)
        self.segment.append(new_segment)

    def extend(self):
        self.add_segment(self.segment[-1].position())
        
    def move(self):
        for seg in range(len(START_POSI) - 1, 0, -1):
            new_x = self.segment[seg - 1].xcor()
            new_y = self.segment[seg - 1].ycor()
            self.segment[seg].goto(new_x, new_y)
        self.segment[0].forward(MOVE_DIS)

    def up(self):
        if self.head.heading()!=DOWN:
            self.head.setheading(UP)

    def down(self):
        if self.head.heading()!=UP:
            self.head.setheading(DOWN)

    def left(self):
        if self.head.heading()!=RIGHT:
            self.head.setheading(LEFT)

    def right(self):
        if self.head.heading()!=LEFT:
            self.head.setheading(RIGHT)

food.py

from turtle import Turtle
import random
class Food(Turtle):

    def __init__(self):
        super().__init__()
        self.penup()
        self.shape("circle")
        self.shapesize(0.5,0.5)
        self.color("red")
        self.refresh()
    def refresh(self):
        xcord = random.randint(-280,280)
        ycord = random.randint(-280, 280)
        self.goto(xcord,ycord)
Abhi
  • 11
  • 1

1 Answers1

0

You're only looping as far as len(START_POSI) but this isn't the entire tail after extension. Try len(self.segment):

    def move(self):
        #                    v----------- here's the fix
        for seg in range(len(self.segment) - 1, 0, -1):
            new_x = self.segment[seg - 1].xcor()

As an aside, I'd call turtle.update() and time.sleep() (in that order) at the very bottom of the update loop, not at the top. The per-frame flow is update state/positions -> redraw -> register a tick/repaint/update with the turtle API -> sleep for the next frame. I ususally use ontimer rather than while and sleep but I'm not sure that it's necessarily much more reliable (that's a pending research project).

Also, I'm not a fan of subclassing Turtle. Although this program appears OK at a glance, the practice can lead to a number of issues down the line so I'd switch to composition rather than inheritance. Only subclass your own interfaces or APIs which are explicitly designed for it.

ggorlen
  • 44,755
  • 7
  • 76
  • 106