Creating a Cross-Platform Multi-Player Game in Unity — Part 2

In the second part of this tutorial, you’ll write the code to have users connect with each other and then get a race started! By Todd Kerpelman.

Leave a rating/review
Save for later
Share
You are currently viewing page 6 of 6 of this article. Click here to view the first page.

Receiving Message Data

In MultiplayerController.cs, replace the code of OnRealTimeMessageReceived with the following:

// We'll be doing more with this later...
byte messageVersion = (byte)data[0];
// Let's figure out what type of message this is.
char messageType = (char)data[1];
if (messageType == 'U' && data.Length == _updateMessageLength) { 
    float posX = System.BitConverter.ToSingle(data, 2);
    float posY = System.BitConverter.ToSingle(data, 6);
    float velX = System.BitConverter.ToSingle(data, 10);
    float velY = System.BitConverter.ToSingle(data, 14);
    float rotZ = System.BitConverter.ToSingle(data, 18);
    Debug.Log ("Player " + senderId + " is at (" + posX + ", " + posY + ") traveling (" + velX + ", " + velY + ") rotation " + rotZ);
    // We'd better tell our GameController about this.
}

You're basically doing the opposite of what SendMyUpdate does; instead of putting data into a ByteArray, you're extracting it into useful values that you can use in your game. System.BitConverter.ToSingle() takes a ByteArray and an offset, and converts those bytes into a native data type.

Now that you have the information you need, you can do something useful with it. Add the following interface definition to MPInterfaces.cs:

public interface MPUpdateListener {
    void UpdateReceived(string participantId, float posX, float posY, float velX, float velY, float rotZ);
}

Next, add the following public variable to the top of your MultiplayerController class:

public MPUpdateListener updateListener;

Then, add the following to the end of the if block in OnRealTimeMessageReceived, right after the We'd better tell our GameController about this comment:

if (updateListener != null) {
    updateListener.UpdateReceived(senderId, posX, posY, velX, velY, rotZ);
}

Go back to GameController.cs and declare that it satisfies the MPUpdateListener interface as follows:

public class GameController : MonoBehaviour, MPUpdateListener {

Then add the following method somewhere inside that same class:

public void UpdateReceived(string senderId, float posX, float posY, float velX, float velY, float rotZ) {
    if (_multiplayerReady) {
        OpponentCarController opponent = _opponentScripts[senderId];
        if (opponent != null) {
            opponent.SetCarInformation (posX, posY, velX, velY, rotZ);
        }
    }
}

Here you're checking that _multiplayerReady is true, as there's always a chance you could receive a message before you're done your setup; if you don't protect against this you could end up with some fun and exciting null pointer exceptions.

If everything checks out, you then call SetCarInformation() on the OpponentCarController corresponding to the participantID of the sender.

Now open OpponentCarController.cs and add the following method:

public void SetCarInformation(float posX, float posY, float velX, float velY, float rotZ) {
    transform.position = new Vector3 (posX, posY, 0);
    transform.rotation = Quaternion.Euler (0, 0, rotZ);
    // We're going to do nothing with velocity.... for now
}

There's nothing too surprising in SetCarInformation; you simply set this car's position and rotation to the values reported by its game client.

Finally, go back to GameController and add the following line to the top of SetupMultiplayerGame():

MultiplayerController.Instance.updateListener = this;

In the code above, GameController tells MultiplayerController that "I am the class you should talk to when you get an update from another player in a multiplayer game." So MultiplayerController will call UpdateReceived() in your GameController, which will then call SetCarInformation() on the appropriate OpponentCarController object.

Build and run your app on both devices; you should now be able to move your car on one screen and see its movement reflected on the other screen. Move both cars on both devices at the same time, and hey — you've got yourself a racing game! :]

Look, ma! We're racing!

Victory!

If everything hasn't gone well, I'd suggest you try the following two things:

  • Make sure you're running the latest version of the game on both devices. Sometimes I'll update my game on only one device and forget that I need to load it on the other as well.
  • Kill the app on both devices and try again. Sadly, the "try it a second time and maybe it will magically work this time" solution seems to work for multiplayer games more times than I'd care to admit.

Where to Go From Here?

You can download the completed project over here.

Your multiplayer racing game is off to a really good start, but there still are a few problems that you'll need to address:

  • A biggie: the game doesn't end! You'll need a way to declare a winner and leave the room.
  • You're making network calls more frequently than you need to. It'd be nice if your game was a little more considerate of your user's battery and data plan.
  • Depending on your network connection, the cars' movements might look a little jittery. You need a way to smooth them out and make the animation look fluid.

Luckily, these are all relatively easy issues to fix — and you'll address them all in Part 3 of this tutorial series. As always, if you have any questions or comments, please feel free to join in the discussion below!

Todd Kerpelman

Contributors

Todd Kerpelman

Author

Over 300 content creators. Join our team.