繁体   English   中英

无法使用pickle序列化pygame.Surface对象

[英]can't serialized pygame.Surface objects with pickle

我正在使用 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

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

这是@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)

要查看可以使用哪些模式将数据存储为字符串(此处为“RGB”),请查看文档

根据@MegaIng 的回答,我开发了他/她的回答,以便您可以正常使用 pygame.Surface,但添加了泡菜功能。 它不应该打扰您的任何代码。 我已经在 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()

然后在我的屏幕上:

脚本在我屏幕上的结果

谢谢@MegaIng

Ps:我还通过newSurface = PickleableSurface(PygameSurface)添加了将newSurface = PickleableSurface(PygameSurface)腌制的 pygame 表面转换为可腌制的表面的功能,但是,它只测试了一次,因此可能存在一些错误。 如果你找到了,请随时告诉我! 我希望它会帮助你! :D

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM