Making Dark Nova: Learning Phaser and Deploying with GitLab CI to AWS

This is a series of some things we learned while making Dark Nova, currently in alpha. It was originally posted at Ryan's blog

Intro

There are a handful of tutorials concerning both Phaser and Typescript, but they are somewhat old at this point, usually rely on a full Visual Studio install, and don't go into actually hosting your game. While developing Dark Nova I found a plethora of easy to use, cross-platform tools facilitating good development practices and fast iteration for our team. I'm hoping this series can be a working introduction to devops with indie game dev. By the end, we will have a simple game with some networking running in AWS, and employing a full CI\CD pipeline through Gitlab. Multiplayer networking architecture and "netcode" are beyond the scope of this series. If you are looking for specifics surrounding networking, Glenn Fiedler has an excellent site on a multitude of those topics (seriously go read his stuff). The itinerary for this series follows:
  1. (This post) Foundational development tools and running a Hello World-like game. Building this game using Gitlab's CI runners every commit to master
  2. Add Mocha and Chai for some unit tests and a 2nd Stage to the CI pipeline for testing
  3. Deploying our project to AWS by hosting it on S3 and adding a 3rd CI Stage for deployment
  4. Adding some simple networking and a server. Add Terraform to deploy every commit to master
  5. Setup Terraform and Gitlab CI to deploy a new environment on every feature/* branch. Optimize build times using a custom docker image. Further optimize spinning up our own dedicated gitlab job runner.
Prerequisites (* - this post):
  • *Node installed
  • *An account on GitLab
  • An account on AWS. I will be using only free tier capabilities, but know that if you are already using AWS free tier you run the risk of going over the limit (still fairly cheap ~8$ a month for a t2.micro)
  • Terraform installed
  • A text editor (I'm using vs code). I won't be using any platform-specific extensions or build tools. I use Powershell (I use conemu), but Windows is not required here - in fact it proved to be more difficult when it came to docker in later steps.

Setup

Here we'll set up git, Typescript, Phaser, npm and gulp. ** If you don't care to do setup step by step, you can just pull the setup project as of this commit and skip to CI setup. ** Create folders, initialize git, npm, Typescript, Phaser, and install a handful of gulp tools we'll use to build our project: https://gist.github.com/ryanhallcs/2e56a68797984cd90a643b6ff605d8ca npm options above are for -g(lobal), -S(ave dependency), and -D(evelopment dependency). The distinction is if you want the package installed system-wide, for production runtime, and for development-only packages, respectively. Create a simple .gitignore in your root project - just use Microsoft's prebuilt one for typescript: https://github.com/Microsoft/TypeScript/blob/master/.gitignore We'll be using the code from Phaser's own 'Getting Started' project. Download the image needed here and put into the assets folder, named "phaser.png": You'll want to update your typescript config for now. I have mine set to the following, which is more lax about "implicit any", excludes folders we don't want compiling, and defines dist as our output directory: https://gist.github.com/ryanhallcs/319f56f5ab439ad86a50948b270cc01b Create the following game.js file in the src directory: https://gist.github.com/ryanhallcs/4a3f891276e9d688986df340cb9e2066 Create an index.html and place it in the src folder: https://gist.github.com/ryanhallcs/de8137100d4689caba94f853e51bff91 I use Gulp pretty heavily. It adds a nice layer above the messiness of cramming npm scripts in the package.json, and more control with an array of helpful libraries at your disposal. Create gulpfile.js in your root folder: https://gist.github.com/ryanhallcs/a85eac4586beec25799c89b888787a4e Browserify will help package all of your typescript up into a browser friendly entrypoint that you hand off to browser-sync. Browsersync is invaluable in that, along with gulp-watch, it will allow you to recompile and refresh all browsers pointing to your local testing server on a change. You should now be able to run gulp serve and see your game pop up in a browser! phaser-browser Go ahead and change the width of your game in game.ts, save, and watch the changes happen without manually rebuilding or refreshing.

Continuous Integration

Gitlab provides a feature rich CI platform you can plug into in many ways along with free shared runners to build, test, and deploy your projects. It's incredibly easy get started using a base set of features: create a .gitlab-ci.yml file in the root of your project, define a few things, and push. Gitlab will, by convention, kick off a pipeline conforming to the file's directions. For now we will simply tell the runner to install the included dependencies, and run the default gulp task which ensures our project builds on every commit to master. Add this file to the root of your project and name it .gitlab-ci.yml: https://gist.github.com/ryanhallcs/aaf7f15b400029fe5291efd5f7f91ae9 Here is a breakdown:
  • image: node:6 tells the runner this is the docker image we need. This will ensure node and npm are installed and available at the command line. You can build your own docker images for more advanced use cases and provide them here as well.
  • build: Defines a new stage called build
    • type: build: Tell Gitlab this stage is of type build. See the docs for details on how Gitlab uses this convention
    • script: define a script block. This is where we can put in line by line commands or kick off our own shell script
    • npm inpm i gulp -g and gulp: you should recognize these as simply installing your package.json dependencies, installing gulp globally, and running the default gulp task, respectively
  • only: Run this stage only on specific branches
    • master Only build master. Commits to other branches will not kick off this stage
Shared runners tend to get pretty backed up. Adding your own runner for your project (it can be in the cloud or your own computer) is left as an exercise to the reader. Add the file, commit, and push to Gitlab. Go to your Gitlab project page, navigate to the Pipelines tab, and watch that sucker kick off. You can drill down into the stage the pipeline is currently on (remember ours only has one - build) and watch the runner output in real time. You should now see a nice green check indicating a successful build on that last commit: gitlab-pipeline-pass In the next post we will add some unit tests to be tested in a test CI stage, and host the game on AWS S3 in a deploy stage.