Welcome to MLink Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
275 views
in Technique[技术] by (71.8m points)

python - How to save object using pygame.Surfaces to file using pickle

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

pygame.Surfaces 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()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to MLink Developer Q&A Community for programmer and developer-Open, Learning and Share
...