gpt4 book ai didi

python - 多人游戏中的 Pygame 和套接字 : OverflowError

转载 作者:行者123 更新时间:2023-12-03 11:54:49 26 4
gpt4 key购买 nike

我正在尝试使用 pygame 在 Python 中创建一个简单的多人游戏和 socket模块。它只是由两个圆圈组成,由两台不同计算机的 W、A、S、D 键控制。
起初我用 recv() 创建了一个客户端。在 pygame 循环的中间。它运行良好,但 recv()阻塞了循环,所以圆圈的运动并不顺畅,我不得不将速度增加到 6(在设置为 0.6 之前)才能获得正常速度。这是代码(我已经总结了一下):
客户端第一版

#import modules

def main(sock):
pygame.init()

#Display screen and set initial me_x and me_y

vel = 0.6

while True:
keys_pressed = pygame.key.get_pressed()

#Change me_x and me_y (with A, D, W, S keys)

#Make sure me_x and me_y don't get off the screen

screen.fill(color)

if other_x and other_y:
pygame.draw.circle(screen, colorMe, (other_x, other_y), radi)

pygame.draw.circle(screen, colorOther, (int(me_x), int(me_y)), radi)

pygame.display.flip()

sock.send(int(me_x).to_bytes(3, byteorder = 'big') + int(me_y).to_bytes(3, byteorder = 'big'))

otherPos = sock.recv(BUFSIZ)

other_x = int.from_bytes(otherPos[:3], byteorder = 'big')
other_y = int.from_bytes(otherPos[3:], byteorder = 'big')
print(other_x, other_y)

#CONNECT TO TCP SOCKET

other_x = None
other_y = None

main(client_socket)
然后,我试着把 recv()在线程中停止阻塞循环:
客户端第二版
#import modules

def main(sock):
pygame.init()

#Display screen and set initial me_x and me_y

vel = 0.6

while True:
for i in range(30):
keys_pressed = pygame.key.get_pressed()

#Change me_x and me_y (with A, D, W, S keys)

#Make sure me_x and me_y don't get off the screen

screen.fill(color)

if other_x and other_y:
pygame.draw.circle(screen, colorOther, (other_x, other_y), 15)

pygame.draw.circle(screen, colorMe, (int(me_x), int(me_y)), 15)

pygame.display.flip()

msg = int(me_x).to_bytes(3, byteorder = 'big') + int(me_y).to_bytes(3, byteorder = 'big')
sock.send(msg)

def recv_pos(sock):
while True:
other_pos = sock.recv(BUFSIZ)
other_x = int.from_bytes(other_pos[:3], byteorder = 'big')
other_y = int.from_bytes(other_pos[3:], byteorder = 'big')

print(other_x, other_y)

#CONNECT TO TCP SOCKET

other_x = None
other_y = None

receive_thread = threading.Thread(target = recv_pos, args = (client_socket,))
receive_thread.daemon = True
receive_thread.start()

main(client_socket)
但是,当我在两台不同的计算机上启动客户端 2 的 2 个实例时,它给了我一个 OverflowError :

OverflowError: Python int too large to convert to C long


我添加了 for i in range(30):因为我认为服务器正在崩溃,因为同时发送的消息太多。输出是相同的:大约 3 秒后,程序崩溃并给出 OverflowError .
我添加了 print() recv() 之后的两个版本中的语句查看我收到的 x 和 y 的值。在第一个版本中,它们都在宽度和高度范围内。但是,在第 2 版中,收到的消息中有 1/5 是一个很大的数字,例如 124381473265。 .如果这个数字更大,它给出 OverflowError .我不明白为什么会这样:我在两个版本中都以相同的方式编码和解码消息,但是一个有效,另一个无效。
我不包括服务器代码,因为我认为没有必要。它只是在两个客户端之间传输消息而不修改它们。服务器不是错误,因为在第一个客户端版本中,消息被正确发送和接收。
任何帮助将不胜感激。如果您需要有关任何一点的更多信息,请告诉我。
提前致谢!

最佳答案

将您的套接字代码放入线程中,或使用 select.select()用于非阻塞套接字读取。然后当数据报从服务器到达时,将自定义事件消息发布回主循环。

