问题
If I have created my own class which has some attributes that are pygame.Surfaces and I would like to save this object to a file, how can I do this as an error occurs when I try.
The class which I have created is an object which is essentially the following (Item class is included because the player has items which have attributes that are pygame.Surfaces):
class Item:
def __init__(self,name,icon):
self.name = name
self.icon = pygame.image.load(icon)
class Player(pygame.Sprite):
def __init__(self,{some_attrs})
skins = [{a pygame.Surface from a load image},{another}]
self.money = 0
self.items = [{Item object}]
Then when I try to save, I use the following:
with open('save.dat','wb') as file:
pickle.dump(player , file , protocol = 4)
#I have also tried without the protocol argument
But I get the following error:
Traceback (most recent call last):
File "{file path}", line 883, in <module>
save_progress()
File "{file path}", line 107, in save_progress
pickle.dump(player,file,protocol=4)
TypeError: can't pickle pygame.Surface objects
FYI, Everything that I have put in curly braces ({ and }) is just something that I have abbreviated or left out because it wasn't needed
If you need any more detail, I can easily add it if you reply what you need
回答1:
pygame.Surface
s are not meant to be pickled. You could put your images into a dictionary, so that you can retrieve them by their name/dictionary key (a string). Then store this name in your sprite to serialize it with pickle or json (which is more secure) and use it to recreate the sprite when you load the game.
Here's a simple example in which you can save and load some sprites (only the relevant attributes) by pressing s and w:
import json
import pygame as pg
pg.init()
IMAGE_BLUE = pg.Surface((32, 52))
IMAGE_BLUE.fill(pg.Color('steelblue1'))
IMAGE_SIENNA = pg.Surface((32, 52))
IMAGE_SIENNA.fill(pg.Color('sienna1'))
# Put the images into a dictionary, so that we can get them by their name.
IMAGES = {'blue': IMAGE_BLUE, 'sienna': IMAGE_SIENNA}
class Entity(pg.sprite.Sprite):
def __init__(self, pos, image_name):
super().__init__()
# Store the image name to save it with json later.
self.image_name = image_name
self.image = IMAGES[image_name]
self.rect = self.image.get_rect(topleft=pos)
class Game:
def __init__(self):
self.done = False
self.bg_color = pg.Color('gray13')
self.clock = pg.time.Clock()
self.screen = pg.display.set_mode((640, 480))
# Pass the image names (i.e. keys of the IMAGES dict).
entity1 = Entity((250, 120), 'blue')
entity2 = Entity((400, 260), 'sienna')
self.all_sprites = pg.sprite.Group(entity1, entity2)
self.selected = None
def run(self):
while not self.done:
self.handle_events()
self.run_logic()
self.draw()
self.clock.tick(60)
def handle_events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
elif event.type == pg.MOUSEBUTTONDOWN:
if self.selected:
self.selected = None
else:
for sprite in self.all_sprites:
if sprite.rect.collidepoint(event.pos):
self.selected = sprite
elif event.type == pg.MOUSEMOTION:
if self.selected:
self.selected.rect.move_ip(event.rel)
elif event.type == pg.KEYDOWN:
if event.key == pg.K_s:
self.save()
elif event.key == pg.K_w:
self.load()
def run_logic(self):
self.all_sprites.update()
def draw(self):
self.screen.fill(self.bg_color)
self.all_sprites.draw(self.screen)
pg.display.flip()
def save(self):
with open('save_game1.json', 'w') as file:
print('Saving')
# Create a list of the top left positions and the
# image names.
data = [(sprite.rect.topleft, sprite.image_name)
for sprite in self.all_sprites]
json.dump(data, file)
def load(self):
with open('save_game1.json', 'r') as file:
print('Loading')
data = json.load(file)
self.selected = None
self.all_sprites.empty()
# Use the positions and image names to recreate the sprites.
for pos, image_name in data:
self.all_sprites.add(Entity(pos, image_name))
if __name__ == '__main__':
Game().run()
pg.quit()
来源:https://stackoverflow.com/questions/52336196/how-to-save-object-using-pygame-surfaces-to-file-using-pickle