About Me

My name is Ricardo Pascal, I'm a developer and sysadmin who lives in Florianopolis/Brazil. I enjoy work with projects related to Linux, Python, Science, Web, Django and Network.

g+ I finally found a place with plenty of space to fly my f330, now I just have to lose the fear of flying... | Vaga de emprego para programador python na lett.com.br O serviço que eles oferecem parece interessante... | "The Horribly Slow Murderer with the Extremely Inefficient Weapon", it's number one in my top 10 worst... | Challenge accepted! One per night til the end of year ( minus weekends )  | TIL: genotoxicity  is not a made up word | +Detectify  i have to say, well done Sirs ! " tl;dr: We uploaded a malicious XML to one of Google’s... | A drug used to treat Cytomegalovirus infections can increase almost four times the survive rate of people... | Physics FTW! | Just to clarify!  | It seems that Brazil actually "chose" the best. | Good tips for dev teams. | it's like our entire body is a baby's soft spot! | Next time I will try with a lighter battery ( < 330g )  | Testing my F330 with multiwii crius | Anyone here who owns a LG 29" 29EA73 know if the full resolution(2560x1080) can be achieved in Ubuntu... | Particularly, I think(as audience) that less slides and more whiteboard is better than no slides. | It would be awesome have something like that in multiwii. #quadrotor | LMFAO!  This is sooooo true! #ComputerNerdProblems   | Good news everyone! Galaxy note 10.1 (n8000) will be updated to android 4.4 http://www.samsungmobi... | In Brazil, cops don't put people in jail. They prefer to beat you in hope to scare you away. |

How (not) to create a network game

One of the most important thing that you should keep in mind while developing a real time network game is that latency is a bitch.


  • For the sake of simplicity the code will be focused on latency without any attempt to fix that.
  • Our sample code is constructed based on a previous post about proxy, since the server code is 99% the same, a explanation about how the server works can be retrieved from that post.

Overall architecture

The architecture of our game is really really simple, in a raw way it will emulate one of the most common conception of how a network communication in a game can occur:

1) there is a server; 2) each client connect to this server and send his current position; 3) as response, the server send back a dictionary that holds the position of all objects; 4) with this data the client draw all the objects at their respective positions.




import socket
import select
import time
import sys
import simplejson

buffer_size = 2000
delay = 0
ships = {}

class TheServer:

    def __init__(self, host, port):
        self.input_list = []
        self.channel = {}

        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server.bind((host, port))

    def main_loop(self):
        while 1:
            inputr, outputr, exceptr = select.select(self.input_list, [], [])
            for self.s in inputr:
                if self.s == self.server:
                    self.data = self.s.recv(buffer_size)
                if len(self.data) == 0:

    def on_accept(self):
        clientsock, clientaddr = self.server.accept()
        print clientaddr, "has connected"
        ships[clientaddr[1]] = {}

    def on_close(self):
        clientaddr = self.s.getpeername()
        print " %s has disconnected" % clientaddr[0]
        #remove objects from input_list

    def on_recv(self):
        _id = self.s.getpeername()[1]
        ships[_id] = simplejson.loads(self.data)

if __name__ == '__main__':
        server = TheServer('', 50090)
        except KeyboardInterrupt:
            print "Ctrl C - Stopping server"


#!/usr/bin/env python
import pyglet
import math
import socket
import simplejson

resolution = (800, 600)
keys = pyglet.window.key.KeyStateHandler()
image = pyglet.image.load('ship.png')
image.anchor_x = image.width // 2
image.anchor_y = image.height // 2

def forward():
    conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    conn.connect(('', 50090))
    _id = str(conn.getsockname()[1])
    return [_id, conn]

def create_ship(_id=False):
    ship = pyglet.sprite.Sprite(image)
    ship.x = resolution[0] / 2
    ship.y = resolution[1] / 2
    if _id:
        ship.opacity = 64
        ship._id = _id
    return ship

class MainWindow(pyglet.window.Window):
    def __init__(self, *args, **kwargs):
        pyglet.window.Window.__init__(self, *args, **kwargs)
        self.ship = create_ship()
        self.me, self.conn = forward()
        self.players = []
        self.players_id = []

    def on_draw(self):
        x, y = self.ship.position
        a = self.ship.rotation
        data = simplejson.dumps([x, y, a])
        data = simplejson.loads(self.conn.recv(2000))

        for shipid in data.keys():
            if shipid != self.me and shipid not in self.players_id:

        for player in self.players:
            if player._id in data:
                player.x, player.y, player.rotation = data[player._id]
                player.x, player.y, player.rotation = [0, 0, 0]

        if keys[pyglet.window.key.LEFT]:
            self.ship.rotation -= 2

        if keys[pyglet.window.key.RIGHT]:
            self.ship.rotation += 2

        if keys[pyglet.window.key.UP]:
            diff = math.cos(math.radians(self.ship.rotation))
            self.ship.y += 6 * diff
            increase = math.sin(math.radians(self.ship.rotation))
            self.ship.x += 6 * increase

if __name__ == "__main__":
    MainWindow(width=resolution[0], height=resolution[1])

Client explanation

function forward()

returns a communication channel with the server, using this socket the client will send the spaceship position, and retrieve the global position map.

function create_ship()

returns a spaceship object (a pyglet sprite); set the initial position, if that is not your ship define a _id and put a little of opacity;

class MainWindow() init()

Start the pyglet screen; bind the keyboard as input; create your ship; start the communication channel

class MainWindow() on_draw()

(1) Clear screen and draw your spaceship. (2) Stores your spaceship position/orientation, them send this data encoded as json to the server. (3) Receive and decode the global position data. (4) Iterate over the returned data to create a list of ships id and ships objects. (5) Iterate over the list of objects; define their new position and draw them all. (6) Check for keyboard input and move your ship.

What happens when you run the code?

If you use 3 similar computers on a local network, one as server and two as clients, you will have a close to smooth experience. But if you run this over Internet things will go wrong. Do you realize why?

The bitch latency! Over a LAN you will have less than 1ms of latency, in one second close to 500 interchanges between the server and client can occur. (Since we need a response from server, each action will take twice the latency time: 1000ms / (1ms + 1ms) ) But between my home broadband and my vps only 4 happens.

Let's imagine a scenario where 3 people from different parts of the world connect to my game server running at this VPS(in Germany). How the spaceship speed will be seen from the watcher perspective?

  • People A Joe from Haarlem (NL) with 100ms of latency
  • People B Mika from Hamburg (DE) with 50ms of latency
  • People C Me from Florianópolis (BR) with 250ms of latency

That's what will be seen:

Spaceship speed

Each spaceship will have a different speed, and each client will see a different pattern of lag which will warp all the others spaceships. At this point you probably realize that writing a network game is not so simple.

That's all folks!

by Ricardo Pascal on Sep 10, 2012