Python3.6多人游戏开发:pickle无法序列化pygame.Surface对象求助
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

