Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added networking example

  • Loading branch information...
commit 1788a53484e32e07112e059082422982ff7946cb 1 parent 1e9c166
@alecgoebel alecgoebel authored
Showing with 1,243 additions and 0 deletions.
  1. +6 −0 samplecode/networking_example/client.py
  2. 0  samplecode/networking_example/coinget/__init__.py
  3. +1 −0  samplecode/networking_example/coinget/client/__init__.py
  4. +96 −0 samplecode/networking_example/coinget/client/app.py
  5. +49 −0 samplecode/networking_example/coinget/client/client.py
  6. +48 −0 samplecode/networking_example/coinget/client/controller.py
  7. +72 −0 samplecode/networking_example/coinget/client/game.py
  8. +91 −0 samplecode/networking_example/coinget/client/network.py
  9. +2 −0  samplecode/networking_example/coinget/client/sprites/__init__.py
  10. +33 −0 samplecode/networking_example/coinget/client/sprites/coin.py
  11. +36 −0 samplecode/networking_example/coinget/client/sprites/player.py
  12. +7 −0 samplecode/networking_example/coinget/graphics/__init__.py
  13. +65 −0 samplecode/networking_example/coinget/graphics/anim.py
  14. +21 −0 samplecode/networking_example/coinget/graphics/layer.py
  15. +40 −0 samplecode/networking_example/coinget/graphics/shadows.py
  16. +24 −0 samplecode/networking_example/coinget/graphics/spritesheet.py
  17. +60 −0 samplecode/networking_example/coinget/graphics/text.py
  18. +31 −0 samplecode/networking_example/coinget/graphics/tile.py
  19. 0  samplecode/networking_example/coinget/network/__init__.py
  20. +33 −0 samplecode/networking_example/coinget/network/clock.py
  21. +3 −0  samplecode/networking_example/coinget/network/cmd/__init__.py
  22. +33 −0 samplecode/networking_example/coinget/network/cmd/coin.py
  23. +60 −0 samplecode/networking_example/coinget/network/cmd/player.py
  24. +45 −0 samplecode/networking_example/coinget/network/cmd/world.py
  25. +21 −0 samplecode/networking_example/coinget/rand.py
  26. +1 −0  samplecode/networking_example/coinget/server/__init__.py
  27. +45 −0 samplecode/networking_example/coinget/server/environment.py
  28. +85 −0 samplecode/networking_example/coinget/server/network.py
  29. +29 −0 samplecode/networking_example/coinget/server/server.py
  30. +13 −0 samplecode/networking_example/coinget/settings.py
  31. +16 −0 samplecode/networking_example/coinget/signals.py
  32. +3 −0  samplecode/networking_example/coinget/world/__init__.py
  33. +28 −0 samplecode/networking_example/coinget/world/coin.py
  34. +25 −0 samplecode/networking_example/coinget/world/obj.py
  35. +49 −0 samplecode/networking_example/coinget/world/player.py
  36. +64 −0 samplecode/networking_example/coinget/world/world.py
  37. BIN  samplecode/networking_example/images/coin.bmp
  38. BIN  samplecode/networking_example/images/grass.bmp
  39. BIN  samplecode/networking_example/images/logo.bmp
  40. BIN  samplecode/networking_example/images/mario.bmp
  41. +8 −0 samplecode/networking_example/server.py
  42. BIN  samplecode/networking_example/sounds/coin.ogg
  43. BIN  samplecode/networking_example/sounds/music/maintheme.ogg
  44. BIN  samplecode/networking_example/sounds/music/title.ogg
  45. BIN  samplecode/networking_example/sounds/pause.ogg
