I'm not a game developer, but Unity is really easy to learn

Late last year, with all the talk of the metaverse in the air I started getting curious about 3D visualizations and whether my skill set was anywhere within striking distance of the subject.  I have intermediate 3D modeling skills and can otherwise hack together anything with open source software so the missing element is a larger framework for running the visualization.  This was starting to sound suspiciously like a ... video game.

I figured that a good place to start would be checking out existing game development frameworks, and I suddenly wondered how hard would it be to make a game?  I followed my curiosity.

Choosing a Framework

I took stock of my options and it seemed that my choice was between Unity and Unreal.  I read a lot of opinions and ultimately settled on Unity because I believed it had better community support, and the consensus seemed to be that it is easier to learn. The amount of children giving Unity tutorials on YouTube seemed to back this up.

So what is a framework?  To me, a framework is the glue that holds everything together; the 3D models, the 3D rendering, and the code that handles everything - including user inputs and any external inputs.  

I don't remember installing Unity, which means it must not have been that bad. I can report that it works great on Ubuntu.  I did have to register for an account with Unity Hub which all seemed unnecessary, but the whole thing was actually very streamlined.

Before I knew it I had the blank canvas of a new project sitting in front of me.

Why C#?

I don't know / I can't remember why ( something to do with Microsoft? ), but the important point is that there is no other API within the Unity framework. So it really doesn't matter how I feel about learning a little C# as it is the only choice ( I'll complain later ).  Having experience with C++ and Javascript helped to fumble through it with a little help from some tweens on YouTube.

My Game

The fun part!  I learned how to add some basic objects to my scene, a plane and a ball.  I learned to make them interact (collide) and when the plane was tilted the ball would roll off into oblivion.  I just kept making it more complex and learned along the way how to:

  • Add textures to objects within my scene
  • Handle user keyboard inputs and affect objects in the scene
  • Detect and handle collisions between objects
  • Have a camera track an object as it moves
  • Restart the game / scene

Before I knew it I had something that could easily be mistaken for a game created by a child.  The little blue ball has to fight his way up the ramp while trying to collect green pills and trying to avoid the red Satan pills. Green pills add to the player score, but also increase the size of the green ball which makes it harder to avoid the red pills.

There are countless things I would improve, but it is actually pretty fun to play as-is.

Reality Check

I'm not a Game Developer, I'm not even a gamer.  I also wasn't loving C#.  I didn't want to spend too much more time learning a language for the sole sake of curiosity.  I also wondered how 'portable' the outputs of a Unity game were, and specifically if they could be run in a browser?

Exporting

I first had to set WebGL as the selected platform and check the player settings:

Be sure that the scene is included in 'Scenes In Build' list!

Then 'Build and Run' exported the files to a selected directory. Cool.

I opened the index.html and I get errors.  For good security reasons, browsers don't let you load just any type of file asset from the computer (your computer's) file system.  You can  find instructions for how to disable some of these features of the browser, but that obviously isn't the solution. We have to host this thing.

Structure of my 'project'

drwxrwxr-x  4 anthony anthony 4096 Dec 17  2021 .
drwxrwxr-x 43 anthony anthony 4096 Dec 17  2021 ..
drwxrwxr-x  2 anthony anthony 4096 Dec 17  2021 Build
-rw-rw-r--  1 anthony anthony  146 Dec 16  2021 docker-compose.yml
-rw-r--r--  1 anthony anthony 4477 Dec 17  2021 index.html
drwxrwxr-x  2 anthony anthony 4096 Dec 17  2021 TemplateData

The actual game assets being in Build

$ du -h Build/*
1.4M	Build/FirstWebGLBuild.data.unityweb
84K	Build/FirstWebGLBuild.framework.js.unityweb
40K	Build/FirstWebGLBuild.loader.js
3.6M	Build/FirstWebGLBuild.wasm.unityweb

I interpret that as my game is 3.6M. I could optimize this by serving the file with gzip

All the runtime details captured in docker-compose.yml form:

version: '2'
services:
  webgl:
    container_name: webgl
    image: nginx
    ports:
     - "3000:80"
    volumes:
     - .:/usr/share/nginx/html

This is an "off the shelf" nginx image with my file assets mounted into the nginx "document root" (where files go that are being served).  The image automatically starts nginx on port 80, proxied to 3000 on the host, which is my laptop.

Then docker-compose up and at localhost:3000/ I get:

This was a great way to play the game, it seemed like the browser was able to render things just as smoothly as I saw in the Unity framework previews. I played it enough to come up with a whole list of things that would make it better / more fun.

  • regenerating / continuous flows of green and red pills
  • animating the size changes of the blue ball
  • simply show scoring information on the game viewport

Then I had slow down because I realized how easy it would be to fall down this rabbit hole. When working to make something more fun is the goal, then there is no reasonable expectation for when something is good enough.  I could endlessly make improvements to my game ( some of them which would involve learning some very complex and enriching new subjects ), but ultimately it will be judged by how fun it is.  I think it would be frustrating to have the outputs of my work judged so subjectively.

New Directions

Now that I was competently loading the game in the browser, I got curious about how I could make my game interact more with the browser's Javascript runtime environment. I wanted to know to what extent I could build an API-like interface between my my game and another javascript application running in the browser.  ( Think of it as sending inputs to the game and getting outputs from the game )

A lot of research later and I've learned that there is an interface but it doesn't feel ... that good. This page is super helpful.

Sending nput into the game using javascript in the browser:
so a C# method in a script attached to a game object ( in a game exported to webGL running in a HTML / browser ) like this ( this example updates the scoreboard ) :

void callExternally (int arg) { scoreText.text = arg+" points";}

can be called from Javascript running in the browser ( with access to the unityInstance of the game instnace ) like this:

myGlobalInstance.SendMessage('GameObjectName', 'callExternally', 9)

This works but is frankly kinda limited. Passing data works but it wasn't immediately clear how I would get data responses.  

I realized again that developing games was not actually where my curiosity was headed.  It turns out that there is a very similar framework that handles WebGL in the browser and is designed to be integrated with JS apps called Three.js.  It's not game-oriented at all, just a blank canvas rendering 3D models.

I realized that I was interested in building live 3D visualizations that integrate with larger applications. I had the ideal project in mind and I'll tease a future post with this screenshot:

Rover with no idea about its surroundings. I'm hoping to give it some localization data.

My next project is a live visualization of one of my robot projects.  On the simpler end of the spectrum this could show the state of the robot, like wheel directions and speeds. More complicated will be to try to localize it with data from QR codes seen by the camera and render its movements in relationship to surroundings.

I was jamming right along until ... Quaternions ! Ouch! My brain.