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
相关产品推荐
相关产品推荐

