twisted pygame

Perspective Broker

Für mein erstes Netzwerkspiel (ok, Spiel ist vielleicht etwas übertrieben) habe ich zunächst ein kleines Spiel geschrieben, bei dem es zwei Objekte gibt. Jeder Spieler kann eines dieser Objekte bewegen, wobei es hier erstmal nur einen Spieler gibt, das andere Objekt ist quasi tot.

Im nächsten Schritt habe ich die Netzwerkfunktionalität in einer weiteren Datei implementiert. Als Ausgangspunkt habe ich dieses Pseudoscript genommen. Und nun kommt der interessante (und auch unsaubere) Teil. Die Klasse PygameTimer funktioniert sowohl als Server als auch als Client, je nach gesetztem START_SERVER Flag. Der Server ist in diesem Falle passiv und stellt nur Methoden bereit, über die der Client dann aktiv Daten abfragen und setzen kann.

Hier mein erster Code, der noch sehr zusammengahackt und unsauber ist:

simple_game.py

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/env python
# coding: utf-8
"""
My first test with pygame and twisted
game part

(cc) by Julian Habrock, 23.1.09
bytemuehle.de
"""

import sys, pygame, time, os
from pygame.locals import *


BG_COLOR = (0, 0, 0)

def load_image(name, colorkey=None):
    fullname = name#os.path.join('data', name)
    try:
        image = pygame.image.load(fullname)
    except pygame.error, message:
        print 'Cannot load image:', fullname
        raise SystemExit, message
    image = image.convert()
    if colorkey is not None:
        if colorkey is -1:
            colorkey = image.get_at((0,0))
            print "colorkey: ", colorkey
        image.set_colorkey(colorkey, RLEACCEL)
    return image, image.get_rect()


class Player(pygame.sprite.Sprite):
    """
    Simple game object
    you can move your player (self.local == True) between 2 positions with
    the "<-" and "->" keys
    """
    positions = {"left":100, "right":540}
    colors = {"red":(199, 3, 3), "green":(1, 243, 1)}
    rows = {"top":150, "bottom":250}
    def __init__(self, pos, color, row, local=0):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect  = load_image("player.gif", -1)
        pxarray = pygame.PixelArray(self.image)
        pxarray.replace((255, 0, 0), self.colors[color])
        self.image = pxarray.make_surface()
        self.image.set_colorkey(self.image.get_at((0,0)), RLEACCEL)
        self.image.convert()
        self.position = pos
        self.row = row
        self.rect.centery = self.rows[row]
        self.local = local

    def update(self, events):
        if self.local:
            for event in events:
                if event.type == KEYDOWN:
                    if event.key == K_LEFT:
                        self.position = "left"
                    elif event.key == K_RIGHT:
                        self.position = "right"
                    else:
                        print event.key
        self.rect.centerx = self.positions[self.position]



class Game():
    def __init__(self):

        pygame.init()
        self.screen = pygame.display.set_mode((640, 400))
        pygame.display.set_caption('title')
        pygame.mouse.set_visible(1)

    #Create The Backgound
        self.background = pygame.Surface(self.screen.get_size())
        self.background = self.background.convert()
        #background.fill((250, 250, 250))
        self.background.fill(BG_COLOR)


    #Put Text On The Background, Centered
        if pygame.font:
            font = pygame.font.Font(None, 36)
            text = font.render("twisted pygame", 1, (10, 10, 10))
            textpos = text.get_rect(centerx=self.background.get_width()/2)
            self.background.blit(text, textpos)

    #Display The Background
        self.screen.blit(self.background, (0, 0))
        pygame.display.flip()

    #Prepare Game Objects

        self.clock = pygame.time.Clock()
    #    boom_sound = load_sound('boom.wav')


        self.allsprites = pygame.sprite.RenderPlain()

        self.player = Player("right", "green", "bottom", 1)
        self.player2 = Player("left", "red", "top")
        self.allsprites.add(self.player, self.player2)
        self.running = True



    def update(self):
        #Handle Input Events
        events = pygame.event.get()
        for event in events:
            if event.type == QUIT:
                self.running = False
            elif event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    self.running = False

        self.allsprites.update(events)

    #Draw Everything
        self.screen.blit(self.background, (0, 0))
        self.allsprites.draw(self.screen)
        pygame.display.flip()


