【问题标题】:Twisted clients within pygame mainloop?pygame主循环中的扭曲客户端?
【发布时间】:2012-09-05 01:49:42
【问题描述】:

我正在尝试使用 pygame-clients 运行一个扭曲的服务器:

class ChatClientProtocol(LineReceiver):
    def lineReceived(self,line):
        print (line)

class ChatClient(ClientFactory):
    def __init__(self):
        self.protocol = ChatClientProtocol

def main():
    flag = 0
    default_screen()
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
               return
            elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                pos = pygame.mouse.get_pos()
                # some rect.collidepoint(pos) rest of loop... 

这里是服务器:

from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor

class Chat(LineReceiver):
    def __init__(self, users, players):
        self.users = users
        self.name = None
        self.players = players

    def connectionMade(self):
        new = 'player_' + str(len(self.players) + 1)
        self.players.append(new)
        self.sendLine(str(self.players,))

class ChatFactory(Factory):
    def __init__(self):
        self.users = {} #maps instances to clients 
        self.players = []

    def buildProtocol(self, addr):
        return Chat(self.users,self.players)


reactor.listenTCP(6000, ChatFactory())
reactor.run()

我正在使用没有 reactor.CallLater() 方法和 pygames 代码的客户端代码运行此服务器,并且客户端连接良好。我使用 reactor 方法是错误的还是 pygames 代码在结构上存在问题?任何帮助将不胜感激。

所以我不知道 pygames 位中的循环是否会中断以再次调用反应器?

【问题讨论】:

  • 有什么不工作吗?你的问题在哪里?
  • 我将进行编辑以更彻底地解释。

标签: python twisted pygame main


【解决方案1】:

您应该在使用twisted 时编写自己的主循环(使用while)。 twisted 必须控制主循环,而 pygame 足够灵活,无需关心(它不需要自己的自己的循环)。

您应该将主循环中的所有内容放入一个函数中,并通过调用 reactor.CallLater() 将其与扭曲的反应器一起处理

def main():
    flag = 0
    default_screen()
    reactor.callLater(0.1, tick)

def tick():
   for event in pygame.event.get():
        if event.type == pygame.QUIT:
            reactor.stop() # just stop somehow
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            reactor.stop() # just stop somehow
        elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            pos = pygame.mouse.get_pos()
            # some stuff
   reactor.callLater(0.1, tick)

这样,您可以确保反应器运行并可以处理网络事件。


这是一个客户端的小工作示例,它将只呈现收到的最后一行:

from twisted.internet import reactor
from twisted.internet.protocol import ClientFactory
from twisted.protocols.basic import LineReceiver

import pygame

class ChatClientProtocol(LineReceiver):

    def __init__(self, recv):
        self.recv = recv

    def lineReceived(self,line):
        self.recv(line)

class ChatClient(ClientFactory):
    def __init__(self, recv):
        self.protocol = ChatClientProtocol
        self.recv = recv

    def buildProtocol(self, addr):
        return ChatClientProtocol(self.recv)

class Client(object):

    def __init__(self):
        self.line = 'no message'
        pygame.init()
        self.screen = pygame.display.set_mode((200, 200))
        reactor.callLater(0.1, self.tick)

    def new_line(self, line):
        self.line = line

    def tick(self):
        self.screen.fill((0,0,0))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                reactor.stop() # just stop somehow
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                reactor.stop() # just stop somehow
        self.screen.blit(pygame.font.SysFont('mono', 12, bold=True).render(self.line, True, (0, 255, 0)), (20,20))
        pygame.display.flip()
        reactor.callLater(0.1, self.tick)

if __name__ == '__main__':
    c = Client()
    reactor.connectTCP('127.0.0.1',6000, ChatClient(c.new_line))    
    reactor.run()

这是一个使用 LoopingCall 的简单示例,正如 Glyph 建议的那样(我省略了协议/工厂类,因为它们与上面相同):

from twisted.internet.task import LoopingCall

class Client(object):

    def __init__(self):
        self.line = 'no message'
        pygame.init()
        self.screen = pygame.display.set_mode((200, 200))

    def new_line(self, line):
        self.line = line

    def tick(self):
        self.screen.fill((0,0,0))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                reactor.stop() # just stop somehow
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                reactor.stop() # just stop somehow
        self.screen.blit(pygame.font.SysFont('mono', 12, bold=True).render(self.line, True, (0, 255, 0)), (20,20))
        pygame.display.flip()

if __name__ == '__main__':
    c = Client()

    lc = LoopingCall(c.tick)
    lc.start(0.1)
    reactor.connectTCP('127.0.0.1',6000, ChatClient(c.new_line))    
    reactor.run()

【讨论】:

  • 我应该在打勾和 main 之后打电话给reactor.run() 吗?我认为我需要启动它,或者这会阻止 main 和 tick 运行吗?因为没有它,pygame 屏幕会启动然后退出,并且 pygame 屏幕根本不会出现(所以 main 不会被调用)
  • 只需调用一次main()(或调用任何代码来初始化客户端)。重要的部分是 reactor.callLater(0.1, tick) 在你调用 reactor.run() 之前被调用一次。
  • 在调用main() 之后,我还需要运行reactor.ConnectTcp('192.168.1.2',6000, ChatClient())reactor.run 吗?我已经尝试过了,但是现在 pygames 事件没有响应?
  • 我被指出twisted.internet.task.Cooperator() 也是解决这个问题的好方法。
  • twisted.internet.task.LoopingCallCooperator 更接近您想要的。您想在帧之间放置一些实际时间 - Cooperator 假设如果您没有返回 Deferred 并且速度非常快,那么总会有更多工作要做。此外,LoopingCall 具有 withCount,它允许您缩放输入的大小(例如,如果用户按住“向上”4 帧,也许您想将它们移动 4 个像素)。
猜你喜欢
  • 2011-05-30
  • 2011-01-09
  • 1970-01-01
  • 1970-01-01
  • 2012-09-13
  • 2013-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多