Pygame贪吃蛇游戏绘制食物时触发AttributeError问题求助
先直接解决你遇到的AttributeError:
在第134行,你写了:
pygame.draw.rect(window.pygame.Color("RED"), pygame.Rect(int(foodpos[0]), int(foodpos[1]), 10, 10))
这里的问题是把参数顺序搞混了,还错误地在window后面追加了.pygame.Color。pygame.draw.rect的正确参数顺序是:绘制目标Surface(也就是你的window)、颜色、矩形对象。所以正确写法应该是:
pygame.draw.rect(window, pygame.Color("RED"), pygame.Rect(int(foodpos[0]), int(foodpos[1]), 10, 10))
你之前的写法把颜色放在了第一个参数的位置,还试图从window这个Surface对象里获取pygame属性,这就是报错'pygame.Surface' object has no attribute 'pygame'的核心原因。
接下来,你的代码里还有不少其他bug,不修复的话游戏还是无法正常运行,我逐一帮你指出并修正:
1. Snake类方法定义与逻辑错误
(1) change_direction_to方法命名冲突
你在__init__里定义了self.change_direction_to = self.direction,后面又定义了同名的方法,这会导致方法被覆盖。把__init__里的那行删掉,保留方法名change_direction_to,同时游戏主循环里的调用要改成对应的名字(你现在写的是snake.change_dir_to,要改成snake.change_direction_to)。
(2) move方法方向逻辑错误
你的move方法里,UP和DOWN方向修改的是self.position[0](x坐标),这会导致蛇上下移动时变成左右走,正确的应该是修改self.position[1](y坐标):
def move(self): if self.direction == "RIGHT": self.position[0] += 10 if self.direction == "LEFT": self.position[0] -= 10 if self.direction == "UP": self.position[1] -= 10 # 这里改成position[1] if self.direction == "DOWN": self.position[1] += 10 # 这里改成position[1]
(3) body_insert方法语法错误
这个方法的定义完全不对,参数应该是self,而且逻辑要调整:它应该在蛇移动后插入新的头部,吃到食物就不删除尾部,没吃到就删除尾部。正确的写法应该是:
def body_insert(self): # 把新头部插入身体列表开头 self.body.insert(0, list(self.position)) if self.position == foodpos: return 1 # 吃到食物,返回1表示加分 else: self.body.pop() # 没吃到,删除尾部 return 0
另外,你之前的写法里参数写了0,这是完全错误的,类方法第一个参数必须是self。
(4) check_collision方法逻辑错误
- 判断撞墙时,
self.position < 0是错误的,应该分别判断x和y坐标是否超出范围; - 检查撞自身的代码缩进错误,它应该是
check_collision方法里的一部分,而不是类的顶级代码。
修正后的check_collision:
def check_collision(self): # 检查撞墙(对应700x600窗口,蛇块10px) if self.position[0] > 690 or self.position[0] < 0: return 1 if self.position[1] > 590 or self.position[1] < 0: return 1 # 检查撞自身 for body_part in self.body[1:]: if self.position == body_part: return 1 return 0
2. FoodSpawner类错误
(1) 食物位置初始化错误
你初始化self.position时用了逗号,变成了元组([x], [y]),这会导致后面取foodpos[0]和foodpos[1]时得到的是列表,而不是数值。正确的写法应该是:
def __init__(self): self.position = [random.randrange(1, 70) * 10, random.randrange(1, 60) * 10] # 对应700x600窗口 self.is_food_on_screen = True
spawn_food方法里也要改成同样的写法:
def spawn_food(self): if not self.is_food_on_screen: self.position = [random.randrange(1, 70) * 10, random.randrange(1, 60) * 10] self.is_food_on_screen = True return self.position
(2) set_food_on_screen方法拼写错误
你写的是self.is_food_on_sceen = b,少了一个r,应该是self.is_food_on_screen = b。
3. 游戏主循环错误
(1) 方向控制重复错误
你在键盘事件处理里,多次写了event.key == pygame.K_RIGHT,导致UP和DOWN方向永远触发不了,正确的应该是:
elif event.type == pygame.KEYDOWN: if event.key == pygame.K_RIGHT: snake.change_direction_to("RIGHT") elif event.key == pygame.K_LEFT: snake.change_direction_to("LEFT") elif event.key == pygame.K_UP: snake.change_direction_to("UP") elif event.key == pygame.K_DOWN: snake.change_direction_to("DOWN")
用elif而不是多个if,避免多个方向同时触发。
(2) snake.move()调用错误
你写的是if snake.move(foodpos) == 1:,但move方法不需要参数,而且判断是否吃到食物应该调用body_insert方法:
snake.move() # 先让蛇移动 # 然后处理身体插入和食物判断 foodpos = food_spawner.spawn_food() if snake.body_insert() == 1: score += 1 food_spawner.set_food_on_screen(False)
(3) 标题更新拼写错误
你写的是pygme.display.set_caption,少了一个a,应该是pygame.display.set_caption。
修正后的完整代码(关键部分已修复)
import pygame, sys, random, time BLACK = (0, 0, 0) WHITE = (225, 225, 225) BLUE = (0, 0, 225) RED = (225, 0, 0) class Snake(object): def __init__(self): self.position = [100, 50] # 设置蛇的初始位置 self.body = [[100, 50], [90, 50], [80, 50]] # 设置蛇初始身体长度为3段 self.direction = "RIGHT" # ---------------------------- 允许改变方向,但不能直接反向 def change_direction_to(self, dir): if dir == "RIGHT" and not self.direction == "LEFT": self.direction = "RIGHT" elif dir == "LEFT" and not self.direction == "RIGHT": self.direction = "LEFT" elif dir == "UP" and not self.direction == "DOWN": self.direction = "UP" elif dir == "DOWN" and not self.direction == "UP": self.direction = "DOWN" # ---------------------------- # -------------------------------- 设置蛇的移动速度 def move(self): if self.direction == "RIGHT": self.position[0] += 10 if self.direction == "LEFT": self.position[0] -= 10 if self.direction == "UP": self.position[1] -= 10 if self.direction == "DOWN": self.position[1] += 10 # --------------------------------- # ----------------------------- 检查蛇是否吃到食物 def body_insert(self): self.body.insert(0, list(self.position)) if self.position == foodpos: return 1 else: self.body.pop() return 0 # ----------------------------- # ---------------------------------检查蛇是否撞墙和自身 def check_collision(self): # 撞墙判断 if self.position[0] > 690 or self.position[0] < 0: return 1 if self.position[1] > 590 or self.position[1] < 0: return 1 # 撞自身判断 for body_part in self.body[1:]: if self.position == body_part: return 1 return 0 # ---------------------------------- def get_head_position(self): return self.position def get_body(self): return self.body class FoodSpawner: def __init__(self): self.position = [random.randrange(1, 70) * 10, random.randrange(1, 60) * 10] self.is_food_on_screen = True def spawn_food(self): if not self.is_food_on_screen: self.position = [random.randrange(1, 70) * 10, random.randrange(1, 60) * 10] self.is_food_on_screen = True return self.position def set_food_on_screen(self, b): self.is_food_on_screen = b # 修正了拼写错误 window = pygame.display.set_mode((700, 600)) pygame.display.set_caption("Definitely Not Snake") fps = pygame.time.Clock() score = 0 snake = Snake() food_spawner = FoodSpawner() def game_over(): pygame.quit() sys.exit() while True: for event in pygame.event.get(): # ------------------------- 退出游戏 if event.type == pygame.QUIT: game_over() # ------------------------- # ------------------------- 蛇的移动控制 elif event.type == pygame.KEYDOWN: if event.key == pygame.K_RIGHT: snake.change_direction_to("RIGHT") elif event.key == pygame.K_LEFT: snake.change_direction_to("LEFT") elif event.key == pygame.K_UP: snake.change_direction_to("UP") elif event.key == pygame.K_DOWN: snake.change_direction_to("DOWN") # ------------------------- # ----------------------------- 蛇移动与吃到食物判断 snake.move() foodpos = food_spawner.spawn_food() if snake.body_insert() == 1: score += 1 food_spawner.set_food_on_screen(False) # ------------------------------ # ------------------------------ 绘制屏幕、蛇和食物 window.fill(pygame.Color("BLACK")) for pos in snake.get_body(): pygame.draw.rect(window, pygame.Color("BLUE"), pygame.Rect(pos[0], pos[1], 10, 10)) # 修正了draw.rect的参数顺序 pygame.draw.rect(window, pygame.Color("RED"), pygame.Rect(int(foodpos[0]), int(foodpos[1]), 10, 10)) # ------------------------------ if snake.check_collision() == 1: game_over() # 修正了拼写错误 pygame.display.set_caption("Definitely not Snake | Score : " + str(score)) pygame.display.flip() fps.tick(24)
现在你可以运行修正后的代码,应该能正常启动贪吃蛇游戏了。如果还有其他问题,可以继续调试。
内容的提问来源于stack exchange,提问作者TFreezen

