如何解决pygame中的多人游戏程序在添加一些代码后运行非常慢
我有一个pygame / socket程序,它基本上是一个迷宫游戏,您必须在其中“标记”其他玩家,但是当我添加发送代码时,该程序的运行速度大大降低,该程序处于全屏状态,因此我添加了另一个套接字发送行以确保搜索器相同,然后停止快速运行。听到我的代码:
我的第一个目标:
import pygame
import time
import random
import socket
import struct
pygame.init()
s = socket.socket()
port = 12345
s.bind(('',port))
s.listen(5)
c,addr = s.accept()
print ("Socket Up and running with a connection from",addr)
screen = pygame.display.set_mode((0,0),pygame.FULLSCREEN)
blocks = [(50,50,200,25),(200,25,250),(300,(50,200),(250,100,250,(350,225,(75,325,(25,150,(100,75,100),375,175,425,75),500,450,150),(150,550,300,175),600,(0,400,650,(125,625,750,10000,28),(1350,16,10000),(225,125),(175,700,(275,125,50),(500,300),(400,225),(425,(450,275),500),(550,475),575,(325,(375,(475,(525,(600,525,(650,(850,475,675,(700,725,(900,(950,(800,275,(750,(875,350,(575,(925,(1025,(1050,(1125,375),(1075,(1175,(1150,(1300,(1250,(1000,(1100,(1200,25)
]
walls = [pygame.Rect(r) for r in blocks]
svel = 5
Hvel = 5
red = pygame.Rect(225,25)
blue = pygame.Rect(1100,25)
SeekChoice = random.randint(1,2)
if SeekChoice == 1:
seeker = "red"
Snum = 2
if SeekChoice == 2:
seeker = "blue"
Snum = 1
Num = 0
c.send(struct.pack("2i",SeekChoice,Num))
Redscore = 0
Bluescore = 0
RTime = 0
BTime = 0
running = True
font = pygame.font.Font(None,60)
RedWin = font.render("RED IS WINNER!",(255,0))
BlueWin = font.render("BLUE IS WINNER!",255))
while running:
buf = c.recv(8,socket.MSG_WAITALL)
struct.unpack("2i",buf)
x,y = struct.unpack("2i",buf)
red = pygame.Rect(x,y,25)
if Redscore >= 20:
screen.fill([255,255,255])
screen.blit(RedWin,[500,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
if Bluescore >= 20:
screen.fill([255,255])
screen.blit(BlueWin,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
RTime += 1
BTime += 1
x1 = red.x
y1 = red.y
x2 = blue.x
y2 = blue.y
if seeker == "red":
RTime = 0
elif RTime >= 2000:
RTime = 0
Redscore += 1
if seeker == "blue":
BTime = 0
elif BTime >= 2000:
BTime = 0
Bluescore += 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
blue.x = max(blue.x - svel,0)
for wall in walls:
if blue.colliderect(wall):
blue.left = max(blue.left,wall.right)
if keys[pygame.K_RIGHT]:
blue.x = min(blue.x + svel,1341)
for wall in walls:
if blue.colliderect(wall):
blue.right = min(blue.right,wall.left)
if keys[pygame.K_UP]:
blue.y = max(blue.y - svel,0)
for wall in walls:
if blue.colliderect(wall):
blue.top = max(blue.top,wall.bottom)
if keys[pygame.K_DOWN]:
blue.y = min(blue.y + svel,743)
for wall in walls:
if blue.colliderect(wall):
blue.bottom = min(blue.bottom,wall.top)
screen.fill([0,0])
#pygame.draw.circle(screen,[255,255],(x1+12,y1+12),125)
pygame.draw.circle(screen,(x2+12,y2+12),125)
for wall in walls:
pygame.draw.rect(screen,[0,0],wall)
#pygame.draw.rect(screen,red)
pygame.draw.rect(screen,blue)
if seeker == "red":
pygame.draw.rect(screen,(red.x+7,red.y+7,10,10))
if seeker == "blue":
pygame.draw.rect(screen,(blue.x+7,blue.y+7,10))
pygame.display.flip()
if red.colliderect(blue):
if seeker == "red":
print ("red/blue")
seeker = "blue"
Snum = 1
BTime = 0
Redscore += 2
Bluescore -= 3
red = pygame.Rect(225,25)
blue = pygame.Rect(1166,334,25)
elif seeker == "blue":
print ("blue/red")
Snum = 2
RTime = 0
seeker = "red"
Bluescore += 2
Redscore -= 3
red = pygame.Rect(225,25)
seeker2 = seeker.encode()
c.send(seeker2)
c.send(struct.pack("2i",blue.x,blue.y))
我的第二个目的:
import pygame
import time
import random
import socket
import struct
pygame.init()
s = socket.socket()
s.connect(('192.168.43.188',12345))
screen = pygame.display.set_mode((0,25)
]
walls = [pygame.Rect(r) for r in blocks]
svel = 5
Hvel = 5
red = pygame.Rect(225,25)
buf = s.recv(8,socket.MSG_WAITALL)
SeekChoice,Num = struct.unpack("2i",buf)
if SeekChoice == 1:
seeker = "red"
Snum = 1
if SeekChoice == 2:
seeker = "blue"
Snum = 2
Redscore = 0
Bluescore = 0
RTime = 0
BTime = 0
running = True
font = pygame.font.Font(None,255))
screen.fill([255,255])
pygame.draw.circle(screen,(red.x+12,red.y+12),75)
pygame.draw.circle(screen,(blue.x+12,blue.y+12),75)
for wall in walls:
pygame.draw.rect(screen,wall)
pygame.draw.rect(screen,red)
pygame.draw.rect(screen,blue)
if seeker == "red":
pygame.draw.rect(screen,10))
if seeker == "blue":
pygame.draw.rect(screen,10))
pygame.display.flip()
while running:
if Snum == 1:
seeker = "red"
if Snum == 2:
seeker = "blue"
s.send(struct.pack("2i",red.x,red.y))
if Redscore >= 20:
screen.fill([255,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
RTime += 1
BTime += 1
if seeker == "red":
RTime = 0
elif RTime >= 2000:
RTime = 0
Redscore += 1
if seeker == "blue":
BTime = 0
elif BTime >= 2000:
BTime = 0
Bluescore += 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
red.x = max(red.x - svel,0)
for wall in walls:
if red.colliderect(wall):
red.left = max(red.left,wall.right)
if keys[pygame.K_RIGHT]:
red.x = min(red.x + svel,1341)
for wall in walls:
if red.colliderect(wall):
red.right = min(red.right,wall.left)
if keys[pygame.K_UP]:
red.y = max(red.y - svel,0)
for wall in walls:
if red.colliderect(wall):
red.top = max(red.top,wall.bottom)
if keys[pygame.K_DOWN]:
red.y = min(red.y + svel,743)
for wall in walls:
if red.colliderect(wall):
red.bottom = min(red.bottom,0])
pygame.draw.circle(screen,125)
#pygame.draw.circle(screen,wall)
pygame.draw.rect(screen,red)
#pygame.draw.rect(screen,10))
pygame.display.flip()
seeker = s.recv(1024)
seeker = seeker.decode()
buf = s.recv(8,socket.MSG_WAITALL)
x,buf)
blue = pygame.Rect(x,25)
red = pygame.Rect(red.x,red.y,25)
感谢您的帮助。
解决方法
您的套接字处理代码(可能)是导致速度下降的原因。 socket.recv()
正在等待数据到达。当然,您可以将套接字设置为非阻塞读取,但是仍然存在是否已到达完整数据包的问题。
我会将您的代码转换为使用固定的数据包大小。与其发送可变长度的颜色名称,不如发送一个颜色元组。发送[250 250 210],然后发送“浅金黄色”要快得多;)我想您可以只使用[red ]
和[blue]
。
一旦您确定了数据包的大小,则可以准确地知道何时有新数据包到达,而不是说半个数据包。当然,对于本地网络上没有微小碎片的小数据包来说,这并不是真正的问题。但是数据量增加,网络拓扑发生变化,出现碎片。
我喜欢使用select
模块(紧密模拟同名的C系统函数)来知道是否有任何数据到达套接字,如果没有任何内容,则只需返回主程序循环。但是,如果有可用数据,则将任何内容读入缓冲区。这为您提供了一个程序模型,您可以在其中读取任何已到达的内容(大多数情况下什么都不读取),并且如果“到达的”缓冲区中有足够的字节,则取出足够的字节以形成完整的数据包。它简单,强大且运行良好。
给定功能:
import socket
import select
def socketReadIfAvailable( read_socket:socket.socket,packet_buffer:bytearray,amount:int=1,timeout:float=0 ):
""" Given an open socket,and a packet-buffer,return a packet if one is available.
Returns a tuple of:
None - if no packet is available
data-packet - (of <amount> bytes) if data is available (of <amount> bytes length)
-1 - if the socket has closed
AND the current packet-buffer """
result = None
# If we already have enough data buffered,don't re-fetch
if ( len( packet_buffer ) >= amount ):
bytes_read = packet_buffer[0:amount]
packet_buffer = packet_buffer[amount:]
result = bytes_read
else:
# There's not enough data,so try to read some,but only for <timeout> seconds
# if timeout is zero,just read whatever is sitting in the socket buffer already
read_events_on = [ read_socket ]
(read_list,write_list,except_list) = select.select( read_events_on,[],timeout )
if ( len( read_list ) > 0 ):
# New data arrived,read it
incoming = read_socket.recv( 8192 )
if ( len( incoming ) == 0 ):
# No data arrived,meaning the socket has closed
result = -1
else:
#print("%d bytes Rx'd" % ( len( incoming ) ) )
#print("%d bytes buffered" % ( len( packet_buffer ) ) )
packet_buffer += incoming # new bytes arrived,is there enough data now?
if ( len( packet_buffer ) >= amount ):
bytes_read = packet_buffer[0:amount]
packet_buffer = packet_buffer[amount:]
result = bytes_read
return result,packet_buffer
一个11字节的固定大小的数据包(RGB颜色为3字节,每个坐标为4字节),您的读取代码可能类似于:
packet_buffer = bytearray()
...
pygame.display.flip()
packet,packet_buffer = socketReadIfAvailable( s,packet_buffer,11 )
if ( packet != None ):
if ( packet == -1 ):
# TODO: handle Socket has closed
packet_buffer = bytearray() # clear buffer
else:
colour = struct.unpack( "!BBB",packet[0:3] ) # use network byte-order
x,y = struct.unpack( "!2i",packet[3:11] )
当然,如果您不想使用固定大小,则可以仅查看是否有任何数据到达,然后try:
对其进行解包(或整理),并希望获得最好的结果。不过,这效率相对较低。
编辑
通常我会尽量不成为免费的代码编写服务,但是我对有趣的外观原型游戏深信不疑;)
好吧,我不确定您的游戏应该如何运作。我发现整个red
和blue
变量集令人困惑。我认为您应该对代码进行重新设计,以使其具有不带GUI的单个服务器,而只是在客户端之间分流更新的位置。然后,您可以拥有一个游戏代码,其中两个玩家(或 N 玩家)都连接到该服务器。这也会从您的代码中删除red
与blue
VS x
,留下“本地”和“其他”(或您想称呼它们的任何东西)。
我修改了您的代码,使其仅在y
和import pygame
import time
import random
import socket
import struct
import select
network_buffer = bytearray()
def socketReadIfAvailable( read_socket:socket.socket,return a packet if one is available.
Returns a tuple of:
None - if no packet is available
data-packet - (of <amount> bytes) if data is available (of <amount> bytes length)
-1 - if the socket has closed
AND the current packet-buffer """
result = None
# If we already have enough data buffered,packet_buffer
pygame.init()
s = socket.socket()
port = 12345
s.bind(('',port))
s.listen(5)
c,addr = s.accept()
print ("Socket Up and running with a connection from",addr)
screen = pygame.display.set_mode( ( 1200,960 ) )
pygame.display.set_caption("Maze Server")
blocks = [(50,50,200,25),(200,25,250),(300,(50,200),(250,100,250,(350,225,(75,325,(25,150,(100,75,100),375,175,425,75),500,450,150),(150,550,300,175),600,(0,400,650,(125,625,750,10000,28),(1350,16,10000),(225,125),(175,700,(275,125,50),(500,300),(400,225),(425,(450,275),500),(550,475),575,(325,(375,(475,(525,(600,525,(650,(850,475,675,(700,725,(900,(950,(800,275,(750,(875,350,(575,(925,(1025,(1050,(1125,375),(1075,(1175,(1150,(1300,(1250,(1000,(1100,(1200,25)
]
x,y = 0,0
sent_x,sent_y = -1,-1
walls = [pygame.Rect(r) for r in blocks]
Svel = 5
Hvel = 5
red = pygame.Rect(225,25)
blue = pygame.Rect(1100,25)
SeekChoice = random.randint(1,2)
if SeekChoice == 1:
seeker = "red"
Snum = 2
if SeekChoice == 2:
seeker = "blue"
Snum = 1
Num = 0
c.send(struct.pack("2i",SeekChoice,Num))
RedScore = 0
BlueScore = 0
RTime = 0
BTime = 0
running = True
font = pygame.font.Font(None,60)
RedWin = font.render("RED IS WINNER!",(255,0))
BlueWin = font.render("BLUE IS WINNER!",255))
while running:
### Receive a fixed-size packet from the client (if any)
### Client only sends us an x,y
#buf = c.recv(8,socket.MSG_WAITALL)
buf,network_buffer = socketReadIfAvailable( s,network_buffer,8 ) # 8 bytes in a full packet
if ( buf != None ): # *IF* a packet was received
if ( buf == -1 ):
print( "Client disconnected" )
network_buffer = bytearray()
# TODO
else:
# A packet was received,unpack it
x,y = struct.unpack( "2i",buf ) # unpack the co-ordinates
print( "Rx: (%d,%d)" % ( x,y ) )
red = pygame.Rect(x,y,25)
if RedScore >= 20:
screen.fill([255,255,255])
screen.blit(RedWin,[500,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
if BlueScore >= 20:
screen.fill([255,255])
screen.blit(BlueWin,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
RTime += 1
BTime += 1
x1 = red.x
y1 = red.y
x2 = blue.x
y2 = blue.y
if seeker == "red":
RTime = 0
elif RTime >= 2000:
RTime = 0
RedScore += 1
if seeker == "blue":
BTime = 0
elif BTime >= 2000:
BTime = 0
BlueScore += 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
blue.x = max(blue.x - Svel,0)
for wall in walls:
if blue.colliderect(wall):
blue.left = max(blue.left,wall.right)
if keys[pygame.K_RIGHT]:
blue.x = min(blue.x + Svel,1341)
for wall in walls:
if blue.colliderect(wall):
blue.right = min(blue.right,wall.left)
if keys[pygame.K_UP]:
blue.y = max(blue.y - Svel,0)
for wall in walls:
if blue.colliderect(wall):
blue.top = max(blue.top,wall.bottom)
if keys[pygame.K_DOWN]:
blue.y = min(blue.y + Svel,743)
for wall in walls:
if blue.colliderect(wall):
blue.bottom = min(blue.bottom,wall.top)
screen.fill([0,0])
#pygame.draw.circle(screen,[255,255],(x1+12,y1+12),125)
pygame.draw.circle(screen,(x2+12,y2+12),125)
for wall in walls:
pygame.draw.rect(screen,[0,0],wall)
#pygame.draw.rect(screen,red)
pygame.draw.rect(screen,blue)
# if seeker == "red":
# pygame.draw.rect(screen,(red.x+7,red.y+7,10,10))
# if seeker == "blue":
# pygame.draw.rect(screen,(blue.x+7,blue.y+7,10))
pygame.draw.rect(screen,10))
pygame.display.flip()
if red.colliderect(blue):
if seeker == "red":
print ("red/blue")
seeker = "blue"
Snum = 1
BTime = 0
RedScore += 2
BlueScore -= 3
red = pygame.Rect(225,25)
blue = pygame.Rect(1166,334,25)
elif seeker == "blue":
print ("blue/red")
Snum = 2
RTime = 0
seeker = "red"
BlueScore += 2
RedScore -= 3
red = pygame.Rect(225,25)
### Pack and send the fixed-size data to the client
### But only if the position x,y has changed
if ( sent_x != blue.x or sent_y != blue.y ):
seeker_name = "%-12s" % ( seeker ) # pad to 12 spaces,this never changes,move outside loop
seeker_name = seeker_name.encode() # this too
c.send( bytes( seeker_name ) ) # send the colour-name padded to 12 letters
c.send( struct.pack("2i",blue.x,blue.y ) ) # send the x,y
sent_x = blue.x
sent_y = blue.y
print( "Tx: [%s],(%d,%d)" % ( seeker,sent_x,sent_y ) )
坐标更改时才发送位置。无需使用相同的不变坐标将网络垃圾邮件每秒60次。
还可以考虑添加注释,有时还可以在代码中添加空白行,这使跟踪变得更加容易。我将此添加到其中一个文件中。
服务器:
import pygame
import time
import random
import socket
import struct
pygame.init()
import select
network_buffer = bytearray()
def socketReadIfAvailable( read_socket:socket.socket,packet_buffer
s = socket.socket()
s.connect(('127.0.0.1',12345))
screen = pygame.display.set_mode( ( 1200,960 ) )
pygame.display.set_caption("Maze Client")
blocks = [(50,25)
]
sent_x,25)
buf = s.recv(8,socket.MSG_WAITALL)
SeekChoice,Num = struct.unpack("2i",buf)
if SeekChoice == 1:
seeker = "red"
Snum = 1
if SeekChoice == 2:
seeker = "blue"
Snum = 2
RedScore = 0
BlueScore = 0
RTime = 0
BTime = 0
running = True
font = pygame.font.Font(None,255))
#screen.fill([255,255])
#pygame.draw.circle(screen,(red.x+12,red.y+12),75)
#pygame.draw.circle(screen,(blue.x+12,blue.y+12),75)
#for wall in walls:
# pygame.draw.rect(screen,wall)
#pygame.draw.rect(screen,red)
#pygame.draw.rect(screen,blue)
#if seeker == "red":
# pygame.draw.rect(screen,10))
#if seeker == "blue":
# pygame.draw.rect(screen,10))
#pygame.display.flip()
while running:
# if Snum == 1:
# seeker = "red"
# if Snum == 2:
# seeker = "blue"
### Send the x,y position only if it's changed
if ( sent_x != red.x or sent_y != red.y ):
s.send(struct.pack("2i",red.x,red.y))
sent_x = red.x
sent_y = red.y
print( "Tx: (%d,%d)" % ( sent_x,sent_y ) )
if RedScore >= 20:
screen.fill([255,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
RTime += 1
BTime += 1
if seeker == "red":
RTime = 0
elif RTime >= 2000:
RTime = 0
RedScore += 1
if seeker == "blue":
BTime = 0
elif BTime >= 2000:
BTime = 0
BlueScore += 1
# Handle Events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
running = False
# Handle movement keys
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
red.x = max(red.x - Svel,0)
for wall in walls:
if red.colliderect(wall):
red.left = max(red.left,wall.right)
if keys[pygame.K_RIGHT]:
red.x = min(red.x + Svel,1341)
for wall in walls:
if red.colliderect(wall):
red.right = min(red.right,wall.left)
if keys[pygame.K_UP]:
red.y = max(red.y - Svel,0)
for wall in walls:
if red.colliderect(wall):
red.top = max(red.top,wall.bottom)
if keys[pygame.K_DOWN]:
red.y = min(red.y + Svel,743)
for wall in walls:
if red.colliderect(wall):
red.bottom = min(red.bottom,wall.top)
# Paint the screen
screen.fill([0,0])
pygame.draw.circle(screen,125)
#pygame.draw.circle(screen,wall)
pygame.draw.rect(screen,red)
#pygame.draw.rect(screen,10))
pygame.display.flip()
#seeker = s.recv(1024)
#seeker = seeker.decode()
#buf = s.recv(8,socket.MSG_WAITALL)
#x,y = struct.unpack("2i",buf)
### Receive a fixed-size packet from the server (if any)
### Server sends a 12-letter name,and x,y
buf,20 ) # 20 bytes in a full packet
if ( buf != None ): # *IF* a packet was received
if ( buf == -1 ):
print( "Client disconnected" )
network_buffer = bytearray()
# TODO
else:
# A packet was received,unpack it
seeker = buf[0:12].decode( "utf-8" ) # unpack the 12-letter (padded) name
seeker = seeker.strip()
x,buf[12:20] ) # unpack the co-ordinates
blue = pygame.Rect(x,25)
print( "Rx: [%s] at (%d,x,y ) )
red = pygame.Rect(red.x,red.y,25)
客户:
socketReadIfAvailable()
很显然,您可以将blocks
移到一个公共文件中,也许也移到class Manager:
def __init__(self,cls): self.cls=cls
# …
class PreManager:
def __get__(self,cls,obj): return Manager(cls)
class Model:
objects=PreManager()
中。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。