You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python3.6多人游戏开发:pickle无法序列化pygame.Surface对象求助

Fixing pygame.Surface Pickle Serialization Error for Multiplayer Game

Got it, let's tackle that pickle error you're hitting with your Cargo class. The core issue is that pygame.Surface wraps a low-level SDL graphics object—pickle has no idea how to serialize that into a format you can send over the network. Since your multiplayer setup only needs to transmit game state (not rendered graphics), here are three solid solutions, ordered by how practical they are for your use case:

1. Filter Out Non-Serializable Fields with __getstate__/__setstate__

The simplest fix is to tell pickle exactly what data to serialize by overriding these two methods. Since your server doesn't need to render the ship (it just handles game logic), you can exclude surface and rect from serialization, then rebuild them locally on the client after receiving the data.

Here's how to update your Cargo class:

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.surface.get_rect(center=pos)  # Assuming this is how you set rect

    def __getstate__(self):
        # Create a copy of the object's state, minus non-serializable fields
        state = self.__dict__.copy()
        del state['surface']
        del state['rect']
        return state

    def __setstate__(self, state):
        # Restore the object's state, then rebuild surface/rect locally
        self.__dict__.update(state)
        # Recreate the surface and rect using the stored 'nom' and 'pos'
        self.surface = pygame.image.load(f"images/{self.nom}.png").convert_alpha()
        self.rect = self.surface.get_rect(center=self.pos)

This way, when you pickle a Cargo instance, only the game-critical data (like nom, pos, armateur) gets sent. The client rebuilds the graphics objects using its local image files—no need to waste bandwidth sending image data.

2. Use JSON for Safer, Explicit Serialization

Pickle has security risks (it can execute arbitrary code if you load untrusted data), which is a big red flag for multiplayer games. A better approach is to use JSON, which only serializes basic Python types. You'll define methods to convert your Cargo object to a dictionary (and back) manually.

Example implementation:

import json

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.surface.get_rect(center=pos)

    def to_dict(self):
        # Return only the data needed to reconstruct the object's state
        return {
            'nom': self.nom,
            'pos': self.pos,
            'armateur': self.armateur,
            # Add any other fields from the Bateau base class you need to transmit
        }

    @classmethod
    def from_dict(cls, map, data):
        # Recreate the Cargo object from the dictionary
        return cls(map, data['nom'], data['pos'], data['armateur'])

How to use this:

  • On the client (sending data):
    # Convert Cargo object to JSON string
    cargo_json = json.dumps(player_cargo.to_dict())
    # Send cargo_json to server (using your network library of choice)
    
  • On the client (receiving data):
    # Parse JSON string back to dictionary
    cargo_data = json.loads(received_json)
    # Recreate the Cargo object
    received_cargo = Cargo.from_dict(game_map, cargo_data)
    

This method is safer, more transparent, and avoids pickle's security pitfalls—highly recommended for multiplayer games.

3. Transmit Surface Data (Only If Absolutely Necessary)

If you ever need to send custom image data (like user-created skins, which doesn't seem to be your case), you can convert the Surface to a byte stream. This is bandwidth-heavy, so only use it if you can't avoid it.

Example code snippet:

from io import BytesIO

def surface_to_bytes(surface):
    buffer = BytesIO()
    pygame.image.save(surface, buffer, 'PNG')
    buffer.seek(0)
    return buffer.getvalue()

def bytes_to_surface(byte_data):
    buffer = BytesIO(byte_data)
    return pygame.image.load(buffer).convert_alpha()

You'd then add the byte data to your serialized state in __getstate__, and convert it back in __setstate__. But again, this is overkill for your current setup—stick to the first two solutions unless you have a specific need for it.


内容的提问来源于stack exchange,提问作者patol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:41:43