Pong

A multi-player version of the classic Pong game. This project started as an exercise to implement a very simple use of the case of the Unity physics engine, then evolved in to an exercise in multi-player code.

The Challenge

Keeping multiple game states in sync over a network with lag and with (in some cases) non-deterministic physics behaviour [1].

Architecture

A client/server architecture was developed that allowed for optimized network utilization.

The Server

The server is a nodejs application written to provide a number of features:

  • It is the authoritative source of all games, which limits the scope of cheating.
  • It is a game lobby for players to join.
  • It is a transmission hub for all game traffic. This allows spectating and removes the need for clients to set up firewalls.

The server provides a gRPC service that is used by the clients to share game state and share messages [2].

The server is bundled as a docker container and can be found here.

The Client

The client is a unity c# application written as the main game interface for all players.

It communicates over a bi-directional stream with the server's gRPC service.

Network Protocol

The game server updates the physics of each game 60 times per second.

To minimize the network traffic, it only sends a GameState message to the clients when

  • The ball hits a paddle or wall
  • A player starts, or stops movement

To minimize the impact of lag, each client (using Unity's physics engine) updates the ball's position each frame. Only when a GameState message is received from the server is the ball's position and direction manually updated. The GameState message includes the ball position and velocity allowing the client side physics simulation to take over in between.

The client does not implement the non-natural rebound logic, resulting in a small window of opportunity for some ball teleportation after it hits a wall or paddle. This is generally not too bad but could be improved by implementing the same logic client side.


1 Ball rebounds are manipulated to make the game more interesting. Non-natural rebounds occur when the ball hits off center on the paddle, and when the ball hits a wall and the horizontal velocity is under a threshold.

2 The state of Unity multiplayer support is extremely confusing, with the current implementation (UNet) totally deprecated, but the replacement in an unclear state. I also wanted to be able to write non-unity clients, so went with an open protocol.