不能用pyle

时间:2018-05-03 08:57:36

标签: python pygame

我正在使用python 3.6开发游戏,我希望在其多人游戏版本中将客户端(播放器)修改的服务器对象发送到我想要将它们序列化以进行传输。我在我的对象中使用pygame和pygame.Surface

我有这种结构的对象:

class Cargo(Bateau):
  dictCargos = dict()
  def __init__(self, map, nom, pos, armateur=None):
    Bateau.__init__(self, map, nom, armateur, pos)
    self.surface = pygame.image.load(f"images/{self.nom}.png").convert_alpha()
    self.rect = self.map.blit(self.surface, self.pos)
    ...
    Cargo.dictCargos[self.nom] = self

当我在没有pygame实例的情况下序列化另一个对象时,它没问题 但是对于上面描述的对象,我收到此错误消息:

import pickle as pickle
pickle.dump(Cargo.dictCargos, open('file2.pkl', 'wb'), protocol=pickle.HIGHEST_PROTOCOL)

Traceback (most recent call last):
  File "./pytransit.py", line 182, in <module>
    encreG(joueur, event)
  File "/home/patrick/Bureau/PyTransit/modulesJeu/tests.py", line 25, in encreG
    pickle.dump(Cargo.dictCargos, open('file2.pkl', 'wb'), protocol=pickle.HIGHEST_PROTOCOL)
TypeError: can't pickle pygame.Surface objects

您是否知道如何将这些项目传输到服务器。或绕过这个泡菜限制?
如果我想保存零件会出现同样的问题,所以保存这些对象

2 个答案:

答案 0 :(得分:2)

这是@IonicSolutions在评论中指出的一个例子:

import pickle
import pygame


class Test:
    def __init__(self, surface):
        self.surface = surface
        self.name = "Test"

    def __getstate__(self):
        state = self.__dict__.copy()
        surface = state.pop("surface")
        state["surface_string"] = (pygame.image.tostring(surface, "RGB"), surface.get_size())
        return state

    def __setstate__(self, state):
        surface_string, size = state.pop("surface_string")
        state["surface"] = pygame.image.fromstring(surface_string, size, "RGB")
        self.__dict__.update(state)


t = Test(pygame.Surface((100, 100)))
b = pickle.dumps(t)
t = pickle.loads(b)

print(t.surface)

要查看可用于将数据存储为字符串的模式(此处为&#34; RGB&#34;),请查看into the documentation

答案 1 :(得分:0)

基于@MegaIng的答案,我制定了他/她的答案,以便您可以正常使用pygame.Surface,但添加了pickle功能。它不应打扰您的任何代码。我已经在python 3.7(64位)上对其进行了测试,并且可以正常工作。也已经在我的项目上尝试过/实现了它,没有什么受到干扰。

import pygame as pg

pgSurf = pg.surface.Surface

class PickleableSurface(pgSurf):
    def __init__(self, *arg,**kwarg):
        size = arg[0]

        # size given is not an iterable,  but the object of pgSurf itself
        if (isinstance(size, pgSurf)):
            pgSurf.__init__(self, size=size.get_size(), flags=size.get_flags())
            self.surface = self
            self.name='test'
            self.blit(size, (0, 0))

        else:
            pgSurf.__init__(self, *arg, **kwarg)
            self.surface = self
            self.name = 'test'

    def __getstate__(self):
        state = self.__dict__.copy()
        surface = state["surface"]

        _1 = pg.image.tostring(surface.copy(), "RGBA")
        _2 = surface.get_size()
        _3 = surface.get_flags()
        state["surface_string"] = (_1, _2, _3)
        return state

    def __setstate__(self, state):
        surface_string, size, flags = state["surface_string"]

        pgSurf.__init__(self, size=size, flags=flags)

        s=pg.image.fromstring(surface_string, size, "RGBA")
        state["surface"] =s;
        self.blit(s,(0,0));self.surface=self;
        self.__dict__.update(state)

这是一个例子

pg.Surface = PickleableSurface
pg.surface.Surface = PickleableSurface

surf = pg.Surface((300, 400), pg.SRCALPHA|pg.HWSURFACE)
# Surface, color, start pos, end pos, width
pg.draw.line(surf, (0,0,0), (0,100), (200, 300), 2)  

from pickle import loads, dumps

dump = dumps(surf)
loaded = loads(dump)
pg.init()
screen = pg.display.set_mode((300, 400))
screen.fill((255, 255, 255))
screen.blit(loaded, (0,0))
pg.display.update()

然后在我的屏幕上

The result of the script on my screen

谢谢@MegaIng

P.s: 我还添加了功能,通过执行newSurface = PickleableSurface(PygameSurface),将无法上刺的pygame表面转换为可以上酱的表面 但是,它仅测试了一次,因此可能存在一些错误。如果您找到一个,请随时告诉我!希望对您有所帮助! :D