How to Develop a Two Player Pong game over Network in Python and Pygame

Saurabh Ghosh
Predict
Published in
9 min readOct 5, 2022

Let’s learn python programming concepts by creating a multiplayer network game.

Photo by Feelfarbig Magazine on Unsplash

What to expect in this blog?

My previous blogs explained working with python core concepts with fun programs and games.

Now it is time to take on more challenges and create a fusion of three important concepts –

  1. Pygame library for game programming
  2. Creating client and server programs
  3. Sending and receiving objects over the network with Pickle library
  4. Working with threads

By the end of this blog, you should be able to create your own Pong game and play with an opponent in your local network.

What is a Pong game?

Pong is probably one of the first computer games ever created.

It is a tennis-like game played by two players. Each player controls a paddle or bat. There is a ball on the board. The players need to hit the ball to reflect towards the opposite side. If a player misses, the opponent scores a point.

In this blog, you’ll create a network-based Pong game. Players in the local network will connect to the server and play against another player on the network.

Let’s plan for the work

The game will be played over the network by two players per game. Each pair of players will see the game progress and will be able to control their own bats. The movement of the ball should be in sync for both players. Multiple pairs of players should be able to play the game.

So, at a high level, we’ll need two components –

  1. A server program which will keep track of the movement of the players’ bats and the ball.
  2. A client program which can be used by multiple players to connect to the server and join a game.

Important user interaction involved (Client program)

  1. The user should be able to connect to the server program.
  2. If the user is the first player, the user will wait till a second player joins the game.
  3. If the user is the second player joining the game, the game will start.
  4. Users should be able to identify their own bat in the game.
  5. The user should be able to move their own bat to hit the ball.
  6. The user should see the ball's movement.
  7. Users should see the points get added to the players when a player misses the ball.
  8. The user should be able to leave the game.
  9. If one of the players leaves or gets disconnected, the other player will be waiting till another player joins the game.

Important system processing involved (Server program)

  1. The server should continuously listen for incoming client connections on a specific port.
  2. The server should maintain a queue of ongoing games (each game supporting two players).
  3. When a client (player) connects to the server port, the server should add the client to an existing game where one player is already connected or create a new game in the queue and keep the player waiting till another player joins the server.
  4. When both players are connected, the server should start a game and continue the below actions in a loop -
    — The server should receive the movement of the bats from the connected players.
    — The server should manage the movement of the ball.
    — The server should maintain the state of the game which includes movement of the ball, movement of the bats, and points for the players.
    — The server should send the updated state of the game to the connected players.
  5. When a player leaves or gets disconnected from the server, the server should remove that player from the game.
  6. If both players leave or get disconnected, the server should delete the game from the queue.

High-level design thinking

Server

  1. PongDTO class — This data transfer object class will contain the variables sent and received between the server and clients. The variables should describe the bat positions, the ball position, and player points.
  2. Game class and queue of game objects — The server will be maintaining a queue of Game objects. Each object will contain an identifier for the game, a list of the player ids and the PongDTO object corresponding to the game. When multiple games are in progress, there will be multiple Game objects with different game identifiers.
  3. get_game() and get_game_dto() — These two methods will facilitate retrieving the Game object and the PongDTO object for the game respectively from the game queue when supplied with the unique game identifier.
  4. update_game_dto() — This method should take a PongDTO object as an argument and update required variables from the input DTO into the DTO maintained in the server queue for the game.
  5. update_game_state() — This method will update the state of the game. Here, this method will move the ball and update the ball's position. This method will also reset the position if a player misses the ball or the ball gets reflected off a wall. This method increases players’ points as well.
  6. get_game_player_id() — This method will be called when a new connection is accepted to start a game and needs the game id and player id. It’ll provide the available game id and the player id for the new player. If there is any game where one player is waiting for another player, that game id and a player id will be considered. If there is no existing game with one available slot, it’ll create a new game and return the ids.
  7. threaded_client() — This method will be called to start a new parallel thread for the new player. It’ll perform the below actions. Please keep in mind that these actions will be taken with respect to the current player. There will be a parallel thread performing the same actions for the opponent in the game.
    a. Get the PongDTO object for the game from the game queue by calling the get_game_dto() method.
    b. Set the player id into the DTO and send the DTO to the client application
    c. Start the loop with the below actions in each loop –
    — Set the game speed
    — Receive DTO from the client
    — If the game has both players, update the game state by calling the update_game_state() method.
    — Until the game has both players, do not update the game state
    — Send updated DTO to the client
    d. If the connection is lost with a client for any reason –
    — Release the player id
    — Reset the game state
    — If both players left, remove the game from the game queue
  8. Global process — Since the server program will be executed as a python script, the below server processes will be at the script level.
    a. Create a socket with IP and port.
    b. Initiate the game queue.
    c. Start loop for accepting incoming connections from clients (i.e. players) to this server.
    d. For each incoming connection, get the game id and player id by calling the method get_game_player_id().
    e. Initiate a new thread for the player by calling the threaded_client() method.

