Let’s make a multiplayer game (part 5)


At this point I am going to spend to time to recap on the concepts I covered in the previous articles.

The game is designed to be a single entry point that can either operate in server mode or client mode. This is a design choice and not a requirement.

The game has the following common responsibilities in both server and client mode.

  • Update game objects. Each of our game objects have their own logic which needs to be processed. In this game it is typically the physics logic to allow the objects to move around the screen.
  • Apply game logic. An example of game logic is the processing of collisions between game objects. This behaviour needs to be handled consistently on both the client and server to ensure the responsiveness of the game.
  • Draw game objects. The game obviously needs to render the scene.

When the game is running in client mode it is also responsible for the following.

  • Notify the Server of player actions. When the player performs an action we need to execute it on the client to provide immediate feedback. We also need to inform the server of the action so that it does not override the player state during the next update cycle.
  • Respond to messages from the server. The client needs to respond to server messages to ensure that the client version of the simulation is synchronised with the server version.

When the game is running in server mode it responsible for the following (in addition to the common elements).

  • Respond to messages from the client. The server needs to process messages received from the client. Here the server can override any invalid requests and the action will be reverted on the client.
  • Notify clients of game object changes. The server needs to send out periodic state updates to all the clients. I call this the heartbeat update as it should happen at a regular time interval.
  • Create game objects. The server is responsible for the game state, by not allowing clients to create objects we can be fairly confident of a synchronised simulation.
  • Delete game objects. This is the inverse of creating objects again we do this on the server to ensure consistency.

We encapsulate our game network messages in a message class that implements the following IGameMessage interface.

public interface IGameMessage
{
    GameMessageTypes MessageType { get; }

    void Encode(NetOutgoingMessage om);

    void Decode(NetIncomingMessage im);
}

The MessageType property is used to identify our game messages and should be the first byte sent and received for every game message.

The Encode and Decode methods should mirror each other exactly. This will eliminate a lot of errors that could occur when sending and receiving messages.

public void Decode(NetIncomingMessage im)
{
    this.Id = im.ReadInt64();
    this.MessageTime = im.ReadDouble();
    this.Position = im.ReadVector2();
    this.Velocity = im.ReadVector2();
    this.Rotation = im.ReadSingle();
}

public void Encode(NetOutgoingMessage om)
{
    om.Write(this.Id);
    om.Write(this.MessageTime);
    om.Write(this.Position);
    om.Write(this.Velocity);
    om.Write(this.Rotation);
}

I recommend always sending the NetTime.Now value along with the game message as it is useful in determining the exact latency when the message is processed as well as filtering out of sequence messages.

I think that covers the main ideas I wanted to review. In the next article I will add the PlayerManager class which will allow us to control the player ship.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s