目前,我有一款使用socket
模块同步进行网络连接的游戏。
结构如下:
服务器:
while True:
add_new_clients()
process_game_state()
for client in clients:
send_data(client)
get_data_from(client)
客户端:
connect_to_server()
while True:
get_data_from_server()
process_game_state()
draw_to_screen()
send_input_to_server()
我想将网络代码替换为使用比socket
更高级别模块的网络代码,例如asyncio
或gevent。但是,我不知道该怎么做。
我见过的所有例子的结构都是这样的:
class Server:
def handle_client(self, connection):
while True:
input = get_input(connection)
output = process(input)
send(connection, output)
然后为每个加入的客户端使用线程或其他东西并行调用handle_client
。
如果可以单独处理客户端,则此工作正常。但是,我仍然希望保持游戏循环类型结构,其中处理仅在一种情况下发生 - 我不希望必须检查每个客户端的冲突等。我该怎么做?
答案 0 :(得分:2)
我假设您了解如何使用协议创建服务器以及异步范例如何工作。
您需要的只是将分解的事件循环转换为处理程序。
让我们看看服务器案例和客户案例:
您需要创建一个我们称之为协议的东西,它将用于创建服务器并充当每个实例=客户端的模式:
class ClientProtocol(asyncio.Protocol):
def connection_made(self, transport):
# Here, we have a new player, the transport represent a socket.
self.transport = transport
def data_received(self, data):
packet = decode_packet(data) # some function for reading packets
if packet.opcode == CMSG_MOVE: # opcode is a operation code.
self.player.move(packet[0]) # packet[0] is the first "real" data.
self.transport.write("OK YOUR MOVE IS ACCEPTED") # Send back confirmation or whatever.
好的,现在您已了解如何与客户合作。
之后,您需要每X ms处理一次游戏状态:
def processGameState():
# some code...
eventLoop.call_later(0.1, processGameState) # every 100 ms, processGameState is called.
在某些时候,你将在初始化时调用processGameState,它会告诉eventLoop在100毫秒之后调用processGameState(这可能不是理想的方式,但它是一个像另一个想法/强>)
至于向客户端发送新数据,您只需要存储ClientProtocol
的列表,并为每个传输写一个简单的。
显然删除了get_data_from,因为我们在data_received
的{{1}}方法中异步接收了所有数据。
这是如何将所有同步代码重构为异步代码的草图。您可能想要添加身份验证和其他一些事情,如果这是您第一次使用异步范例,我建议您尝试使用Twisted而不是asyncio:Twisted可能比asyncio(但是asyncio)更有记录和解释与Twisted完全相同,因此您可以每次都切换回来。
这里也差不多。
但是,您可能需要注意绘制方式以及如何管理输入。您可能需要最终使用另一个线程来调用输入处理程序,并使用另一个线程以恒定的帧速率绘制到屏幕。
在异步中思考起初非常困难。
但值得付出努力。
请注意,即使我的方法可能不是最好的或适合游戏。我只是觉得我会这样做,请花点时间测试你的代码并对其进行分析。 检查你是否在同一个函数中没有混合同步和异步代码而没有使用deferToThread(或其他帮助者)正确处理,它会销毁你游戏的表现< /强>