def main():
    """this function is called when the program starts.
       it initializes everything it needs, then runs in
       a loop until the function returns."""
#Initialize Everything
    game = Game()


#Main Loop
    while 1:
        game.clock.tick(100)
        game.update()
        if not game.running:
            break

    #Game Over


#this calls the 'main' function when this script is executed
if __name__ == '__main__': main()

twisted_game.py

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/env python
# coding: utf-8
"""
My first test with pygame and twisted
network part

(c) by Julian Habrock, 23.1.09
bytemuehle.de
"""

import sys

from pygame import time

from twisted.internet import reactor
from twisted.spread import pb

import simple_game

help1 = """
twisted PyGame
================
usage:
$python twisted_game.py [arg]

arg must be one of:
'server' or 's' to start the server
'client' or 'c' to start the client

-----------
(c) by Julian Habrock
bytemuehle.de"""

help2 = """
arg must be one of:
'server' or 's' to start the server
'client' or 'c' to start the client
"""

if len(sys.argv) != 2:
    print help1
    START_SERVER = None
else:
    arg = sys.argv[1]
    if arg in ("server", "s"):
        START_SERVER = True
    elif arg in ("client", "c"):
        START_SERVER = False
    else:
        print help2
        START_SERVER = None

def clientfunc(func):
    def dummy(*args):pass
    if not START_SERVER:
        return func
    else: return dummy

def serverfunc(func):
    def dummy(*args):pass
    if not START_SERVER:
        return dummy
    else: return func

class PygameTimer(pb.Root):
    def __init__(self, factory=None):
        self.clock = time.Clock()
        self.game = simple_game.Game()
        self.factory = factory
        if not START_SERVER:
            assert self.factory != None
        self.update_game()

    def update_game(self):
        """
        replaces the pygame event loop
        """
#        self.clock.tick()
#        self.ms = self.clock.get_rawtime()

#        framespeed = (1.0/100.0) * 1000
#        lastspeed = self.ms
#        next = framespeed - lastspeed

#        print "framespeed", framespeed, "ms", self.ms, "next", next, "fps",\
#                                                         self.clock.get_fps()
        self.get_pos()
        self.game.update()
        self.send_pos()


        if self.game.running:
            reactor.callLater(0.05, self.update_game)
        else:
            reactor.stop()


    def setpos(self, pos):
        self.game.player2.position = pos

    def dummy(self, *args):
        print "dummy: ", args


    # CLIENT PART
    @clientfunc
    def send_pos(self):
        d = factory.getRootObject()
        d.addCallback(lambda object: object.callRemote('setpos',
                                                    self.game.player.position))

    @clientfunc
    def get_pos(self):
        d = factory.getRootObject()
        d.addCallback(lambda object: object.callRemote('getpos'))
        d.addCallback(self.setpos)


    # SERVER PART
    @serverfunc
    def remote_getpos(self):
        #print 'getdir'
        return self.game.player.position

    @serverfunc
    def remote_setpos(self, new_pos):
        #print "setting position: ", new_pos
        self.game.player2.position = new_pos
        return True



if __name__ == '__main__' and START_SERVER is not None:
    if START_SERVER:
        pt = PygameTimer()
        reactor.listenTCP(8789, pb.PBServerFactory(pt))
    else:
        factory = pb.PBClientFactory()
        pt = PygameTimer(factory)
        reactor.connectTCP("localhost", 8789, factory)
    reactor.run()

Player.gif

http://media.bytemuehle.de/downloads/twisted_pygame/player.gif
tags: Netzwerkprogrammierung & Twisted erstellt am 30.1.2009 20:20, zuletzt gendert am 30.1.2009 20:20