如何修改Python Socket双玩家游戏代码以支持多客户端?
从双玩家到多玩家:Python Socket游戏改造方案
原教程仅支持双玩家,要扩展为多玩家,核心是让服务器维护完整的玩家列表,并将所有其他玩家的数据同步给每个客户端。以下是具体修改步骤:
1. 改造Server.py(核心修改)
- 调整监听连接数,支持更多玩家接入
- 动态创建新玩家,不再固定初始两个玩家
- 同步时返回当前玩家以外的所有玩家列表,而非单个玩家
修改后的server.py代码:
import socket from _thread import * from player import Player import pickle import random server = "10.11.250.207" port = 5555 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: s.bind((server, port)) except socket.error as e: print(str(e)) # 调整监听数,支持更多玩家(示例设为10人) s.listen(10) print("Waiting for connections, Server Started") players = [] def threaded_client(conn, player_id): # 给新玩家生成随机初始位置和颜色 x = random.randint(50, 400) y = random.randint(50, 400) color = (random.randint(0,255), random.randint(0,255), random.randint(0,255)) new_player = Player(x, y, 50, 50, color) players.append(new_player) # 先把当前玩家的数据发给客户端 conn.send(pickle.dumps(new_player)) while True: try: # 接收客户端发来的自己的最新状态 data = pickle.loads(conn.recv(2048)) if not data: print(f"Player {player_id} disconnected") break # 更新服务器上的玩家状态 players[player_id] = data # 准备回复:除了当前玩家之外的所有玩家 reply = [p for idx, p in enumerate(players) if idx != player_id] conn.sendall(pickle.dumps(reply)) except Exception as e: print(f"Error: {e}") break # 玩家断开,从列表移除 del players[player_id] print(f"Player {player_id} removed from list") conn.close() current_player_id = 0 while True: conn, addr = s.accept() print(f"Connected to: {addr}, Player ID: {current_player_id}") start_new_thread(threaded_client, (conn, current_player_id)) current_player_id += 1
2. 调整Network.py(适配返回列表)
无需大幅修改,只需确保客户端能正确接收列表格式的数据,原代码可直接使用:
import socket import pickle class Network: def __init__(self): self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server = "10.11.250.207" self.port = 5555 self.addr = (self.server, self.port) self.p = self.connect() def getP(self): return self.p def connect(self): try: self.client.connect(self.addr) return pickle.loads(self.client.recv(2048)) except Exception as e: print(e) def send(self, data): try: self.client.send(pickle.dumps(data)) return pickle.loads(self.client.recv(2048)) except socket.error as e: print(e)
3. 修改Client.py(渲染所有玩家)
- 更新窗口渲染函数,遍历所有其他玩家进行绘制
- 调整主循环逻辑,处理服务器返回的玩家列表
修改后的client.py代码:
import pygame from network import Network from player import Player width = 500 height = 500 win = pygame.display.set_mode((width, height)) pygame.display.set_caption("Multiplayer Client") def redrawWindow(win, self_player, other_players): win.fill((255,255,255)) # 先画自己 self_player.draw(win) # 遍历画所有其他玩家 for player in other_players: player.draw(win) pygame.display.update() def main(): run = True n = Network() self_player = n.getP() clock = pygame.time.Clock() while run: clock.tick(60) # 发送自己的状态,接收其他玩家列表 other_players = n.send(self_player) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False pygame.quit() self_player.move() redrawWindow(win, self_player, other_players) if __name__ == "__main__": main()
4. Player.py(可选优化)
可以给Player类添加id属性方便后续扩展(比如区分玩家),基础版无需修改,原代码可直接使用:
import pygame class Player(): def __init__(self, x, y, width, height, color): self.x = x self.y = y self.width = width self.height = height self.color = color self.rect = (x,y,width,height) self.vel = 3 def draw(self, win): pygame.draw.rect(win, self.color, self.rect) def move(self): keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: self.x -= self.vel if keys[pygame.K_RIGHT]: self.x += self.vel if keys[pygame.K_UP]: self.y -= self.vel if keys[pygame.K_DOWN]: self.y += self.vel self.update() def update(self): self.rect = (self.x, self.y, self.width, self.height)
核心改动说明
- 服务器不再固定初始玩家,而是为每个新连接动态生成玩家并加入列表
- 同步逻辑从“返回单个对手”改成“返回所有其他玩家”
- 客户端渲染逻辑从绘制两个玩家改成绘制自己+所有其他玩家
- 增加了玩家断开后的列表清理逻辑
内容的提问来源于stack exchange,提问作者Justin Cheng
相关产品推荐
相关产品推荐

