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
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()