You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pygame开发贪吃蛇:蛇身随机重置为初始长度问题求助

问题原因

你的贪吃蛇偶尔变回初始长度,核心问题出在Snake类的update方法实现上:

  • 你使用self.body.append(self.head)将头部对象直接加入身体列表,随后用self.body.remove(self.head)移除。但list.remove()会移除第一个与头部值相等(位置、尺寸完全一致)的Rect对象,当蛇的身体某块位置与头部重合时(比如自撞、苹果生成在身体上导致生长后位置重叠),会误删正常的身体块,导致蛇长度骤减。
  • 这种基于对象引用的移动逻辑本身就不健壮,容易引发匹配错误。
解决方案

修改update方法,采用保存位置后依次更新的方式,彻底避免append和remove操作带来的误删问题;同时优化输入逻辑禁止蛇直接掉头,减少身体与头部位置重合的概率。

修改后的代码

snake.py

import pygame
 
class Snake:
    """A simple moveable snake"""
    def __init__(self, settings):
        self.settings = settings
        self.x = self.settings.BLOCK_SIZE
        self.y =self.settings.BLOCK_SIZE
        self.xdir = 1
        self.ydir = 0
        self.head = pygame.Rect(self.x, self.y, 
        self.settings.BLOCK_SIZE, self.settings.BLOCK_SIZE)
        self.body = [pygame.Rect(self.x-self.settings.BLOCK_SIZE,
        self.y, self.settings.BLOCK_SIZE, self.settings.BLOCK_SIZE)]
        self.collided = False
        self.excess_border = False
        
    def draw_snake(self, screen):
        """Draw a snake on the screen."""
        pygame.draw.rect(screen, (30, 180,15), self.head)
        for square in self.body:
            pygame.draw.rect(screen, (30, 180, 15), square)
 
    def update(self):
        """Make a snake move"""
        # 保存头部和所有身体块的当前位置
        all_positions = [(self.head.x, self.head.y)]
        for seg in self.body:
            all_positions.append((seg.x, seg.y))
        
        # 移动头部到新位置
        self.head.x += self.xdir * self.settings.BLOCK_SIZE
        self.head.y += self.ydir * self.settings.BLOCK_SIZE
        
        # 更新每个身体块的位置,使其移动到前一个块的位置
        for i in range(len(self.body)):
            self.body[i].x, self.body[i].y = all_positions[i]
        
    def change_direction(self, event):
        """React to an user's input."""
        # 禁止直接掉头,避免立即自撞
        if event.key == pygame.K_DOWN and self.ydir != -1:
            self.xdir = 0
            self.ydir = 1
        if event.key == pygame.K_UP and self.ydir != 1:
            self.xdir = 0
            self.ydir = -1
        if event.key == pygame.K_LEFT and self.xdir != 1:
            self.xdir = -1
            self.ydir = 0
        if event.key == pygame.K_RIGHT and self.xdir != -1:
            self.xdir = 1
            self.ydir = 0
                
    def grow(self):
        """Make the snake grow."""
        self.body.append(pygame.Rect(self.head.x, self.head.y,
        self.settings.BLOCK_SIZE, self.settings.BLOCK_SIZE))
        
    def eat(self, apple):
        """Make a snake eat."""
        if (self.head.x == apple.x) and (self.head.y == apple.y):
         self.grow()
         apple.create_apple()

main.py(调整调用顺序)

import sys
import random
import pygame
 
from apple import Apple
from settings import Settings
from snake import Snake
 
settings = Settings()
snake = Snake(settings)
apple = Apple(settings)
pygame.init()
screen = pygame.display.set_mode((settings.SW, settings.SH))
pygame.display.set_caption(settings.title)
clock = pygame.time.Clock()
 
 
def draw_grid():
    """Draw a gird on the screen."""
    for x in range(0, settings.SW, settings.BLOCK_SIZE):
        for y in range(0, settings.SH, settings.BLOCK_SIZE):
            rect = pygame.Rect(x, y, settings.BLOCK_SIZE, 
            settings.BLOCK_SIZE)
            pygame.draw.rect(screen, (255, 255, 255), rect, 1)
 
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            snake.change_direction(event)
    snake.update()
    snake.eat(apple)  # 移动后检查吃苹果,逻辑更合理
    screen.fill(settings.BLACK)
    draw_grid()
    apple.draw_apple(screen)
    snake.draw_snake(screen)
    pygame.display.update()
    clock.tick(10) 
额外优化(可选)

可以在Apple类的create_apple方法中添加检查,避免苹果生成在蛇的身体或头部上:

def create_apple(self):
    """Create a new apple not on snake body."""
    while True:
        self.x = (int(random.randint(0, self.settings.SW - self.settings.BLOCK_SIZE)/
        self.settings.BLOCK_SIZE) 
        * self.settings.BLOCK_SIZE)
        self.y =  (int(random.randint(0, self.settings.SH - self.settings.BLOCK_SIZE)
        / self.settings.BLOCK_SIZE) 
        * self.settings.BLOCK_SIZE)
        self.apple = pygame.Rect(self.x, self.y, 
        self.settings.BLOCK_SIZE,
        self.settings.BLOCK_SIZE)
        # 检查苹果是否在蛇身上
        on_snake = False
        if self.x == snake.head.x and self.y == snake.head.y:
            on_snake = True
        for seg in snake.body:
            if self.x == seg.x and self.y == seg.y:
                on_snake = True
                break
        if not on_snake:
            break

内容的提问来源于stack exchange,提问作者Otusscops

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 20:45:53