Game Engine Agnostic Network Protocol


About The Game

This is a game that builds bridges instead of burning them. Venture into this VVVVVV inspired co-op adventure, but first each player need to choose a launcher. There exists two launchers, one made in Unity3D, and the other is made in Unreal Engine 4.

Since the physics don’t quite function the same in the different engines, you will notice that some sections might be easier to complete in one engine over the other, or vise versa.

It is up to the players to work together, playing to each of their engines strengths to help each other out.

Technical Details

Context

This game was created in during a game jam lasting about two days, any design decision regarding the protocol were therefore taken for the sole purpose of “it’s easy and its fast” instead of say, for stability reasons. I would not, for the love of god, create a real game based on these transfer methods.

Protocol Structure

The protocol is fairly simple: Each client will create two sockets, one UDP receiver, and one UDP sender. Once the game is started, the client will start sending packets in a set interval through its sender socket.

Both clients will need to know each others IP addresses beforehand. When the game starts, the game client will start sending data regarding the game state to the stated partners IP address. This is obviously not great, as you might get the IP of your partner wrong, causing the game client to receive updates from his partner, but being unable to respond with his own game state. In a real game you would want to create some form of handshaking, and establish a connection before you start bombarding some random IP with information of your game state.

Any JSON data sent adheres the following structure:

{
    "gravityDirection": 0,
    "packetId": 337,
    "jsonPackages": [
        {
            "positionX": 0,
            "positionY": 0,
            "positionZ": 840,
            "angle": 0,
            "scaleX": 2,
            "scaleY": 30.5,
            "scaleZ": 1,
            "id": -1,
            "type": "Wall"
        },
        {
            "positionX": 0,
            "positionY": 0,
            "positionZ": -300,
            "angle": 0,
            "scaleX": 3.5,
            "scaleY": 31.75,
            "scaleZ": 1,
            "id": -2,
            "type": "Wall"
        },
        {
            "positionX": 0,
            "positionY": -1020,
            "positionZ": 737.74993896484375,
            "angle": 0,
            "scaleX": 1,
            "scaleY": 1,
            "scaleZ": 1,
            "id": -3,
            "type": "testCubePlayer"
        }
    ]
}

Each packet contains any objects that needs updating, as well as their transform. As you can see, we might send a great deal of information each packet as the number of objects that need updating grow. On larger levels it would completely saturate any connection if you needed to send information about the entire level each frame. What is instead done, is that each client agrees only to send information about objects which has changed. This does create a problem of removing objects, which is why an agreed time-out time of a few seconds has been defined. It is up to each client to ensure that objects does not time out on the other client, and to send information regarding them every now and then to avoid the object timing out.

It is important to note that in order for for both players to operate on the same level, each player needs to bring over their part of the level for the other player to see. To build a level, all you have to do is use either the Unreal Engine 4, or the Unity3D level editor and use objects with agreed upon measurements (hence the “type”: “Wall” entry in our protocol). When a level is played, each game engine runs some custom code which runs through the level to find and object which matches any agreed upon object type. It then send information regarding this object its connected partner, causing the partner client to spawn said object if it cannot find an object which corresponds to the object id received.

Although this looks incredibly addock and sketchy (and it is) it does have some fun side-effects. A level can for example be completely built in Unity, using agreed upon measurements of objects, and then be played on the unreal client without ever having to touch the level editor.

In this game we added the following objects:

  • Wall
  • Spike
  • testCubePlayer (terrible name I know)
  • checkpoint

Adding new objects is simple. Agree on an Id, measurements of the object, its effects, and then add the object to each client and have it spawn when an object of the corresponding id shows up in a received packet.

Source for both the Unreal Engine 4 and Unity3D versions can be found here.