How We Created an MMO in Unity for FROG using Socket.IO


As new developers with Unity, we found it quite unclear as to the best route to take to make on online multiplayer. Instead of going back and forth between possibilities, we took a quick look at Socket.IO and ran with that! We had used it before for a small, chat client college project and we hoped we could bend it into something that we keep our online game running smoothly!

TLDR: Socket.IO is great and lightweight! Go use it for your Unity online game!

Socket.IO ended up being extremely lightweight and relatively easy to get up and running. The Unity integration that we used is on github at the following address: https://github.com/floatinghotpot/socket.io-unity

It has been a little while since it has seen any love but it definitely still worked for us.

How Socket.IO works is that you have a dedicated server with a node Socket.IO server set up on it. We used this to manage all of our players and their actions. Each Unity client then communicates with the server to get up to date information as to what other players are online and other attributes like their current position.

We took the files from the Lib/ folder and moved them to the Packages folder in our Unity project. Then you are good to import it into your scripts and use it!

There are some core components of Socket.IO that we used to build out the functionality for FROG.

Clients or the Server can send updates by using socket.emit(). So an example of this would be if you move your player, you will “emit” your new position to the server or the server can “emit” the current list of players to your client when you join the game.

After something has been emitted, the message then needs to be received correctly and that is done with socket.on(). You create a socket.on() for every socket.emit() that is used. So for example, the server will have a socket.on(“update-player-position”) to receive position updates that have been emitted from the individual clients.

A slight variation on this is another call that we have on our server and this is socket.broadcast.emit() and this sends out an update to all clients as opposed to just one. If we receive a new position from a client, we then need to update all of the other clients of this change and we can do that using socket.broadcast.emit() to “broadcast” the message out.

Let's look at some code snippets!

An Example

In this small example, I am just including a few snippets that describe some communication back and forth between the server and the clients. Event names like “player-join” are what both sides listen for. Once they receive one of these event names they go and do their thing!

E.g. Client joins → “player-join” → Server → “new-player” → all online players

Server Snippets (JavaScript)

When a new player joins...

    socket.on("player-join", function(msg){    
        var received_player_info = JSON.parse(msg);
        
        // Create player object with received information    
        player_info = {      
            uid: socket.id,      
            username: received_player_info.username,      
            position: received_player_info.position    
        }
        // Convert the current list of players to JSON    
        var player_json = {      
            list: list_of_players    
        }    
        
        // Send the current list of players to the new player    
        socket.emit("player-list", player_json);
    
        // Add new player to the current list of players    
        list_of_players.push(player_info);    
        console.log(list_of_players);
        // Broadcast the new player information to all of the current players    
        socket.broadcast.emit('new-player', JSON.stringify(player_info));  
    });

When a player moves…

    socket.on('update-player-position', function(new_position){    
        // Find the player element that matches the socket id    
        let player_object = list_of_players.find(obj => obj.uid == socket.id)
        // I wrap the position update in a try catch to remove the odd error    
        try {      
            // Update our local player object with the newly received position      
            player_object.position = new_position    
        } catch {}    
        // Broadcast the new information out to all the players    
        socket.broadcast.emit('broadcast-move', player_object);  
    });

Player Code (C# with Unity)

When you join the game…

using Quobject.SocketIoClientDotNet.Client;
.
.
.
socket.On(Socket.EVENT_CONNECT, () => {
    // Convert our player info object into a json string                
    string playerInfoJson = JsonUtility.ToJson(playerInfo);
    
    // Send our information to the server                
    socket.Emit("player-join", playerInfoJson);
    
    // Setup the different events, like the ones describes after this section                
    socket.On("example-event-from-server", (data) => {
        // Smarts go here                
    }                
    });
    socket.On("another-example-event-from-server", (data) => {
        // Smarts go here                
    }                
    });
});

When a new player joins…

[Serializable] 
public class OnlinePlayerInfo {     
    public string uid;     
    public string username;     
    public string position; 
}
.
.
.
socket.On("new-player", (data) => {
    // Create an instance of the serialisable JSON class                    
    private OnlinePlayerInfo onlinePlayerInfo = new OnlinePlayerInfo(); 
                   
    // Store the newly joined player online to a class                    
    onlinePlayerInfo = JsonUtility.FromJson<OnlinePlayerInfo>(data.ToString());
    // Add the new player to the buffer of players to be created in Update()                    
    spawnBuffer.Add(onlinePlayerInfo);
    // Add the new player to the list of online players                    
    onlinePlayerList.Add(onlinePlayerInfo);                    
    Debug.Log("A new player has joined the server!");                
});

When a player online moves…

socket.On("broadcast-move", (data) => {
    // Create a new object for the online player                    
    OnlinePlayerInfo onlinePlayerObject = new OnlinePlayerInfo();                    
    onlinePlayerObject = JsonUtility.FromJson<OnlinePlayerInfo>(data.ToString());
    
    // Search for the online player in the list of online players                    
    for (int i = 0; i <= onlinePlayerList.Count; i++) {                        
        if (onlinePlayerList[i].uid == onlinePlayerObject.uid) { 
            // Update the position of that player in the list of player information                            
            onlinePlayerList[i].position = onlinePlayerObject.position;
            // Add the new information to the update buffer to update the game object in Update()                            
            positionUpdateBuffer.Add(onlinePlayerList[i]);                        
        }                    
    }                
});

Conclusion

Given that this was our first time attempting an online multiplayer game, we found Socket.IO very easy to get up and running and then manage as it scaled.  If we needed to add a new feature, it never took more than a few minutes to add the code for the server and the client.

It is worth noting that we only have about 15-20 players online at peak times but even at that, the server CPU barely registers any activity on our 5$ DigitalOcean droplet.

If you have gotten this far and want some more information on specifics of how we implemented something, just let me know in a comment or email me at james[at]poole[dot]ie.

Also feel free to sign up to my small mailing list at: http://eepurl.com/g0lA5v

Check out more bits and pieces at james.poole.ie or at my blog.

Lets create games together and I will keep you up to date with the things that I am building!

Get FROG

Download NowName your own price

Leave a comment

Log in with itch.io to leave a comment.