Jump to content

  • Log In with Google      Sign In   
  • Create Account

Like
13Likes
Dislike

Multilevel-Multiplayer with Unity

By Sorin Albu | Published Jul 29 2014 09:05 PM in Multiplayer and Network Programming
Peer Reviewed by (dejaime, jbadams, jefferytitan)

unity multilevel multiplayer networking

In this article I will describe my experience with Unity by creating a Multiplayer-Multilevel 3D application. I'm not calling this a "game" because I intend this to be something where you don't need to shoot, or destroy, or earn money, or all other game stuff.

So what is the application doing: in a 3D environment with streets/buildings you can communicate with other users directly or leave a message at their home. For now it's simple, but in the future I want to enable voice, and home customization, and different types of buildings like: schools/companies/organizations/conference buildings.


Attached Image: StreetShot1.png


You can try this on: http://www.meeworld.net

Development considerations


Unity is a great tool, you directly work in a 3D scene where you can add objects and manipulate the terrain. For each object you can add different components, that are already existing in Unity, or you can implement those. Unity has also an Asset store where you can find a lot of 3D objects/scripts. The debugging part is also very interesting, when you run the application you can switch to Scene View and make modifications as you want and see results directly in your Game play.

I also took into consideration Unity because I'v used .NET for over 6 years, so I'm used to it. Unity also can be used with JavaScript, but for me it was easier to work with C#.

Networking


There are a lot of articles about networking in Unity, I don’t want to go deeper into that, but basically there is a MasterServer that handles the communication between applications. One of those applications can be the server that can handle the server operations, and all the clients go through the server and send information through RPC (Remote Procedure Call).

Multilevel-Multiplayer in Unity


The application currently has different streets, where there are different buildings. So a user can go to a street where can meet other users, so for that I had to send the position of the users only to those from that street. Ok, and how to do that? Unity has NetworkView.group, and SetLevelPrefix() but it didn't help me for a multilevel-multiplayer application. This was the hardest part to make, because I didn't find anywhere exactly how to do that with Unity. Of course, you can find some third-party that can be used.


Attached Image: networkViewDisable.png


Unity has the component NetworkView that synchronizes an observed component. This is working okay if you have a single scene with all the users. But if you have different scenes where the users can enter, the NetworkView with the synchronized observed component is not a good choice, because the NetworkView will send the information to all the scenes. So, the first thing to do was to disable the NetworkView synchronization and send the player state only to other players from the same level. For that the server should know on which level (scene) each player is located. So the call of the client is something like this:

On client(send the status to the server):

    void Update()
    {
                if (lastLocalPlayerPosition != localPlayerObject.transform.position || lastLocalPlayerRotation != localPlayerObject.transform.rotation)
                {
                    networkView.RPC("ServerUpdatePlayerPosition", RPCMode.Server, lastLocalPlayerPosition, lastLocalPlayerRotation,  level);
                }
    }

On server(filter the players and send the update only to the ones from the same level):

    [RPC]
    void ServerUpdatePlayerPosition(Vector3 pos, Quaternion rot, string level)
    {
            foreach (PlayerProperties player in server_OnlinePlayers.Values)
            {
                if (player.Level == level && player.NetworkPlayer != Network.Player)
                    networkView.RPC("ClientUpdatePlayerPosition", player.NetworkPlayer, p, pos, rot);
            }
    }

On other clients:


    [RPC]
    void ClientUpdatePlayerPosition(NetworkPlayer p, Vector3 pos, Quaternion rot)
    {
        var thePlayer = FindPlayer(p);
        if ( thePlayer != null && thePlayer.GameObject != null)
        {
            var controller = thePlayer.GameObject.GetComponent<ThirdPersonControllerC>();
            controller.position = pos;
            controller.rotation = rot;
        }
    }

Some Tricks


How to send custom objects through RPC calls.



Unity does not allow sending on RPC calls according to their documentation; only int/string/float/NetworkPlayer/NetworkViewID/Vector/Quaternation. To send a different type of object you must serialize the object and de-serialize. First I used strings for that but it was a problem with strings larger than 4096 chars, and then I found that that Unity accepts also arrays of bytes, so I used this feature.

For example to send an object UserMessage with different properties (Date, UserId, Message, Type,..etc.) through an RPC call, it's impossible because that object is not accepted, so I serialize the object like this:

        public static byte[] Byte_ConvertObjectToBinary(object obj)
        {
            MemoryStream o = new MemoryStream();
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(o, obj);
            return o.GetBuffer();
        }

and send through a rpc call:

networkView.RPC("Server_NewMessageAdded", networkPlayer, Utils.Byte_ConvertObjectToBinary(userMessage ));

and on the client de-serialize:

        public static object Byte_ReadFromBinary(byte[] data)
        {
            if (data == null || data.Length == 0)
                return null;
            var ins = new MemoryStream(data);
            BinaryFormatter bf = new BinaryFormatter();
            return bf.Deserialize(ins);
        }

How to attach a custom object to a game object

(that is not derived from MonoBehaviour):

I added to the game object an empty object that has a TextMesh, so on text property I serialize an object as a string, and when I need the object I de-serialize the object back and use it.

Free 3D objects


For this application I needed some 3D objects, but I'm not a 3D modeler so I needed some objects to place into the application. Sketchup is a great tool, where you create or find a lot of free 3D models. Also on Unity Asset store there are a lot of free objects.

Conclusion


Working with Unity was great, and for me was a new experience to see how 3D game application can be done. Another great thing with Unity is that the application can be compiled for: Windows/Linux/Android/BlackBerry/iOS/Windows Phone 8/unity WebPlayer/XBOX/Wii.

If you have questions or do you want to help on continuing this application please don't hesitate to contact me.

Thanks for reading,
Sorin



About the Author(s)


Software developer for over 13 years, always looking for new technologies.

License


GDOL (Gamedev.net Open License)




Comments

I like small articles. They are very understandable and fits well on the screen. Nice article.

Good article, as irlanrobson said. Concise, pratical, usefull.

Good article though serializing objects to byte[] like that isn't going to me very memory friendly I think.

Yes byte[] conversion will take some processing, and also some memory, but to send custom objects that are larger than 4096 this is the best way. The other way will be to split the message and send it with multiple [RPC] calls. What do you prefer?

I guess after the converting to a byte stream, you could run a fast compressor on it too....

very cool, if you continue you will end up with a new version of secondilfe, thanks for the article.


Note: Please offer only positive, constructive comments - we are looking to promote a positive atmosphere where collaboration is valued above all else.




PARTNERS