我正在用 Python 开发著名的贪吃蛇游戏,偶然发现了一个小故障,蛇在吃食物时会开始做一些事情。

蛇在整个游戏过程中应保持恒定速度,并且各节之间的距离应相等。但实际情况是,每次蛇吃食物时,它的速度都会加快,各节之间的距离就会开始变远。

如果有人能帮忙的话,这里是部分代码。

import random
import time
from turtle import Screen, Turtle


MOVE_DISTANCE = 10
POSITIONS = [(0, 0), (0, -20), (0, -40)]
class Snake:
    def __init__(self):
        self.segments = []
        self.create_snake()
        self.head = self.segments[0] 

    def create_snake(self):
        for position in POSITIONS:
            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.segments.append(new_segment) 

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

    def grow(self):
        self.add_segment(self.segments[-1].position()) 

    def up(self):
        if self.head.heading() != 270:
            self.head.setheading(90) 

    def down(self):
        if self.head.heading() != 90:
            self.head.setheading(270) 

    def left(self):
        if self.head.heading() != 0:
            self.head.setheading(180) 

    def right(self):
        if self.head.heading() != 180:
            self.head.setheading(0)

class Food(Turtle):
    def __init__(self):
        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_food() 

    def refresh_food(self):
        rand_x_cor = random.randint(-480, 480)
        rand_y_cor = random.randint(-260, 260)
        self.goto(rand_x_cor, rand_y_cor)

my_screen = Screen()
my_screen.setup(width=1000, height=600)
my_screen.bgcolor("black")
my_screen.title("My Snake Game")
my_screen.tracer(0)

my_snake = Snake()

food = Food()

my_screen.listen()
my_screen.onkey(my_snake.up, "Up")
my_screen.onkey(my_snake.down, "Down")
my_screen.onkey(my_snake.left, "Left")
my_screen.onkey(my_snake.right, "Right")

game_over = False 
while not game_over:
    my_screen.update()
    time.sleep(0.1)
    my_snake.move()

    # Detect collision with the food
    if my_snake.head.distance(food) < 15:
        food.refresh_food()
        my_snake.grow()

    # Detect collision with wall
    if my_snake.head.xcor() < -480 or my_snake.head.xcor() > 480 or my_snake.head.ycor() < -280 or my_snake.head.ycor() > 280:
        game_over = True

    # Detect collision with tail
    for segment in my_snake.segments[2:]:
        if my_snake.head.distance(segment) < 10:
            game_over = True 

我尝试减少蛇头的移动距离
self.head.forward(MOVE_DISTANCE) # Moving distance of head

我也尝试了不同的方法来移动蛇,但是也没有效果。

2

  • 我建议定义所有变量,以便更容易运行和重现问题。谢谢。/update()应该sleep()是循环中的最后一行(或者更好的是,)。


    – 


  • 我不认为这代表一个。ggorlen很棒,但事实上它只涉及代码的一小部分,这表明应该事先进行更多的调试。


    – 


最佳答案
1

move方法看起来不正确:

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

我认为你不需要移动每个尾部片段的头部。相反,你应该先移动头部一次,然后移动所有尾部片段一次:

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

这是一个经过一些调整的可运行示例:

from random import randint
from turtle import Screen, Turtle

GRID_SIZE = 20


class Snake:
    POSITIONS = (0, 0), (GRID_SIZE, 0), (GRID_SIZE * 2, 0)

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

    def create_snake(self):
        for position in Snake.POSITIONS:
            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.segments.append(new_segment)

    def move(self):
        self.head.forward(GRID_SIZE)

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

    def grow(self):
        self.add_segment(self.segments[-1].position())

    def up(self):
        if self.head.heading() != 270:
            self.head.setheading(90)

    def down(self):
        if self.head.heading() != 90:
            self.head.setheading(270)

    def left(self):
        if self.head.heading() != 0:
            self.head.setheading(180)

    def right(self):
        if self.head.heading() != 180:
            self.head.setheading(0)

    def eats(self, food):
        return self.head.distance(food.position()) < GRID_SIZE / 2

    def collides_with_wall(self):
        return (
            self.head.xcor() < -w
            or self.head.xcor() > w
            or self.head.ycor() < -h
            or self.head.ycor() > h
        )

    def collides_with_itself(self):
        for segment in self.segments[3:]:
            if self.head.distance(segment) < GRID_SIZE:
                return True

        return False


class Food:
    def __init__(self):
        self.pen = pen = Turtle()
        pen.shape("circle")
        pen.penup()
        pen.shapesize(stretch_len=0.5, stretch_wid=0.5)
        pen.color("red")
        pen.speed("fastest")
        self.reposition()

    def reposition(self):
        self.pen.goto(
            randint(-w, w) // GRID_SIZE * GRID_SIZE,
            randint(-h, h) // GRID_SIZE * GRID_SIZE,
        )

    def position(self):
        return self.pen.pos()


def tick():
    snake.move()

    if snake.eats(food):
        food.reposition()
        snake.grow()

    if snake.collides_with_wall() or snake.collides_with_itself():
        screen.update()
        return

    screen.update()
    screen.ontimer(tick, fps)


screen = Screen()
screen.setup(width=1000, height=600)
fps = 1000 // 10
w = screen.window_width() / 2 - GRID_SIZE
h = screen.window_height() / 2 - GRID_SIZE
screen.bgcolor("black")
screen.title("My Snake Game")
screen.tracer(0)
snake = Snake()
food = Food()
screen.listen()
screen.onkey(snake.up, "Up")
screen.onkey(snake.down, "Down")
screen.onkey(snake.left, "Left")
screen.onkey(snake.right, "Right")
tick()
screen.exitonclick()

还有改进的空间,但总体来说应该更容易维护。