import pygame
import enum

class NetworkEvents( enum.IntEnum ):
EVENT_HANGUP = pygame.USEREVENT + 1
EVENT_MESSAGE = pygame.USEREVENT + 2

您的套接字读取代码也应该处理部分数据包、挂断和延迟。我认为您上面的错误是由于尝试解包部分(或某种垃圾)数据包引起的。通常人们使用 pickle模块来封装这些数据,但首先,我会使用简单的字符串数据进行预测试。更容易调试。然后,一旦传输代码全部完成并经过测试,如有必要,请更改为二进制。

我喜欢用 select()无论如何,在我的套接字代码中。它对套接字发生的事情提供了细粒度的控制。

这是一个简单的线程套接字对话处理程序。它实际上只支持 socket-hangup 和传入消息。但它可以很容易地扩展以处理更多的消息类型。
import threading
import pygame
import random
import enum
import socket
import select
import time

class ConversationHandlerThread( threading.Thread ):
""" A thread that handles a conversation with a single remote server.
Accepts commands of 'close', 'red', 'green' or 'blue', and posts messages
to the main PyGame thread for processing """
def __init__( self, server_address, server_port ):
threading.Thread.__init__(self)
self.server_address = server_address
self.server_port = server_port
self.server_socket = None
self.data_buffer = ''
self.daemon = True # exit with parent
self.done = False

def stop( self ):
self.done = True

def connect( self ):
self.server_socket = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
while True:
try:
self.server_socket.connect( ( self.server_address, self.server_port ) )
print( "Connected to %s:%d" % ( self.server_address, self.server_port ) )
break;
except:
print( "Failed to connect %s:%d" % ( self.server_address, self.server_port ) )
time.sleep( 12 )
print( "Retrying..." )

def run( self ):
""" Connects to Server, then Loops until the server hangs-up """
self.connect()

# Now we're connected, start reading commands
read_events_on = [ self.server_socket ]
while ( not self.done ):
# Wait for incoming data, or errors, or 0.3 seconds
(read_list, write_list, except_list) = select.select( read_events_on, [], [], 0.5 )

if ( len( read_list ) > 0 ):
# New data arrived, read it
incoming = self.server_socket.recv( 8192 )
if ( len(incoming) == 0):
# Socket has closed
new_event = pygame.event.Event( NetworkEvents.EVENT_HANGUP, { "address" : self.server_address } )
pygame.event.post( new_event )
self.server_socket.close()
self.done = True
else:
# Data has arrived
try:
new_str = incoming.decode('utf-8')
self.data_buffer += new_str
except:
pass # don't understand buffer

# Parse incoming message (trivial parser, not high quality)
# commands are '\n' separated
if (self.data_buffer.find('\n') != -1 ):
for line in self.data_buffer.split('\n'):
line = line.strip()
# client disconnect command
if ( line == 'close' ):
new_event = pygame.event.Event( NetworkEvents.EVENT_HANGUP, { "address" : self.server_address } )
pygame.event.post( new_event )
self.server_socket.close()
self.done = True

# only make events for valid commands
elif ( line in ( 'red', 'green', 'blue' ) ):
new_event = pygame.event.Event( NetworkEvents.EVENT_MESSAGE, { "address" : self.server_address, "message" : line } )
pygame.event.post( new_event )
self.data_buffer = '' # all used-up

将所有这些复杂性放入线程的美妙之处在于,一旦开始,您就可以忘记它。
# Start the network-handler thread
thread1 = ConversationHandlerThread( '127.0.0.1', 5555 )
thread1.start()

在您的主循环中,像处理其他任何事件一样处理事件:
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True

elif ( event.type == NetworkEvents.EVENT_HANGUP ):
print(" CLIENT DISCONNECTED %s " % ( str(event.address) ) )

elif ( event.type == NetworkEvents.EVENT_MESSAGE ):
print(" CLIENT MESSAGE FROM %s - %s " % ( str(event.address), event.message ) )
if ( event.message == 'red' ):
new_sprite = AlienSprite( RED )
SPRITES.add( new_sprite )

关于python - 多人游戏中的 Pygame 和套接字 : OverflowError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60884259/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com