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

别来无恙 提交于 2021-02-05 06:42:11

问题


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


来源:https://stackoverflow.com/questions/52336196/how-to-save-object-using-pygame-surfaces-to-file-using-pickle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!