6

I'm trying to run a twisted-server with 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... 

And here is the server:

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() 

I'm running this server with the client code with out the reactor.CallLater() method and pygames code and the client connects fine. Am I using the reactor method wrong or is there something structurally wrong with the pygames code? Any help would be appreciated.

So I don't know if the loop within the pygames bit ever breaks to call the reactor again?

2
  • Is something not working? Where's your problem? Commented Sep 12, 2012 at 6:09
  • I'll edit to explain more throughly. Commented Sep 12, 2012 at 6:14

1 Answer 1

8

You should not write your own main loop (with while) when using twisted. twisted has to control the main loop, and pygame is flexible enough to not care about (it does not need its own loop).

You should put everything which is inside your main loop into a function, and shedule it with the twisted reactor by calling 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) 

This way, you ensure the reactor runs and can handle network events.


Here's a small working example of a client that will just render the last line recieved:

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() 

Here's a simple example using LoopingCall, as Glyph suggested (I left out the protocoll/factory classes as they're the same as above):

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() 
Sign up to request clarification or add additional context in comments.

7 Comments

Should I be calling reactor.run() after the tick and main? I thought I needed to start it up or will this prevent main and tick from ever running? Because with out it the pygame screen starts then exits and with it the pygame screen doesn't come up at all( so the main isn't being called)
Just call main() once (or whatever code you call to initialize your client). The important part is that reactor.callLater(0.1, tick) is called once before you call reactor.run().
I still need to run reactor.ConnectTcp('192.168.1.2',6000, ChatClient()) and reactor.run after the main() call? I've gone ahead and tried this but, now the pygames events aren't responding?
I was pointed to twisted.internet.task.Cooperator() as good way of going about this, as well.
twisted.internet.task.LoopingCall is closer to what you want than Cooperator. You want to put some actual time between frames - Cooperator assumes there's always more work to do if you didn't return a Deferred and goes very fast. Also, LoopingCall has withCount, which allows you to scale the magnitude of your input (like, if the user held down 'up' for 4 frames, maybe you want to move them 4 pixels).
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.