Почему моя игра-змея в Python останавливается с помощью объекта «float», который не подлежит подписке. Ошибка?

Я работаю над игрой Python Snake, используя модуль черепахи. У меня есть четыре файла: main.py, food.py, scoreboard.py и snake.py.

Вот мой main.py код:

from turtle import Screen
from snake import Snake
from food import Food
from scoreboard import Scoreboard
import time

screen = Screen()
screen.setup(600,600)
screen.title("Snake Game")
screen.bgcolor("black")
screen.tracer(0) # Turning the animation off

snake = Snake()
food = Food()
scoreboard = Scoreboard()


screen.listen()

screen.onkeypress(fun=snake.up,key = "Up")
screen.onkeypress(fun=snake.down,key = "Down")
screen.onkeypress(fun=snake.left,key = "Left")
screen.onkeypress(fun=snake.right,key = "Right")
 

is_game_on = True
score = 0
while is_game_on:
    screen.update()
    time.sleep(0.1)
    snake.move()

    # Detect collision with food

    if snake.head.distance(food) < 15:
        food.refresh()
        scoreboard.score_update()
        snake.extend()

    # Detect collision with wall

    if snake.head.xcor() > 280 or snake.head.xcor() < -280 or\
          snake.head.ycor() > 280 or snake.head.ycor()<-280:
        scoreboard.game_over()
        is_game_on = False


screen.exitonclick()

Вот мой food.py код:

import random
from turtle import Turtle



class Food(Turtle):


    def __init__(self) -> None:
        super().__init__()
        self.shape("circle")
        self.penup()
        self.shapesize(stretch_len=0.5,stretch_wid=0.5)
        self.color("red")
        self.speed("fastest")
        self.refresh()

    def refresh(self):
        random_coordinates = ( random.randint(-280,280), random.randint(-280,280) )
        self.goto(random_coordinates)
        

Вот мой scoreboard.py код:

from turtle import Turtle
ALIGNMENT = "center"
FONT_NAME = "Courier"
FONT_SIZE = 17
FONT_TYPE = "normal"

   
class Scoreboard(Turtle):
    score = 0

    def __init__(self):
        super().__init__()
        self.color("yellow")
        self.hideturtle()
        self.penup()
        self.teleport(0,275)
        self.write(arg = "score = 0",move=False,align=ALIGNMENT,font=(FONT_NAME, FONT_SIZE, FONT_TYPE))
    
    def score_update(self,):
        self.score += 1
        self.clear()
        self.write(arg=f"score = {self.score}",move=False,align=ALIGNMENT,font=(FONT_NAME, FONT_SIZE, FONT_TYPE))
    
    def game_over(self):
        
        self.home()
        self.write(arg=f"GAME OVER",move=False,align=ALIGNMENT,font=(FONT_NAME, FONT_SIZE, FONT_TYPE))
      

Вот мой snake.py код:

from turtle import Turtle, Screen

MOVE_DISTANCE = 20
UP = 90
DOWN = 270
LEFT = 180
RIGHT = 0

class Snake:

    def __init__(self) -> None:
        self.segments = []
        self.create_snake()
        self.head = self.segments[0]
        

    def create_snake(self):
        self.x_cor = 0
        for i in range(3):
            self.add_segment(self.x_cor)
            self.x_cor -= 20

    def add_segment(self,position):
        segment = Turtle("square")
        segment.color("white")
        segment.penup()
        segment.speed("slowest")
        segment.teleport(x=position,y=0)
        self.segments.append(segment)
        
    def extend(self):
        # print(type(self.segments[-1]))
        self.add_segment((self.segments)[-1].pos())

    def move(self):

        for seq_num in range(len(self.segments) -1, 0 ,-1):
            new_x = self.segments[seq_num - 1].xcor()
            new_y = self.segments[seq_num - 1].ycor()
            self.segments[seq_num].goto(new_x, new_y)     
        self.head.forward(MOVE_DISTANCE)


    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)


Всякий раз, когда змея ест пищу, программа останавливается и выдает сообщение об ошибке. Я думаю, проблема в методе add_segment.

Traceback (most recent call last):
  File "/home/xenon_54/Snake_Game/main.py", line 29, in <module>
    screen.update()
  File "/usr/lib64/python3.12/turtle.py", line 1296, in update
    t._drawturtle()
  File "/usr/lib64/python3.12/turtle.py", line 3080, in _drawturtle
    shape = self._polytrafo(self._getshapepoly(tshape))
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/turtle.py", line 3033, in _polytrafo
    return [(p0+(e1*x+e0*y)/screen.xscale, p1+(-e0*x+e1*y)/screen.yscale)
             ~~^~~~~~~~~~~~~~~~~~~~~~~~~~
  File "/usr/lib64/python3.12/turtle.py", line 248, in __add__
    return Vec2D(self[0]+other[0], self[1]+other[1])
                         ~~~~~^^^
TypeError: 'float' object is not subscriptable

В функции extend вы передаете кортеж в add_segment, но эта функция ожидает число: Исправлено: self.add_segment(self.segments[-1].pos()[0])

001 24.07.2024 15:18

@001 Не приведет ли это к противоположной ошибке? Эта ошибка возникает из-за числа, в котором ожидается кортеж.

Barmar 24.07.2024 15:24

Но я согласен, x=position наверное должно быть x=position[0]

Barmar 24.07.2024 15:25

@Barmar Я не слишком знаком с внутренней работой графики Turtle, но да, кажется, все наоборот.

001 24.07.2024 15:27
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
5
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я использовал goto вместо teleport

Также в функции create_snake метод goto ожидает кортеж (x, y) для позиционирования. Поэтому self.x_cor необходимо было передать как кортеж (self.x_cor, 0). Вот код snake.py, который сработал у меня:

from turtle import Turtle

MOVE_DISTANCE = 20
UP = 90
DOWN = 270
LEFT = 180
RIGHT = 0

class Snake:
    def __init__(self) -> None:
        self.segments = []
        self.create_snake()
        self.head = self.segments[0]

    def create_snake(self):
        self.x_cor = 0
        for _ in range(3):
            self.add_segment((self.x_cor, 0))
            self.x_cor -= 20

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

    def extend(self):
        self.add_segment((self.segments)[-1].pos())

    def move(self):
        for seq_num in range(len(self.segments) - 1, 0, -1):
            new_x = self.segments[seq_num - 1].xcor()
            new_y = self.segments[seq_num - 1].ycor()
            self.segments[seq_num].goto(new_x, new_y)
        self.head.forward(MOVE_DISTANCE)

    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)

Другие вопросы по теме