Thursday, June 11, 2015

Programming simple multiplayer game - easy way

Hi,
Again me and I want to share simple idea of making multiplayer game. It's hard to find simple tutorial about multiplayer so I created one.

The first thing: it's simple, you don't make huge MMO game, only simple game to local plays.
The second thing: there is many ways to do that better, so don't think it's good - it's simple and easy to do.
The third thing: it's nice for beginners, so when you understand how works multiplayer games, you should do it 'proper way'.

So let's start:
 - in examples I use C++ and SFML 2.x


We need server and client. So I created two classes Client and Server.
Client is for communicating with server and passing data to game.
Server process every command from client and send updated world.
All data is store in World class. There is players, enities, items etc.
Server store all world and send copy for client.

At first we need to connect:
 - it's simple, just look tutorial on SFML site: http://www.sfml-dev.org/tutorials/2.3/network-socket.php
When you have established connection you can start:

Server side:
 - we need add unique id for player
 - we need add player to world
 - send informations about created player to client

So when client connect to server, server should do:

std::string player_id = "player_id__" + std::to_string(reinterpret_cast<uint32_t>(client)); 

In this way (up) we create player id. It's just get client address in memory (of server) and add it to text "player_id__". Pretty simple and enough safe for local game.

world->addPlayer(Player(player_id, sf::Vector2f(100, 100), sf::Vector2f(66, 92), 100));

Here we add player with: created earlier id, start position, size of player and health points.

Next we send informations about player to client: e.g.:


sf::Packet start_packet;
start_packet << "connect" << *world->getPlayer(player_id); 
client->send(start_packet);

Client side:
 - get our player id from received packet and store in client (it's to inform server which player we are)

So when you receive packet just extract first variable and check is it "connect" and then client_player_id = player.id;

Very easy and rest is very similar.

Client send e.g. "update world" and when server receive this, send all world to client.
When client receive "update world" just replace world in game.
Client send "move player up" and player_id, so server on "move player up" get player from world and move up.

It's simple, to make sure you understand just look this parts of code. It's from my simple project:

Client side:


void Client::runCommand(const std::string& command, const std::string& id)
{
  if(command == "player move")
    {
      sf::Packet packet;
      packet << "player move" << id << player_id;
      socket.send(packet);
    }
  if(command == "destroy item")
    {
      sf::Packet packet;
      packet << "destroy item" << id;
      socket.send(packet);
    }
} 
 
It's part of Client class and I use it in game to make actions, e.g. when player click up arrow I do client.runCommand("player move", "up"); and this is send to server, which do move. Simple and work :)

And server side:

sf::Packet packet;
if(client.receive(packet) == sf::Socket::Done)
{
    std::string event;

    if(packet >> event)
    {
        if(event == "player move")
        {
            std::string player_id;
            std::string direction;
            if(packet >> direction >> player_id)
            {
                if(direction == "up")
                    world->getPlayer(player_id)->position.y -= 5;
                if(direction == "down")
                    world->getPlayer(player_id)->position.y += 5;
                if(direction == "left")
                    world->getPlayer(player_id)->position.x -= 5;
                if(direction == "right")
                    world->getPlayer(player_id)->position.x += 5;
            }
        }
        if(event == "update world")
        {
            sf::Packet send_packet;
            send_packet << "update world" << *world;
            client.send(send_packet);
        }
        if(event == "destroy item")
        {
            std::string item_id;

            if(packet >> item_id)
            {
                world->removeItem(item_id);
            }
        }
    }
}

 
So it's simple, maybe not clean but it's only to show idea.
I hope it's help on the beginning. I know it's hard to find easy tutorials about making multiplayer games so I hope it's good for beginners.

When you understand the basics which you get from this tutorial, you can start doing it like professionals. Just find out more from forums, other blogs etc.

Here is more code and working project that I do in free time, of course you can help me :)
https://github.com/Patys/pmr

Hope it help. If you have any question, just leave comment. Good luck and see you.

1 comment:

  1. Thanks :) I try to remember when I was beginner and I wanted to create some awesome things but no one explain me how to do that. I will create some more advanced tutorials for beginners. Thanks again and keep coding :)

    ReplyDelete