我正在使用 pygame 开发一款两人多人游戏。
这是服务器代码和客户端代码:
import json
import pygame # Main module for the game
import pyautogui # For slightly enhancing control sensitivity
import sys # For console control
import socket # Socket for network communication
import threading # For multithreading
import math
pygame.init() # Initialize Pygame
pygame.display.set_caption('SERVER') # Set window title
height = 960 # Window height
width = 1200 # Window width
screen = pygame.display.set_mode((width, height))
class Bullet:
def __init__(self, img, x, y, dx, dy, w, h, damage, team):
self.__img = img
self.__x = x
self.__y = y
self.__dx = dx
self.__dy = dy
self.__w = w
self.__h = h
self.__damage = damage
self.__team = team
def getdamage(self):
return self.__damage
def getteam(self):
return self.__team
def getrect(self):
nrect = pygame.Rect(0, 0, self.__w, self.__h)
nrect.center = (self.__x, self.__y)
return nrect
def getpos(self):
return (self.__x, self.__y)
def move(self):
self.__x += self.__dx
self.__y += self.__dy
def show(self):
newRect = self.getrect()
screen.blit(self.__img, newRect)
enemy_img = pygame.image.load('char.png')
enemy_img = pygame.transform.flip(enemy_img, True, False)
bulletimg = pygame.image.load('a_bullet.png')
bulletw = bulletimg.get_size()[0]
bulleth = bulletimg.get_size()[1]
imgw = enemy_img.get_size()[0]
imgh = enemy_img.get_size()[1]
bulletlist = []
enex = 0
eney = imgh
playersize = imgw / 2
playerspeed = 3
enexdirec = 0
eneydirec = 0
playerxdirec = 0
playerydirec = 0
playerHp = 100
eneHp = 100
def getPlayerrect(pos):
nrect = pygame.Rect(0, 0, imgw, imgh)
nrect.center = (pos[0], pos[1])
return nrect
def consoles():
global enexdirec, eneydirec
global eneHp, playerHp
while True:
msg = client.recv(1024)
if not msg:
break # Connection closed
decoded_msg = msg.decode() # Decode message to string
if decoded_msg == 'up':
eneydirec = -1
if decoded_msg == 'down':
eneydirec = 1
if decoded_msg == 'left':
enexdirec = -1
if decoded_msg == 'right':
enexdirec = 1
if decoded_msg == 'endx':
enexdirec = 0
if decoded_msg == 'endy':
eneydirec = 0
if decoded_msg == 'damaged':
playerHp -= 10
if playerHp <= 0:
print("LOSE")
quitgame()
if decoded_msg.startswith('{'): # If message is in JSON format, process as bullet data
data = json.loads(decoded_msg) #ERROR!jsondecodeerror
if data.get("type") == "bullet":
# Create and add Bullet object
bulletlist.append(Bullet(
bulletimg,
data['x'],
data['y'],
data['dx'],
data['dy'],
data['width'],
data['height'],
data['damage'],
'E'
))
def acceptC():
global client, server, addr
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('127.0.0.1', 7777))
server.listen()
client, addr = server.accept()
thr = threading.Thread(target=consoles, args=())
thr.Daemon = True
thr.start()
def quitgame():
pygame.quit()
sys.exit()
def clamp(x, mi, ma):
if x > ma:
return ma
elif x < mi:
return mi
return x
def calcvector(sp, fp):
direcx = fp[0] - sp[0]
direcy = fp[1] - sp[1]
l = math.sqrt(direcx**2 + direcy**2)
if l == 0:
return (1, 0)
else:
return (direcx / l, direcy / l)
def GameMain():
global playerHp, eneHp
global enex, eney
global playerxdirec, playerydirec
fps = pygame.time.Clock()
img = pygame.image.load('char.png') # Load player image
imgh = img.get_size()[1]
imgw = img.get_size()[0]
x = 0
y = imgh
while True:
screen.fill((255, 255, 255))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:#send bullet data to client
T = pygame.mouse.get_pos()
direcvec = calcvector((x, y), T)
speed = 8
newB = Bullet(bulletimg, x, y, direcvec[0] * speed, direcvec[1] * speed, 10, 10, 10, 'M')
bulletlist.append(newB)
bullet_data = json.dumps({
'type': 'bullet',
'x': x,
'y': y,
'dx': direcvec[0] * speed,
'dy': direcvec[1] * speed,
'width': 10,
'height': 10,
'damage': 10
})
client.sendall(bullet_data.encode())
keys = pygame.key.get_pressed()
if not(keys[pygame.K_a] ^ keys[pygame.K_d]):
playerxdirec = 0
msg = "endx"
client.sendall(msg.encode())
elif keys[pygame.K_a]:
playerxdirec = -1
msg = "left"
client.sendall(msg.encode())
elif keys[pygame.K_d]:
playerxdirec = 1
msg = "right"
client.sendall(msg.encode())
if not(keys[pygame.K_w] ^ keys[pygame.K_s]):
playerydirec = 0
msg = "endy"
client.sendall(msg.encode())
elif keys[pygame.K_w]:
playerydirec = -1
msg = "up"
client.sendall(msg.encode())
elif keys[pygame.K_s]:
playerydirec = 1
msg = "down"
client.sendall(msg.encode())
for i in bulletlist:
i.move()
bulpos = i.getpos()
if bulpos[0] > width or bulpos[0] < 0 or bulpos[1] < 0 or bulpos[1] > height:
bulletlist.remove(i)
continue
else:
i.show()
if i.getrect().colliderect(getPlayerrect((x, y))) and i.getteam() == 'E':
bulletlist.remove(i)
playerHp -= 10
msg = json.dumps({
'type': 'hp_update',
'hp': eneHp,
'eneHp': playerHp
})
print('er')
client.sendall(msg.encode())
continue
if i.getrect().colliderect(getPlayerrect((enex, eney))) and i.getteam() == 'M':
bulletlist.remove(i)
eneHp -= 10
msg = json.dumps({
'type': 'hp_update',
'hp': eneHp,
'eneHp': playerHp
})
print('su')
client.sendall(msg.encode())
continue
if eneHp <= 0:
print('WIN')
quitgame()
if playerHp <= 0:
print('WIN')
quitgame()
# Draw enemy HP bar
enehpposrect = pygame.Rect(0, 0, 30, 8)
enehpposrect.center = (enex, eney + 20)
enehpposrect2 = pygame.Rect(enehpposrect.x, enehpposrect.y, 30 * (eneHp / 100), 8)
pygame.draw.rect(screen, "red", enehpposrect)
pygame.draw.rect(screen, "green", enehpposrect2)
# Draw player HP bar
playerhpposrect = pygame.Rect(0, 0, 30, 8)
playerhpposrect.center = (x, y + 20)
playerhpposrect2 = pygame.Rect(playerhpposrect.x, playerhpposrect.y, 30 * (playerHp / 100), 8)
pygame.draw.rect(screen, "red", playerhpposrect)
pygame.draw.rect(screen, "green", playerhpposrect2)
x += playerxdirec * playerspeed
y += playerydirec * playerspeed
enex += enexdirec * playerspeed
eney += eneydirec * playerspeed
x = clamp(x, 0, width)
y = clamp(y, 0, height)
enex = clamp(enex, 0, width)
eney = clamp(eney, 0, height)
mRect = pygame.Rect(0, 0, imgw, imgh)
mRect.center = (x, y)
screen.blit(img, mRect)
eRect = pygame.Rect(0, 0, imgw, imgh)
eRect.center = (enex, eney)
screen.blit(enemy_img, eRect)
pygame.display.update() # Update display
fps.tick(60) # Set FPS to 60
if __name__ == '__main__':
acceptC()
GameMain()
import pygame
import pyautogui
import sys
import socket
import threading
import json
import math
pygame.init()
pygame.display.set_caption('CLIENT')
height = 960
width = 1200
screen = pygame.display.set_mode((width, height))
class Bullet:
def __init__(self, img, x, y, dx, dy, w, h, damage, team):
self.__img = img
self.__x = x
self.__y = y
self.__dx = dx
self.__dy = dy
self.__w = w
self.__h = h
self.__damage = damage
self.__team = team
def getdamage(self):
return self.__damage
def getteam(self):
return self.__team
def getrect(self):
nrect = pygame.Rect(0, 0, self.__w, self.__h)
nrect.center = (self.__x, self.__y)
return nrect
def getpos(self):
return (self.__x, self.__y)
def move(self):
self.__x += self.__dx
self.__y += self.__dy
def show(self):
newRect = self.getrect()
screen.blit(self.__img, newRect)
enemy_img = pygame.image.load('char.png')
enemy_img = pygame.transform.flip(enemy_img, True, False)
bulletimg = pygame.image.load('a_bullet.png')
bulletw = bulletimg.get_size()[0]
bulleth = bulletimg.get_size()[1]
imgw = enemy_img.get_size()[0]
imgh = enemy_img.get_size()[1]
bulletlist = []
enex = 0
eney = imgh
playersize = imgw / 2
playerspeed = 3
enexdirec = 0
eneydirec = 0
playerxdirec = 0
playerydirec = 0
playerHp = 100
eneHp = 100
def getPlayerrect(pos):
nrect = pygame.Rect(0, 0, imgw, imgh)
nrect.center = (pos[0], pos[1])
return nrect
def consoles():
global eneHp, playerHp
global enexdirec, eneydirec
while True:
msg = client.recv(1024)
if not msg:
break # If the connection is lost
decoded_msg = msg.decode() # Convert message to string
if decoded_msg == 'up':
eneydirec = -1
if decoded_msg == 'down':
eneydirec = 1
if decoded_msg == 'left':
enexdirec = -1
if decoded_msg == 'right':
enexdirec = 1
if decoded_msg == 'endx':
enexdirec = 0
if decoded_msg == 'endy':
eneydirec = 0
if decoded_msg == 'damaged':
playerHp -= 10
if playerHp <= 0:
print("LOSE")
quitgame()
if decoded_msg.startswith('{'): # If JSON format, treat it as bullet data
data = json.loads(decoded_msg) #ERROR!jsondecodeerror
if data.get("type") == 0:
print('a')
playerHp = data["hp"]
eneHp = data["eneHp"]
if data.get("type") == 1:
# Create and add Bullet object
bulletlist.append(Bullet(
bulletimg,
data['x'],
data['y'],
data['dx'],
data['dy'],
data['width'],
data['height'],
data['damage'],
'E'
))
def acceptC():
global client
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 7777))
thr = threading.Thread(target=consoles, args=())
thr.Daemon = True
thr.start()
def quitgame():
pygame.quit()
sys.exit()
def clamp(x, mi, ma):
if x > ma:
return ma
elif x < mi:
return mi
return x
def calcvector(sp, fp):
direcx = fp[0] - sp[0]
direcy = fp[1] - sp[1]
l = math.sqrt(direcx ** 2 + direcy ** 2)
if l == 0:
return (1, 0)
else:
return (direcx / l, direcy / l)
def GameMain():
global playerHp, eneHp
global playerxdirec, playerydirec
global enex, eney
fps = pygame.time.Clock()
img = pygame.image.load('char.png')
imgh = img.get_size()[1]
imgw = img.get_size()[0]
x = 0
y = imgh
while True:
screen.fill((255, 255, 255))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:#send bullet data to server
T = pygame.mouse.get_pos()
direcvec = calcvector((x, y), T)
speed = 8
newB = Bullet(bulletimg, x, y, direcvec[0] * speed, direcvec[1] * speed, 10, 10, 10, 'M')
bulletlist.append(newB)
bullet_data = json.dumps({
'type': 1,
'x': x,
'y': y,
'dx': direcvec[0] * speed,
'dy': direcvec[1] * speed,
'width': 10,
'height': 10,
'damage': 10
})
client.sendall(bullet_data.encode())
keys = pygame.key.get_pressed()
if not(keys[pygame.K_a] ^ keys[pygame.K_d]):
playerxdirec = 0
msg = "endx"
client.sendall(msg.encode())
elif keys[pygame.K_a]:
playerxdirec = -1
msg = "left"
client.sendall(msg.encode())
elif keys[pygame.K_d]:
playerxdirec = 1
msg = "right"
client.sendall(msg.encode())
if not(keys[pygame.K_w] ^ keys[pygame.K_s]):
playerydirec = 0
msg = "endy"
client.sendall(msg.encode())
elif keys[pygame.K_w]:
playerydirec = -1
msg = "up"
client.sendall(msg.encode())
elif keys[pygame.K_s]:
playerydirec = 1
msg = "down"
client.sendall(msg.encode())
for i in bulletlist:
i.move()
bulpos = i.getpos()
if bulpos[0] > width or bulpos[0] < 0 or bulpos[1] < 0 or bulpos[1] > height:
bulletlist.remove(i)
continue
else:
i.show()
if i.getrect().colliderect(getPlayerrect((x, y))) and i.getteam() == 'E':
bulletlist.remove(i)
continue
if i.getrect().colliderect(getPlayerrect((enex, eney))) and i.getteam() == 'M':
bulletlist.remove(i)
continue
if playerHp <= 0:
print('LOSE')
quitgame()
if eneHp <= 0:
print('WIN')
quitgame()
enehpposrect = pygame.Rect(0, 0, 30, 8)
enehpposrect.center = (enex, eney + 20)
enehpposrect2 = pygame.Rect(enehpposrect.x, enehpposrect.y, 30 * (eneHp / 100), 8)
pygame.draw.rect(screen, "red", enehpposrect)
pygame.draw.rect(screen, "green", enehpposrect2)
playerhpposrect = pygame.Rect(0, 0, 30, 8)
playerhpposrect.center = (x, y + 20)
playerhpposrect2 = pygame.Rect(playerhpposrect.x, playerhpposrect.y, 30 * (playerHp / 100), 8)
pygame.draw.rect(screen, "red", playerhpposrect)
pygame.draw.rect(screen, "green", playerhpposrect2)
x += playerxdirec * playerspeed
y += playerydirec * playerspeed
enex += enexdirec * playerspeed
eney += eneydirec * playerspeed
x = clamp(x, 0, width)
y = clamp(y, 0, height)
enex = clamp(enex, 0, width)
eney = clamp(eney, 0, height)
mRect = pygame.Rect(0, 0, imgw, imgh)
mRect.center = (x, y)
screen.blit(img, mRect)
eRect = pygame.Rect(0, 0, imgw, imgh)
eRect.center = (enex, eney)
screen.blit(enemy_img, eRect)
pygame.display.update()
fps.tick(60)
if __name__ == '__main__':
acceptC()
GameMain()
当我在电脑上运行这两个代码并玩游戏时,一切正常。
但是,如果我更改IP地址并在两台电脑上运行,播放器移动正常,但是一旦我点击鼠标发射子弹,就会出现以下错误:
json.decoder.JSONDecodeError: Extra data: line 1 column 124 (char 123)
如何解决这个问题?
我尝试使用 pickle 而不是使用 JSON 的解码/编码,但出现以下错误:
_pickle.UnpicklingError: unpickling stack underflow
即使我增加 client.recv 值也会发生同样的错误。
def 控制台(): 全球玩家,敌人 而真实: 消息 = 客户端.recv(1024) 如果没有消息: 休息 解码_msgs = msg.decode().split(" ”) 对于decoded_msgs中的decoded_msg: 如果decoded_msg ==“向上”: 敌人.direction_y = -1 elif解码_msg ==“向下”: 敌人.direction_y = 1 elif解码_msg ==“左”: 敌人.direction_x = -1 elif解码_msg ==“正确”: 敌人.direction_x = 1 elif已解码_msg ==“endx”: 敌人.direction_x = 0 elif已解码_msg ==“endy”: 敌人.direction_y = 0 elif解码_msg ==“损坏”: 玩家.take_damage(10) 如果玩家.hp <= 0: print("LOSE") quitgame() elif decoded_msg.startswith("{"): data = json.loads(decoded_msg) if data.get("type") == 1: bulletlist.append(Bullet( bulletimg, data["x"], data["y"], data["dx"], data["dy"], data["width"], data["height"], data["damage"], "E" ))
将consoles()函数替换为以下内容,并在传递数据时为所有数据添加换行符,您的问题将得到解决: