Ping Pong

Unity Game Engine & HTML5 Socket Mashup

Back in March I revised the HTML5 multiplayer node.js example to use WebSockets instead of RESTful calls. Moving to this event based system of communication allowed for more streamlined code and native multithreaded performance. If you haven’t had a chance to read the previous posts in the node.js series, you can catch them here:

Before reading ahead, grab the code under the sockets branch.

Playing Nicely

HTML5 is great and all, especially with the fantastic Pixi.js renderer, but what if I wanted to reach beyond a browser? I could have wrapped the existing HTML5 implementation in an app and called it a day, but performance and blog material would suffer. That is where Unity joins the party. Unity is a popular tool for producing cross platform games and experiences for almost every device out there. Grab Unity it to follow along.

Getting Started

My goal was to keep the existing backend service and just treat the Unity app as another client. This had the added benefit of HTML5 clients playing in the same sandbox as the native app. Once you have Unity installed, and your first project created, you’ll need a few more things. In the Unity Asset store, find and install the following to your project:

SocketIO
A Unity implementation of socket.io.

LeanTween
A popular tweening engine for Unity.

Scene Setup

OK, now that we have all the prerequisites we can focus on the build. Keep in mind that this is a sample and not intended for production use.

1. Enabling WebSockets in Unity

Thanks to the makers of SocketIO, this is incredibly easy. Add the SocketIO prefab to your scene.

Blog Image

After you have dropped the prefab into the scene, select it from the Hierarchy window and look at the properties on the right. For this sample I opted to connect via code, so uncheck Auto Connect.

Blog Image

2. Creating a Player Avatar

  1. Next, create and Empty GameObject by choosing GameObject -> CreateEmpty and rename it to PlayerBaseObject. In the Inspector on the right, set the position to 0 (zero) for X, Y and Z values.
  2. Create another object, this time with a mesh with the top menu option GameObject -> 3D Object -> Sphere. Rename that object to PlayerBaseModel.
  3. Then click-n-drag PlayerBaseModel into PlayerBaseObject so it looks like this…Blog Image
  4. Create two materials and name one PlayerMaterial and the other OtherPlayerMaterial. Create a new folder under Assets called Resources and move OtherPlayerMaterial to that folder.Blog Image This is required to be able to dynamically assign the material during runtime.

3. Scenery

We will need something as a backdrop to our player spheres. Create a ground plane by choosing GameObject -> 3D Object -> Plane. Move this plane down so it is just below the sphere you created earlier. Rename the plane to GroundPlane.

4. The Game Controller

This is the code that will manage interactions, connections and game state. Create an empty game object by by choosing GameObject -> CreateEmpty and rename that to GameController.

Now your scene should look something like this…

Blog Image

Code Time

With the Unity scene setup, you can now start coding. Rather than presenting all the code for you here, I’ll focus on key differences between the HTML5 version and this Unity client. Grab the Git repo and then copy the sample class, GameController.cs into your project by selecting Assets -> Import New Asset… You can find the sample under NodesSockets->Assets. Once imported, drag the GameController.cs class to the GameController GameObject like so…

Blog Image

Assigning the Player Avatar

After you assign the GameController code, select the GameController object and look at the inspector on the right.

Blog Image

Note the property called Player Base Object. This exists because of the public GameObject code declaration here:

public GameObject PlayerBaseObject;

Now select the dot to the right of the field and pick the PlayerBaseObject from the Scene list. This tells the code to assign that object to the PlayerBaseObject field at runtime.

Adjust Coordinate System

From here on out the code comes very close to mirroring the browser based version but reorganized into a Unity MonoBehaviour. I’ve opted to use Unity’s default scene scale and orientation, which doesn’t exactly match the HTML5 canvas. To compensate, the following values are used as multipliers during updates:

private float _coordScaleFactorX = 0.01f;
private float _coordScaleFactorY = -0.01f;

Startup

With MonoBehavior as the base class, there are two methods called by the game engine during runtime: Start and Update. As you probably guessed, Start is only called when the app starts. Update is called once per frame.

In Start we do some housekeeping and initializations.

 

SetVisibile (PlayerBaseObject, false);

Hides our base player object so we can create new instances as the real players.

 

GroundPlane = new Plane(Vector3.up, transform.position);

Creates an invisible ground plane to use as a target for mouse clicks. The visible one in the scene is only there for visual representation.

 

_socketObject = GameObject.Find(“SocketIO”);
_socketComponent = _socketObject.GetComponent<SocketIOComponent>();
_socketComponent.On(“enteredGame”, EnteredGame);
_socketComponent.On(“playerDisconnected”, PlayerDisconnected);
_socketComponent.On(“playerChanged”, PlayerChanged);
_socketComponent.Connect ();

This code finds the SocketIO prefab instance, assigned the event methods and connects to the server socks as set in the URL field.

Blog Image

Animation and Frame Updates

To capture the mouse click event and find the coordinate clicked, see the following code.

if (Input.GetButtonDown(“Fire1")) {
     var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
     float distance;
     if (GroundPlane.Raycast(ray, out distance)){
          Vector3 hitPoint = ray.GetPoint(distance);
          SetTarget(hitPoint);
     }
}
UpdateLocalPlayer ();

On each frame we need to determine if our player has moved and if so emit a message indicating where it moved to. This method can be improved by limiting the frequency of updates to an interval of frames rather than on every frame.

Action

The remainder of the code is almost identical to the JavaScript version with minor differences to accommodate C#, a strongly-typed language. So lets build and run the app to see it in action!

First, don’t forget to start the node server and browse to :3000 in any number of browsers.

slc run

Then in Unity, choose File -> Build & Run. If all is well you will see something like this…

Blog Image

Bringing the console windows to the foreground we can see the debug logs.

Blog Image

Blog Gif

Next Steps

Now that we have Unity and HTML5 running on the same node.js backend, what can we do with this power? Stay tuned for my next post where we throw VR into the mix.

Other Posts in This Series

Related Links

Let us put our HTML5 skills to work for you! Contact us to find out how Liquid can help.