View
6 samplecode/networking_example/client.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+
+from coinget.client import GameClient, Options
+
+options = Options(); options.parseOptions()
+GameClient(options).start()
View
0  samplecode/networking_example/coinget/__init__.py
No changes.
View
1  samplecode/networking_example/coinget/client/__init__.py
@@ -0,0 +1 @@
+from client import GameClient, Options
View
96 samplecode/networking_example/coinget/client/app.py
@@ -0,0 +1,96 @@
+import inspect
+
+from louie import dispatcher
+import pygame
+from pygame.locals import *
+
+
+from coinget import signals
+from coinget.network.clock import SimulationClock
+
+
+class Application(SimulationClock):
+ framerate = 60
+ state = None
+
+ def __init__(self, state=None):
+ SimulationClock.__init__(self, framerate=self.framerate)
+ self.screen = pygame.display.get_surface()
+
+ # initialize base state
+ if state is None:
+ state = Application.State
+
+ self.set_state(state)
+
+ # connect signals
+ dispatcher.connect(self.quit, sender=self, signal=signals.QUIT)
+
+ def quit(self):
+ self.stop()
+
+ def set_state(self, state):
+ if self.state:
+ self.state.pause()
+
+ if inspect.isclass(state):
+ state = state(self)
+
+ state.resume()
+ self.state = state
+
+
+ def advance(self, dt):
+ for event in pygame.event.get():
+ if event.type == QUIT:
+ dispatcher.send(signal=signals.QUIT, sender=self)
+ else:
+ self.state.handle_event(event)
+
+ self.state.update(dt)
+ self.state.draw(self.screen)
+ pygame.display.flip()
+
+
+ class State(object):
+ def __init__(self, app):
+ self.app = app
+ self.setup()
+
+ def setup(self): pass
+ def pause(self): pass
+ def resume(self): pass
+ def handle_event(self, event): pass
+ def update(self, dt): pass
+ def draw(self, screen): pass
+
+"""
+class GameApp(World):
+ fps = 1
+
+ def __init__(self):
+ World.__init__(self, framerate=self.fps)
+
+ pygame.init()
+ self.screen = pygame.display.set_mode((600, 600))
+
+ self.background = TiledImage(load_image("grass"))
+
+
+ def quit(self):
+ self.stop()
+ pygame.quit()
+
+ def draw(self, screen):
+
+ self.background.draw(screen)
+
+ def advance(self, dt):
+ for event in pygame.event.get():
+ if event.type == QUIT:
+ dispatcher.send(signal=signals.QUIT)
+
+ World.advance(self, dt)
+ self.draw(self.screen)
+ pygame.display.flip()
+"""
View
49 samplecode/networking_example/coinget/client/client.py
@@ -0,0 +1,49 @@
+from twisted.internet import reactor
+from twisted.internet.endpoints import TCP4ClientEndpoint
+from twisted.python import usage
+
+import pygame
+
+from coinget import settings
+
+from app import Application
+from game import ConnectingState
+from network import NetworkControllerFactory
+
+
+class Options(usage.Options):
+ optParameters = [
+ ("port", "p", settings.DEFAULT_PORT, "TCP port", usage.portCoerce),
+ ("nick", "n", "Anon", "Nickname"),
+ ("addr", "s", "localhost", "Server address")
+ ]
+
+
+class GameClient(Application):
+ def __init__(self, options):
+ pygame.init()
+ pygame.display.set_mode(settings.SCREEN_SIZE)
+ pygame.display.set_caption(settings.CAPTION)
+
+ self.nick = options["nick"]
+ self.addr = options["addr"]
+ self.port = options["port"]
+
+ self.factory = NetworkControllerFactory(self)
+ Application.__init__(self, ConnectingState)
+
+
+ def connect(self, callback=None):
+ endpt = TCP4ClientEndpoint(reactor, self.addr, self.port)
+ d = endpt.connect(self.factory)
+ if callback:
+ d.addCallback(callback)
+
+ def start(self):
+ Application.start(self)
+ reactor.run()
+
+ def quit(self):
+ Application.quit(self)
+ pygame.quit()
+ reactor.stop()
View
48 samplecode/networking_example/coinget/client/controller.py
@@ -0,0 +1,48 @@
+from louie import dispatcher
+import pygame
+from pygame.locals import *
+
+from coinget import signals
+
+class PlayerController(object):
+ _watched = [ K_UP, K_LEFT, K_RIGHT, K_DOWN ]
+ def __init__(self, player):
+ self.player = player
+ self._pressed = {}
+
+ def handle_event(self, event):
+ if event.type == KEYDOWN:
+ self.on_keydown(event)
+ elif event.type == KEYUP:
+ self.on_keyup(event)
+
+ def on_keydown(self, event):
+ if event.key in self._watched:
+ self._pressed[event.key] = True
+ self.update()
+
+ def on_keyup(self, event):
+ if event.key in self._watched:
+ self._pressed[event.key] = False
+ self.update()
+
+ def update(self):
+ if self._pressed.get(K_LEFT) and self._pressed.get(K_RIGHT):
+ x = 0
+ elif self._pressed.get(K_LEFT):
+ x = -1
+ elif self._pressed.get(K_RIGHT):
+ x = 1
+ else:
+ x = 0
+
+ if self._pressed.get(K_UP) and self._pressed.get(K_DOWN):
+ y = 0
+ elif self._pressed.get(K_UP):
+ y = -1
+ elif self._pressed.get(K_DOWN):
+ y = 1
+ else:
+ y = 0
+
+ dispatcher.send(signal=signals.MOVE_PLAYER, sender=self.player, x=self.player.x, y=self.player.y, vx=x, vy=y)
View
72 samplecode/networking_example/coinget/client/game.py
@@ -0,0 +1,72 @@
+from louie import dispatcher
+import pygame
+
+from coinget import signals
+
+from app import Application
+from controller import PlayerController
+from sprites import *
+
+class ConnectingState(Application.State):
+ text = "Connecting..."
+ fg = 255,255,255
+ bg = 0,0,0
+
+ def setup(self):
+ font = pygame.font.Font(None, 50)
+ self.text = font.render(self.text, True, self.fg, self.bg)
+
+ self.app.connect(self.connected)
+
+ def connected(self, protocol):
+ dispatcher.connect(self.ready, signal=signals.READY, sender=protocol)
+
+ def ready(self, sender):
+ player = sender.player
+ world = sender.world
+ network = sender
+
+ state = GameState(self.app, player, world, network)
+ self.app.set_state(state)
+
+
+ def draw(self, screen):
+ screen.fill(self.bg)
+ rect = self.text.get_rect()
+ bounds = screen.get_rect()
+ rect.center = bounds.center
+ screen.blit(self.text, rect)
+
+
+class GameState(Application.State):
+ def __init__(self, app, player, world, network):
+ self.world = world
+ self.network = network
+ self.player = player
+
+ self.controller = PlayerController(player)
+
+ Application.State.__init__(self, app)
+
+ def setup(self):
+ self.coins = CoinGroup()
+ for coin in self.world.coins:
+ self.coins.add_sprite(coin)
+
+ self.players = PlayerGroup()
+ for player in self.world.players:
+ self.players.add_sprite(player)
+
+ def handle_event(self, event):
+ self.controller.handle_event(event)
+
+ def update(self, dt):
+ self.world.update(dt)
+
+ self.players.update()
+ self.coins.update()
+
+ def draw(self, screen):
+ screen.fill((80,80,80))
+ self.coins.draw(screen)
+ self.players.draw(screen)
View
91 samplecode/networking_example/coinget/client/network.py
@@ -0,0 +1,91 @@
+from louie import dispatcher
+
+from twisted.internet.protocol import ReconnectingClientFactory
+from twisted.protocols import amp
+
+from coinget import signals
+from coinget.network import cmd
+from coinget.world import World, Coin, Player
+
+class NetworkController(amp.AMP):
+ world = None
+
+ def __init__(self, nick):
+ self.nick = nick
+ dispatcher.connect(self.quit, signal=signals.QUIT)
+ dispatcher.connect(self.move_player, signal=signals.MOVE_PLAYER)
+
+ def connectionMade(self):
+ self.sync_world()
+
+ def connectionLost(self, reason):
+ print "Connection with server has been lost"
+
+ def quit(self, sender, signal):
+ if sender is not self:
+ self.transport.loseConnection()
+
+ def create_player(self):
+ d = self.callRemote(cmd.CreatePlayer, nick=self.nick)
+ d.addCallback(self.player_created)
+ return d
+
+ def player_created(self, result):
+ self.player = result["player"]
+ self.world.add(self.player)
+ self.ready()
+
+ def move_player(self, sender, x, y, vx, vy):
+ # only send off if we actually have control
+ if sender is self.player:
+ self.callRemote(cmd.MovePlayer, identifier=sender.identifier, x=x, y=y, vx=vx, vy=vy)
+
+ @cmd.MovePlayer.responder
+ def player_moved(self, identifier, x, y, vx, vy):
+ player = self.world.get(identifier)
+ dispatcher.send(signal=signals.MOVE_PLAYER, sender=player, x=x, y=y, vx=vx, vy=vy)
+ return {}
+
+
+ def sync_world(self):
+ self.callRemote(cmd.SyncWorld).addCallback(self.load_world)
+
+ def load_world(self, result):
+ self.world = World()
+ for obj in result["objects"]:
+ self.world.add(obj)
+ self.world.time = result["time"]
+ self.create_player()
+
+ def ready(self):
+ dispatcher.send(signal=signals.READY, sender=self)
+
+ @cmd.AddCoin.responder
+ def add_coin(self, coin):
+ self.world.add(coin)
+ return {}
+
+ @cmd.AddPlayer.responder
+ def add_player(self, player):
+ self.world.add(player)
+ return {}
+
+ @cmd.RemoveObject.responder
+ def remove_object(self, identifier):
+ self.world.remove(identifier)
+ return {}
+
+class NetworkControllerFactory(ReconnectingClientFactory):
+ def __init__(self, app):
+ self.app = app
+
+ def buildProtocol(self, addr):
+ # create a new world for the appstate once connceted
+
+ print "Connected"
+ self.resetDelay()
+ return NetworkController(self.app.nick)
+
+ # close down reactor on disconnect
+# def clientConnectionLost(self, connector, reason):
+# dispatcher.send(signal=signals.QUIT, sender=connector)
View
2  samplecode/networking_example/coinget/client/sprites/__init__.py
@@ -0,0 +1,2 @@
+from player import PlayerGroup
+from coin import CoinGroup
View
33 samplecode/networking_example/coinget/client/sprites/coin.py
@@ -0,0 +1,33 @@
+from louie import dispatcher
+
+import pygame
+from pygame.sprite import Sprite, Group
+
+from coinget import signals
+from coinget.world import Coin
+
+
+class CoinSprite(Sprite):
+ def __init__(self, coin):
+ Sprite.__init__(self)
+
+ self.image = pygame.Surface(coin.rect.size)
+ self.rect = self.image.get_rect()
+
+ self.image.fill((0,0,0))
+ self.image.fill((255,255,0), self.rect.inflate(-4,-4))
+
+ self.rect.center = coin.rect.center
+
+ self.coin = coin
+ dispatcher.connect(self.kill, signal=signals.DEL_OBJECT, sender=coin)
+
+
+class CoinGroup(Group):
+ def __init__(self):
+ Group.__init__(self)
+
+ dispatcher.connect(self.add_sprite, signal=signals.NEW_OBJECT, sender=Coin)
+
+ def add_sprite(self, obj):
+ self.add(CoinSprite(obj))
View
36 samplecode/networking_example/coinget/client/sprites/player.py
@@ -0,0 +1,36 @@
+from louie import dispatcher
+
+import pygame
+from pygame.sprite import Sprite, Group
+
+from coinget import signals
+from coinget.world import Player
+
+
+class PlayerSprite(Sprite):
+ def __init__(self, player):
+ Sprite.__init__(self)
+
+ self.image = pygame.Surface(player.rect.size)
+ self.rect = self.image.get_rect()
+
+ self.image.fill((0,0,0))
+ self.image.fill(player.color, self.rect.inflate(-4,-4))
+
+ self.rect.center = player.rect.center
+
+ self.player = player
+ dispatcher.connect(self.kill, signal=signals.DEL_OBJECT, sender=player)
+
+ def update(self):
+ self.rect.center = self.player.rect.center
+
+
+class PlayerGroup(Group):
+ def __init__(self):
+ Group.__init__(self)
+
+ dispatcher.connect(self.add_sprite, signal=signals.NEW_OBJECT, sender=Player)
+
+ def add_sprite(self, obj):
+ self.add(PlayerSprite(obj))
View
7 samplecode/networking_example/coinget/graphics/__init__.py
@@ -0,0 +1,7 @@
+from anim import Animation
+from layer import Layer
+from shadows import ShadowLayer
+from spritesheet import SpriteSheet
+from text import TextBlock
+from tile import TiledImage
+
View
65 samplecode/networking_example/coinget/graphics/anim.py
@@ -0,0 +1,65 @@
+from functools import partial
+
+class AnimationFrames(object):
+ def __init__(self, frames, loops=-1):
+ self._times = []
+ self._data = []
+ total = 0
+ for t, data in frames:
+ total += t
+ self._times.append(total)
+ self._data.append(data)
+
+ self.end = total
+ self.loops = loops
+
+
+ def get(self, time):
+ # if looping forever or within the number of loops, wrap time
+ if self.loops == -1 or time < self.loops * self.end:
+ time %= self.end
+
+ # return last frame if we've gone too far
+ if time > self.end:
+ return self._data[-1]
+
+ # otherwise loop until we get the right frame
+ idx = 0
+ while self._times[idx] < time:
+ idx += 1
+
+ return self._data[idx]
+
+
+def _get_anim_frame(var, obj):
+ return getattr(obj, var).get_current_frame()
+
+
+class Animation(object):
+ def __init__(self, spritesheet, frames):
+ if not isinstance(frames, AnimationFrames):
+ frames = AnimationFrames(frames)
+
+ self.spritesheet = spritesheet
+ self.frames = frames
+ self.time = 0
+ self.update(0)
+
+ def get_frame_data(self, time):
+ return self.frames.get(time)
+
+ def get_current_frame(self):
+ return self.spritesheet.get(self.col, self.row)
+
+ def update(self, dt):
+ self.time += dt
+ self.row, self.col = self.get_frame_data(self.time)
+
+ @staticmethod
+ def frameproperty(var):
+ return property(partial(_get_anim_frame, var))
+
+
+ @property
+ def frame(self):
+ return self.get_current_frame()
View
21 samplecode/networking_example/coinget/graphics/layer.py
@@ -0,0 +1,21 @@
+import pygame
+from pygame import Surface
+
+
+class Layer(object):
+
+ def __init__(self, size):
+ self._layer = Surface(size, pygame.SRCALPHA)
+
+ def clear(self):
+ self._layer.fill((0,0,0,0))
+
+ def draw_sprites(self, sprites):
+ for sprite in sprites:
+ self.draw_sprite(sprite)
+
+ def draw_sprite(self, sprite):
+ self._layer.blit(sprite.image, sprite.rect)
+
+ def draw(self, surf, loc=(0,0)):
+ surf.blit(self._layer, loc)
View
40 samplecode/networking_example/coinget/graphics/shadows.py
@@ -0,0 +1,40 @@
+import pygame
+from pygame import Rect, Surface
+
+from layer import Layer
+
+class ShadowLayer(Layer):
+
+ color = 0,0,0,150
+ ratio = 3.0 / 4.0
+
+ def draw_sprite(self, sprite, ratio=None):
+ if ratio is None:
+ ratio = self.ratio
+
+ # calculate the size of the shadow
+ w = sprite.rect.width * ratio + 1
+ h = w/2
+ rect = Rect(0,0,w,h)
+
+ # shrink the shadow according to height
+ if hasattr(sprite, "height"):
+ height0 = sprite.__class__.height
+ ratio = (height0 - sprite.height) / float(height0)
+ rect.width = max(8, rect.width * ratio)
+ rect.height = max(4, rect.height * ratio)
+
+ # move the the midbottom of the sprite
+ rect.center = sprite.rect.midbottom
+ rect.x -= 1
+ rect.y -= 3
+
+ # if the sprite has a height property, use it to move the shadow
+ if hasattr(sprite, "height"):
+ rect.y += sprite.height
+
+
+ # draw to the layer
+ pygame.draw.ellipse(self._layer, self.color, rect)
+# self._layer.fill(self.color, rect)
+
View
24 samplecode/networking_example/coinget/graphics/spritesheet.py
@@ -0,0 +1,24 @@
+class SpriteSheet(object):
+ def __init__(self, image, dimensions, colorkey=-1):
+
+ # load the image
+ if colorkey == -1:
+ colorkey = image.get_at((0,0))
+
+ if colorkey:
+ image.set_colorkey(colorkey)
+
+ cols, rows = dimensions
+ w = self.width = 1.0 * image.get_width() / cols
+ h = self.height = 1.0 * image.get_height() / rows
+
+ # build the images
+ self._images = []
+ for y in range(rows):
+ row = []
+ for x in range(cols):
+ row.append(image.subsurface((x*w, y*h, w, h)))
+ self._images.append(row)
+
+ def get(self, x, y):
+ return self._images[y][x]
View
60 samplecode/networking_example/coinget/graphics/text.py
@@ -0,0 +1,60 @@
+from pygame import Rect, Surface, SRCALPHA
+
+LEFT=0
+RIGHT=1
+CENTER=2
+
+class TextBlock(object):
+
+ LEFT = LEFT
+ RIGHT = RIGHT
+ CENTER = CENTER
+
+ def __init__(self, font, padding=10, justify=LEFT, margin=5):
+ self.font = font
+ self.padding = padding
+ self.margin = margin
+ self.justify = justify
+
+
+ def render(self, lines, antialias, fg, bg=None):
+ block = []
+ bounds = Rect(0,0,self.margin,self.margin)
+ for line in lines:
+
+ if bg is not None:
+ text = self.font.render(line, antialias, fg, bg)
+ else:
+ text = self.font.render(line, antialias, fg)
+
+ rect = text.get_rect()
+ if bounds.bottom > self.margin:
+ rect.top = bounds.bottom + self.padding
+
+ bounds.union_ip(rect)
+ block.append((text,rect))
+
+ bounds.height += self.margin
+
+
+ surf = Surface(bounds.size, SRCALPHA)
+
+ if bg is not None:
+ surf.fill(bg)
+ else:
+ surf.fill((0,0,0,0))
+
+ for line,rect in block:
+
+ if self.justify == LEFT:
+ rect.left = bounds.left + self.margin
+ elif self.justify == RIGHT:
+ rect.right = bounds.right - self.margin
+ elif self.justify == CENTER:
+ rect.centerx = bounds.centerx
+
+ surf.blit(line, rect)
+
+ return surf
+
+
View
31 samplecode/networking_example/coinget/graphics/tile.py
@@ -0,0 +1,31 @@
+class TiledImage(object):
+ def __init__(self, image, rect=None):
+
+ self.image = image
+
+ if rect is None:
+ self.rect = image.get_rect()
+ else:
+ self.rect = rect
+
+
+ def draw(self, surf, rect=None):
+ # if no rect is given, use surfaces rect
+ if rect is None:
+ rect = surf.get_rect()
+
+ w, h = self.rect.size
+ x, y = self.rect.topleft
+
+ # calculate the start and end points
+ x0 = rect.x - (-x % w)
+ x1 = rect.x + rect.width
+
+ y0 = rect.y - (-y % h)
+ y1 = rect.y + rect.height
+
+ # loop through and draw images
+ for y in xrange(y0, y1, h):
+ for x in xrange(x0, x1, w):
+ surf.blit(self.image, (x, y))
+
View
0  samplecode/networking_example/coinget/network/__init__.py
No changes.
View
33 samplecode/networking_example/coinget/network/clock.py
@@ -0,0 +1,33 @@
+from twisted.internet import reactor
+from twisted.internet.task import LoopingCall, Clock
+
+# our new "game loop"
+class SimulationClock(Clock):
+ _call = None
+
+ def __init__(self, framerate):
+ Clock.__init__(self)
+ self.framerate = framerate
+
+
+ def _update(self, frames):
+ self.advance(1.0 * frames / self.framerate)
+
+
+ def start(self):
+ """
+ Start the simulated advancement of time.
+ """
+ self._call = LoopingCall.withCount(self._update)
+ self._call.clock = reactor
+ self._call.start(1.0 / self.framerate, now=False)
+ self._running = True
+
+
+ def stop(self):
+ """
+ Stop the simulated advancement of time. Clean up all pending calls.
+ """
+ if self._running:
+ self._running = False
+ self._call.stop()
View
3  samplecode/networking_example/coinget/network/cmd/__init__.py
@@ -0,0 +1,3 @@
+from coin import *
+from player import *
+from world import *
View
33 samplecode/networking_example/coinget/network/cmd/coin.py
@@ -0,0 +1,33 @@
+import struct
+
+from twisted.protocols import amp
+
+from coinget.world import Coin
+
+class CoinArgument(amp.Argument):
+ frmt = "!iiif"
+
+ def toString(self, coin):
+ identifier = coin.identifier
+ x,y = coin.rect.center
+ life = coin.life
+
+ return struct.pack(self.frmt, identifier, x, y, life)
+
+ def fromString(self, encoded):
+ identifier, x, y, life = struct.unpack(self.frmt, encoded)
+ coin = Coin(identifier, (x,y))
+ coin.life = life
+ return coin
+
+class AddCoin(amp.Command):
+ requiresResponce = False
+ arguments = [("coin", CoinArgument())]
+ responce = []
+
+class CollectCoin(amp.Command):
+ requiresResponce = False
+
+ arguments = [("player_id", amp.Integer()),
+ ("coin_id", amp.Integer()),
+ ("score", amp.Integer())]
View
60 samplecode/networking_example/coinget/network/cmd/player.py
@@ -0,0 +1,60 @@
+import struct
+
+import pygame
+from twisted.protocols import amp
+
+from coinget.world import Player
+
+
+def take(n, arr):
+ result = []
+ for i in range(n):
+ result.append( arr.pop(0) )
+ return result
+
+
+class PlayerArgument(amp.Argument):
+ def toString(self, player):
+ frmt = "!"; data = []
+ frmt += "i"; data += [player.identifier]
+ frmt += "BBB"; data += player.color[:3]
+ frmt += "ii"; data += player.rect.center
+ frmt += "ii"; data += [ player.vx, player.vy]
+ frmt += "s"; data += [ player.nick ]
+
+ return struct.pack(frmt, *data)
+
+ def fromString(self, encoded):
+ frmt = "!iBBBiiiis"
+ data = list(struct.unpack(frmt, encoded))
+
+ identifier = take(1, data)[0]
+ color = take(3, data)
+ pos = take(2, data)
+ vel = take(2, data)
+ nick = take(1, data)[0]
+
+ color = pygame.Color(*color)
+
+ return Player(identifier, nick, color, pos, vel)
+
+
+class CreatePlayer(amp.Command):
+ requiresResponse = True
+ arguments = [("nick", amp.String())]
+ response = [("player", PlayerArgument())]
+
+
+class AddPlayer(amp.Command):
+ requiresResponse = False
+ arguments = [("player", PlayerArgument())]
+ response = []
+
+class MovePlayer(amp.Command):
+ requiresResponse = False
+ arguments = [("identifier", amp.Integer()),
+ ("x", amp.Integer()),
+ ("y", amp.Integer()),
+ ("vx", amp.Integer()),
+ ("vy", amp.Integer())]
+ response = []
View
45 samplecode/networking_example/coinget/network/cmd/world.py
@@ -0,0 +1,45 @@
+from twisted.protocols import amp
+
+from coin import CoinArgument
+from player import PlayerArgument
+
+OBJ_ARG = {
+ "coin": CoinArgument(),
+ "player": PlayerArgument()
+}
+
+
+
+class WorldObjects(amp.Argument):
+ def toBox(self, name, strings, objects, proto):
+ for i,obj in enumerate(objects[name]):
+ obj_name = "%s%d" % (name, i)
+ arg = OBJ_ARG[obj.type]
+ strings[obj_name] = obj.type + ":" + arg.toString(obj)
+
+
+ def fromBox(self, name, strings, objects, proto):
+ objs = []
+
+ for key in strings:
+ if key.startswith(name):
+ typ, data = strings[key].split(":", 1)
+ arg = OBJ_ARG[typ]
+ objs.append(arg.fromString(data))
+
+ objects[name] = objs
+
+
+class SyncWorld(amp.Command):
+ requiresResponse = True
+
+ arguments = []
+ response = [("time", amp.Float()),
+ ("objects", WorldObjects())]
+
+
+class RemoveObject(amp.Command):
+ requiresResponse = False
+
+ arguments = [("identifier", amp.Integer())]
+ responce = []
View
21 samplecode/networking_example/coinget/rand.py
@@ -0,0 +1,21 @@
+from random import randint, randrange
+
+from pygame import Color
+
+def player_color():
+ color = [ randrange(128,256) for _ in range(3) ]
+
+ num_channels = randint(1,2)
+ for i in range(num_channels):
+ channel = randrange(3)
+ color[channel] = 0
+
+ return Color(*color)
+
+
+def position(bounds):
+ x = randrange(bounds.width)
+ y = randrange(bounds.height)
+ return bounds.x + x, bounds.y + y
+
+
View
1  samplecode/networking_example/coinget/server/__init__.py
@@ -0,0 +1 @@
+from server import GameServer, Options
View
45 samplecode/networking_example/coinget/server/environment.py
@@ -0,0 +1,45 @@
+from random import randint, randrange
+
+from pygame import Color
+
+from coinget import rand
+from coinget import settings
+from coinget.network.clock import SimulationClock
+from coinget.world import World
+from coinget.world import Coin, Player
+
+
+class Environment(SimulationClock, World):
+ def __init__(self, framerate=1):
+ SimulationClock.__init__(self, framerate)
+ World.__init__(self)
+
+ def create_player(self, nick):
+ bounds = self.bounds.inflate(-self.bounds.width/2, -self.bounds.height/2)
+ color = rand.player_color()
+ pos = rand.position(bounds)
+
+ return Player(None, nick, color, pos)
+
+ def spawn_coin(self):
+ if len(self.coins) < settings.MAX_COINS:
+ pos = rand.position(self.bounds)
+ coin = Coin(None, pos)
+ self.add(coin)
+
+ def advance(self, dt):
+ self.update(dt)
+
+ # spawn new coins as needed
+ if len(self.coins) == 0:
+ self.spawn_coin()
+
+
+
+ # check to see if any player has hit any coin
+ for player in self.players:
+ for coin in self.coins:
+ if player.rect.colliderect(coin.rect):
+ self.remove(coin.identifier)
+ self.spawn_coin()
+ self.spawn_coin()
View
85 samplecode/networking_example/coinget/server/network.py
@@ -0,0 +1,85 @@
+from louie import dispatcher
+
+from twisted.internet.protocol import ServerFactory
+from twisted.protocols import amp
+
+from coinget import signals
+from coinget.network import cmd
+from coinget.world import Coin, Player
+
+class GameServerProtocol(amp.AMP):
+ """
+ translates amp requests from client into operations on game world
+ """
+
+ def __init__(self, world):
+ self.world = world
+ self.player = None
+
+ dispatcher.connect(self.add_coin, signal=signals.NEW_OBJECT, sender=Coin)
+ dispatcher.connect(self.add_player, signal=signals.NEW_OBJECT, sender=Player)
+ dispatcher.connect(self.remove_object, signal=signals.DEL_OBJECT)
+ dispatcher.connect(self.move_player, signal=signals.MOVE_PLAYER)
+
+ @cmd.SyncWorld.responder
+ def connectionMade(self):
+ return { "time": self.world.time,
+ "objects": self.world.objects }
+
+ def connectionLost(self, reason):
+ print "lost connection"
+ self.world.remove(self.player.identifier)
+
+ def add_coin(self, obj):
+ self.callRemote(cmd.AddCoin, coin=obj)
+
+ def add_player(self, obj):
+ if obj is not self.player:
+ self.callRemote(cmd.AddPlayer, player=obj)
+
+ def remove_object(self, sender):
+ self.callRemote(cmd.RemoveObject, identifier=sender.identifier)
+
+ @cmd.MovePlayer.responder
+ def player_moved(self, identifier, x, y, vx, vy):
+ player = self.world.get(identifier)
+ dispatcher.send(signal=signals.MOVE_PLAYER, sender=player, x=x, y=y, vx=vx, vy=vy)
+ return {}
+
+ def move_player(self, sender, x, y, vx, vy):
+ # don't send the move back
+ if sender.identifier != self.player.identifier:
+ self.callRemote(cmd.MovePlayer,
+ identifier=sender.identifier,
+ x=x,
+ y=y,
+ vx=vx,
+ vy=vy)
+
+ @cmd.CreatePlayer.responder
+ def create_player(self, nick):
+ self.player = self.world.create_player(nick)
+ self.world.add(self.player)
+
+ return {"player": self.player}
+
+
+class GameServerFactory(ServerFactory):
+ def __init__(self, world):
+ print "server started"
+ self.world = world
+ self.connections = []
+
+ dispatcher.connect(self.remove_protocol, signals.CONNECTION_CLOSED)
+
+ # when player connects, create a new player object
+ def buildProtocol(self, addr):
+ print addr, "has connected"
+ protocol = GameServerProtocol(self.world)
+
+ self.connections.append(protocol)
+ return protocol
+
+ def remove_protocol(self, sender):
+ if sender in self.connections:
+ self.connections.remove(sender)
View
29 samplecode/networking_example/coinget/server/server.py
@@ -0,0 +1,29 @@
+from twisted.internet import reactor
+from twisted.internet.endpoints import TCP4ServerEndpoint
+from twisted.python import usage
+
+from environment import Environment
+from network import GameServerFactory
+
+from coinget import settings
+
+class Options(usage.Options):
+ optParameters = [
+ ('port', 'p', settings.DEFAULT_PORT, "TCP port number to listen on.", usage.portCoerce)
+ ]
+
+
+class GameServer(object):
+ def __init__(self, options):
+ self.port = options['port']
+
+ def start(self):
+ environment = Environment(framerate=15)
+ factory = GameServerFactory(environment)
+
+ endpt = TCP4ServerEndpoint(reactor, self.port)
+ endpt.listen(factory)
+
+ environment.start()
+
+ reactor.run()
View
13 samplecode/networking_example/coinget/settings.py
@@ -0,0 +1,13 @@
+CAPTION = "Super Coin Get: MultiMadness"
+SCREEN_SIZE = 800,600
+
+DEFAULT_PORT = 8007
+
+LEVEL_SIZE = SCREEN_SIZE
+
+MAX_COINS = 10000
+COIN_SIZE = 15, 15 # hit box for coins
+COIN_LIFE = 8 # how long coins stay alive in seconds
+
+PLAYER_SIZE = 40, 40
+PLAYER_SPEED = 400
View
16 samplecode/networking_example/coinget/signals.py
@@ -0,0 +1,16 @@
+## SETUP louie, also imports dispatcher so importing modules just need this one
+import louie
+louie.plugin.install_plugin( louie.plugin.TwistedDispatchPlugin() )
+
+# App signals
+QUIT = "QUIT"
+READY = "READY"
+
+CONNECTION_CLOSED = "CONNECTION_CLOSED"
+
+NEW_OBJECT = "NEW_OBJECT"
+DEL_OBJECT = "DEL_OBJECT"
+
+MOVE_PLAYER = "MOVE_PLAYER"
+COLLECT_COIN = "COLLECT_COIN"
+
View
3  samplecode/networking_example/coinget/world/__init__.py
@@ -0,0 +1,3 @@
+from coin import Coin
+from player import Player
+from world import World
View
28 samplecode/networking_example/coinget/world/coin.py
@@ -0,0 +1,28 @@
+from random import randrange
+
+from louie import dispatcher
+from pygame import Rect
+
+from coinget import settings
+from coinget import signals
+from obj import WorldObject
+
+
+## Coin
+class Coin(WorldObject):
+ life = settings.COIN_LIFE
+
+ def __init__(self, identifier, loc):
+ WorldObject.__init__(self, identifier)
+
+ self.rect = Rect((0,0), settings.COIN_SIZE)
+ self.rect.center = loc
+
+ def update(self, dt):
+ self.life -= dt
+
+ if self.life <= 0:
+ self.kill()
+
+ def __repr__(self):
+ return "<Coin: (%d, %d) %f>" % (self.rect.centerx, self.rect.centery, self.life)
View
25 samplecode/networking_example/coinget/world/obj.py
@@ -0,0 +1,25 @@
+def id_generator():
+ c = 0
+ while True:
+ yield c
+ c += 1
+
+
+class WorldObject(object):
+ ids = id_generator()
+ identifier = None
+
+ def __init__(self, identifier):
+ if identifier is None:
+ identifier = WorldObject.ids.next()
+ self.identifier = identifier
+
+ @property
+ def type(self):
+ return self.__class__.__name__.lower()
+
+ def kill(self):
+ self.world.remove(self.identifier)
+
+ def update(self, dt):
+ pass
View
49 samplecode/networking_example/coinget/world/player.py
@@ -0,0 +1,49 @@
+import math
+
+from louie import dispatcher
+from pygame import Rect
+
+from coinget import settings
+from coinget import signals
+
+from obj import WorldObject
+
+
+class Player(WorldObject):
+ def __init__(self, identifier, nick, color, pos, vel=(0,0)):
+ WorldObject.__init__(self, identifier)
+
+ self.nick = nick
+ self.color = color
+ self.rect = Rect((0,0), settings.PLAYER_SIZE)
+ self.vx, self.vy = vel
+ self.x, self.y = pos
+ self.rect.center = pos
+
+ dispatcher.connect(self.move, signal=signals.MOVE_PLAYER, sender=self)
+
+
+ def move(self, x, y, vx, vy):
+ if vx and vy:
+ vx *= 1 / math.sqrt(2)
+ vy *= 1 / math.sqrt(2)
+
+ self.x = x
+ self.y = y
+ self.vx = vx * settings.PLAYER_SPEED
+ self.vy = vy * settings.PLAYER_SPEED
+
+
+ def update(self, dt):
+ self.x += self.vx * dt
+ self.y += self.vy * dt
+
+ self.rect.centerx = self.x
+ self.rect.centery = self.y
+
+ clamp = self.rect.clamp(self.world.bounds)
+ if clamp != self.rect:
+ self.rect = clamp
+ self.x = self.rect.centerx
+ self.y = self.rect.centery
+
View
64 samplecode/networking_example/coinget/world/world.py
@@ -0,0 +1,64 @@
+from collections import defaultdict
+
+from louie import dispatcher
+from pygame import Rect
+
+from coinget import settings
+from coinget import signals
+
+
+class World(object):
+ def __init__(self, time=0.0):
+ self.time = time
+ self._objects = {}
+ self._objects_by_type = defaultdict(list)
+
+ self.bounds = Rect((0,0), settings.LEVEL_SIZE)
+
+ # provide access to lists of objects by type
+ def __getattr__(self, key):
+ return self._objects_by_type[key][:]
+
+ @property
+ def objects(self):
+ return self._objects.values()
+
+ def get(self, identifier):
+ return self._objects.get(identifier)
+
+ def add(self, obj):
+ self._objects[obj.identifier] = obj
+ obj.world = self
+
+ typ = obj.type + "s"
+ self._objects_by_type[typ].append(obj)
+ dispatcher.send(signal=signals.NEW_OBJECT, sender=obj.__class__, obj=obj)
+
+
+ def remove(self, identifier):
+ if identifier in self._objects:
+ obj = self._objects[identifier]
+ typ = obj.type + "s"
+
+ del self._objects[identifier]
+ self._objects_by_type[typ].remove(obj)
+ dispatcher.send(signal=signals.DEL_OBJECT, sender=obj)
+
+
+ # update the world state based on dt
+ def update(self, dt):
+ self.time += dt
+
+ for obj in self._objects.values():
+ obj.update(dt)
+
+
+def monitor_add(sender, obj):
+ print obj, "added"
+
+def monitor_remove(sender):
+ print sender, "removed"
+
+dispatcher.connect(monitor_add, signal=signals.NEW_OBJECT)
+dispatcher.connect(monitor_remove, signal=signals.DEL_OBJECT)
+
View
BIN  samplecode/networking_example/images/coin.bmp
Binary file not shown
View
BIN  samplecode/networking_example/images/grass.bmp
Binary file not shown
View
BIN  samplecode/networking_example/images/logo.bmp
Binary file not shown
View
BIN  samplecode/networking_example/images/mario.bmp
Binary file not shown
View
8 samplecode/networking_example/server.py
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+from coinget.server import GameServer, Options
+
+
+options = Options(); options.parseOptions()
+server = GameServer(options)
+server.start()
+
View
BIN  samplecode/networking_example/sounds/coin.ogg
Binary file not shown
View
BIN  samplecode/networking_example/sounds/music/maintheme.ogg
Binary file not shown
View
BIN  samplecode/networking_example/sounds/music/title.ogg
Binary file not shown
View
BIN  samplecode/networking_example/sounds/pause.ogg
Binary file not shown
Please sign in to comment.
Something went wrong with that request. Please try again.