将pygame的image.load切换为PIL的Image.open报错,如何实现按键切换角色图片
问题解决方法
报错原因
你遇到的TypeError: not a file object报错核心原因是两类图片对象的混用逻辑错误:
- 你提前用
Image.open()得到的hero_img是PIL的Image类实例,但Gamesprite初始化时调用的pygame.image.load()仅支持接收「图片路径字符串」或「系统文件对象」作为参数,不识别PIL的Image对象。 - 另外pygame的精灵类
self.image属性只能接收pygame原生的Surface对象,PIL的Image对象不能直接赋值给该属性,就算跳过初始化加载的步骤直接赋值也会报错。
解决方法
方案1:直接使用pygame原生方法实现(推荐,无需引入PIL依赖)
这个方案改动最小,完全不需要引入PIL依赖:
- 首先修改Player实例化的传参:把现在传的PIL类型
hero_img替换为初始图片的路径字符串,比如:
# 原来错误的传参(hero_img是PIL对象) # player = Player(hero_img, tiles, tiles, int(tiles*0.87), tiles, tiles//10) # 修改为传初始图片路径字符串 player = Player('hero_default.png', tiles, tiles, int(tiles*0.87), tiles, tiles//10)
- 在Player类的
__init__方法里提前保存宽高参数,方便后续切换图片时复用:
class Player(Gamesprite): def __init__(self, img, x, y, width, height, speed): super().__init__(img, x, y, width, height, speed) # 保存宽高用于后续切换图片 self.img_width = width self.img_height = height
- 修改
control方法,直接用pygame的方法加载图片并赋值给self.image即可:
def control(self): keys=key.get_pressed() if keys[K_LEFT]: # 直接用pygame加载对应方向图片,缩放到对应尺寸后赋值给self.image self.image = transform(image.load('hero_left.png'), (self.img_width, self.img_height)) self.rect.x -= self.speed for wall in list_wall: if sprite.collide_rect(self,wall): self.rect.x += self.speed*1.1
- (可选优化)提前预加载所有方向的图片,避免每次按按键都重复读磁盘IO导致卡顿:
class Player(Gamesprite): def __init__(self, img, x, y, width, height, speed): super().__init__(img, x, y, width, height, speed) self.img_width = width self.img_height = height # 预加载所有方向的图片,存在字典里直接取用 self.dir_imgs = { 'left': transform(image.load('hero_left.png'), (self.img_width, self.img_height)), 'right': transform(image.load('hero_right.png'), (self.img_width, self.img_height)), 'up': transform(image.load('hero_up.png'), (self.img_width, self.img_height)), 'down': transform(image.load('hero_down.png'), (self.img_width, self.img_height)) } def control(self): keys=key.get_pressed() if keys[K_LEFT]: self.image = self.dir_imgs['left'] self.rect.x -= self.speed # 碰撞逻辑保持不变
方案2:必须使用PIL加载的兼容方案
如果确实需要用PIL做图片预处理再传给pygame,就需要加一步PIL Image转pygame Surface的转换逻辑:
- 先写转换工具函数:
from PIL import Image import pygame def pil_image_to_pygame_surface(pil_img): return pygame.image.fromstring(pil_img.tobytes(), pil_img.size, pil_img.mode)
- 加载完PIL图片后转换再赋值:
def control(self): keys=key.get_pressed() if keys[K_LEFT]: hero_img = Image.open('hero_left.png') # 转成pygame的Surface对象后再缩放到对应尺寸,赋值给self.image self.image = transform(pil_image_to_pygame_surface(hero_img), (self.img_width, self.img_height)) self.rect.x -= self.speed # 碰撞逻辑保持不变
内容的提问来源于stack exchange,提问作者kapurdok
相关产品推荐
相关产品推荐