Client

  1. PongDTO class — Similar to the server program, the client will also need the PongDTO class. It is the same class duplicated here. It can be moved as a separate python and imported if required.
  2. Bat class — This class will facilitate managing the players’ bats on screen. It’ll have methods to draw the bat, move the bat and increase the point if the opponent misses.
  3. Ball class — This class will facilitate managing the movement of the ball on the screen. It’ll have a method to draw the ball. Please note that ball movement is managed in the server and not in the client. Otherwise, two players will see different ball positions.
  4. update_bat_ball() — This method will take PongDTO as input and update the positions of the bats and the ball. This method will also set the colours of the player and opponent differently.
  5. Global process — Since the client program will be executed as a python script by each player, the below processes will be at the script level.
    a. Connect to the server IP and port and receive the first PongDTO object from the server. Determine the player’s id and the opponent's id from the DTO received.
    b. Create the bats and the ball objects and update them with details received from the server.
    c. Create the pygame surface with size and colour.
    d. Set the title bar caption and colours of the bats.
    e. Start the loop with the below actions in each loop –
    — Set the game speed.
    — Draw the screen components.
    — Get movement keys input by the user and change the bat position. For this game, you’ll use the ‘W’ for upward movement, ‘S’ for downward movement and Escape/mouse click for exiting the game.
    — Send the updated DTO with the player’s bat position.
    — Receive DTO from the server. This will get the ball movement and the opponent’s bat movement.
    — Set the positions of bats and the ball as received from the server.
    — Update the title bar with the player’s points.

Let’s code

As you now know the main methods and their purpose, now let’s get started.

You can follow the comments and docstrings within the code snippets.

Server

Import and global variables

PongDTO class

Game class

get_game()

get_game_dto()

update_game_dto()

update_game_state()

get_game_player_id()

threaded_client()

Key points —
— Coding a method which will run in a parallel thread and interact with global variables
— Using Pygame clock for setting the game speed
— Using Pickle methods for sending and receiving objects over the network
— Exception handling

Global Process

Key points —
— Initiating a new thread and calling a method for the thread
— Using socket for network connections
— Exception handling

Note — The server IP and the port should be changed as per your network. Another possible enhancement can be done to accept an escape input from the user to stop the server.

Client

Import and global variables

PongDTO class

It is the same class as in the server program.

Bat class

Key points —
— Using the draw() method of Pygame

Ball class

Key points —
— Using the draw() method of Pygame

update_bat_ball()

Key points —
— Using RGB values for different colours

Global Process

Key points —
— Connecting to a server port
— Using Pickle methods for sending and receiving objects over the network
— Using Pygame methods for rendering window and related components
— Using Pygame events and key inputs
— Exception handling

Note — The server IP and the port should be changed as per your network.

That’s all the coding. Now it’s time to run the game.

Run the code

The server program needs to be run by the command “python server.py”. The server will wait for a client to connect.

Once the server is listening, the client program needs to be run by the command “python client.py”.

The server will show the player connected.

The client console will show as below.

Until both the players are connected to a game, the game won’t start. It’ll show as below for the first player.

When another player connects, the game will start.

The colours will appear reversed for the second player.

Happy coding!!

Download

GitHub — https://github.com/SaurabhGhosh/pongovernet.git

Conclusion

In this blog, I hope you got some idea about below -

  1. Pygame library for game programming
  2. Creating client and server programs
  3. Sending and receiving objects over the network with Pickle library
  4. Working with threads

In my next blog, I’ll explore another program and learn more concepts.

If you have any questions related to this program, please feel free to post your comments.

Please like, comment and follow me. Keep Learning.

--

--

Saurabh Ghosh
Predict
Writer for

Business Analyst, Machine Learning Enthusiast, Blogger