Friday 6 February 2015

Setting up your project with Grunt and RequireJS

Before we get into the meat and potatoes of our app. We must get the mundane details out of the way.
I would like to dive straight into the graphics and AI stuff, but thought a small primer on getting a nice working environment set up would be worth while in the long run.

There are many ways you can set up your project structure and many ways to host it.

I have chosen to host mine on Heroku via a Ruby On Rails project.

This Rails project will serve up our Javascript application and also may some day serve as a back end to serve data to our games.
I am thinking of using Pusher to share data across devices at some stage, and the Rails application will allow us to do this.

Setting up the Rails app and running it on heroku is outside of the scope of this blog. There are many tutorials online on how to achieve this.

I have included the source code of the project I am working on in tandem with this blog, and will link to the tags where necessary.

Here is the tagged version of the codebase, relating to this blog post.
And here is the current codebase.

See here for an example of the end goal we are trying to achieve


So, now let's get to some coding.


Setting Up Grunt


We will use a Javascript build tool called Grunt to automate some of the tasks required to bundle our code into a runnable application.

I have created a source directory in the rails project root called 2djssrc. This is where our source code will reside. We will rely on some grunt tasks to compile all of our code into the rails public folder which will then be served up to the user. We will also use a Javascript package manager called Bower to manage our Javascript plugins.

To get Grunt set up, you will need to install nodeJS and the node package manager. Here are some guidelines.

These steps will mean you now have a package.json file in your source directory that specifies the node dependencies. This file will list our grunt plugins later on.

Now, our Gruntfile.js is where all the magic happens. This simply contains all of our tasks that will help us to get our code to run.
To run a grunt task, we simply run:

grunt TASKNAME
Tasks can depend on eachother as follows (Don't worry about what each task does right now, the fact is that they can depend on eachother):

grunt.registerTask('compile', ['haml', 'sass', 'coffee', 'requirejs']);
grunt.registerTask('dist', ['compile', 'copy:assets']);
grunt.registerTask('default', 'dist');

If you leave out the taskname, then grunt will run whatever task you have configured as the default. More on Grunt later.


Setting Up Bower


So, we want to use some nice JS plugins. There are so many out there that do great things, so why reinvent the wheel?
Bower to the rescue.

npm install -g bower
This will give you access to the command:

bower install
We just need to tell bower where to install our downloaded plugins.
We do this by placing a .bowerrc file in our project root, with the content:

{ "directory": "src/javascripts/bower_lib" }
Now, let's try it out and install jquery.

bower install --save-dev jquery
You will see the library now in src/javascripts/bower_lib
You can search bower for packages with:

bower search PACKAGENAME
We will use bower to install dependencies needed in our project such as box2d. The source will be included in later blog posts so you will actually not have to run these commands, but get used to the syntax.


Directory Structure And RequireJS


So, we are working inside our 2djssrc directory.

We are going to use Coffeescript to write the our application. Coffeescript will compile down to javascript.
I find it saves a lot of needless typing and has really concise, readable syntax.

Looking at the source, you will notice that there is a directory named coffeescripts and also a directory named javascripts. We will write our code in the coffeescripts directory. We will use a Grunt plugin to compile our coffeescript code into it's associated javascript counterpart, and then we will feed all of that code into another grunt plugin (grunt-contrib-requirejs) that will compile it all into one single file by traversing all of the requireJS dependencies. That was a mouthful! But, really all it means is that we need to do the following (see the github repo for the actual code):

Tell node you want some packages:

npm install grunt-contrib-coffee --save-dev
npm install grunt-contrib-requirejs --save-dev

Now, enable these packages in your Gruntfile.js, by adding the following to the file:

grunt.loadNpmTasks('grunt-contrib-coffee');
grunt.loadNpmTasks('grunt-contrib-requirejs');

In the Javascripts directory, we see two already existing directories lib and bower_lib. The lib directory contains some Javascript libraries that we could not get through bower. They will be copied into the main js file by grunt once we run the RequireJS grunt task. The bower_lib directory is our bower library repository, where any library we get by running:

bower install --dev
is stored.

To achieve this, we must configure our grunt Coffeescript task to find our Coffeescript files and copy them into the Javascripts directory after compilation. We do this with:

    coffee: {
      options: {
        bare: true
      },
      compile: {
        expand: true,
        cwd: 'src/coffeescripts/',
        src: ['**/*.coffee'],
        dest: 'src/javascripts/',
        ext: '.js'
      }
    }

So, once our compiled js files are sitting in the javascripts directory, we can then run the requireJS task to traverse the dependencies and create one big monolithic file! We must tell requireJS where our libraries are. This is done by creating a config.coffee file and referencing it in the grunt task like so:

mainConfigFile: 'src/javascripts/config.js'
In this file we set up the paths to our dependencies. More on this here. Have a look at the source code again if you are unsure.

We then configure the task, as follows, passing it the entry point file "main" as follows:

    requirejs: {
      compile: {
        options: {
          name: 'main',
          baseUrl: 'src/javascripts',
          mainConfigFile: 'src/javascripts/config.js',
          out: '../public/javascripts/main-built.js',
          optimize: "none"
        }
      }
    }

The way the above works is that it looks for the file main.js in the "baseUrl" directory. This file, you write yourself, and it is the entry point into your application.
It will load all other required files using the following syntax:

require([FILELIST], function(DEPENDENCIES){})
Read the requireJS docs for more on this.
Common practice is that main.js will be the entry point into your application.
From there app.js will be called, which contains your application logic.
If you look at the source, you will see that our app, at the moment simply alerts a message to the screen. Ground breaking stuff!


This is not all grunt can do.
We can use it to clean up compiled JS files in the javascripts directory that are no longer needed after compilation.
We can use it to copy over assets or any other files to other destinations in our project.
Furthermore we can run a watcher task that reloads our browser when a file changes. More on this later!
So, if you run the grunt dist task in the included project, you will see a file in the public/javascripts directory called main-build.js which includes all of our source and any included libraries we need.


HAML/SASS And Serving Up Our App


Ok, so we now have two grunt tasks which get us from a bunch of coffeescript files to a monolithic javascript file. What next?

Well, there are some libraries we need that we have to include manually.
I have manually included the requirejs library for now as I had some complications with referencing it from the html.
There is a directory in our source directory called lib. This contains any other libraries we need outside of the requirejs compilation.
We'll we use a grunt task to copy any files in this directory to public/javascripts/lib to be easily referenced.

We have to somehow serve up our app on a web page.
I like to use HAML to write my HTML, but it requires some setting up.

Again, grunt has a task for this: https://github.com/jhchen/grunt-haml2html
We create our index.haml file in our 2djssrc directory and use this plugin to compile it to public/game.html.
If you look in the index.haml file you will see that all it does is reference a file "requirejs" and also has a data-main attribute in the script tag which is used by requireJS.
This attribute must point to our fully compiled JS file from the previous grunt task.

<script data-main='javascripts/main-built' src='javascripts/lib/require.js'></script>
Note that you must install the haml gem for this. It is already included in the Rails app Gemfile, so a simple bundle command will solve this.

One last thing is that I will also use the grunt SASS plugin to compile some SASS files down to CSS. The idea is basically the same as what we did for the coffeescript files. Take a look in the source to get a better understanding.

In theory, this is all we need to get going. If we view our compiled game.html (via the /game url in our rails app) page we will hopefully see the alert message showing up.

It seems like a lot of work to get all this set up, and yes, it is a very steep learning curve.
However, once you have mastered these steps, you will benefit from fast development and modular javascript.
It will allow us to concentrate more on our application logic rather than where stuff should go.
Grunt will serve us as a great tool to automate a lot of things as we progress, so read up on it.

Hopefully, you got something from this tutorial, and it won't be long before we get into some of the good stuff.

Stay tuned!

Thursday 5 February 2015

Do we really need a native app?

As with most adolescent males, I have always been into gaming, having owned an Amstrad at 6 years old, wasting hours playing games like bomb jack. We all remember waiting for what seemed like an eternity on those old tapes to load!

Gaming intrigued me more so because I was curious as to the inner workings and mechanics that drove the games.

I wrote an essay back in college, on the history of gaming, and it was fascinating to me just how far it had come in the mere 30 years since its inception. I always knew that it would be an industry that I would love to work in. After a few years of working in web development, I decided to dive deeper into the guts of gaming, in an attempt to vary the work I was doing. Mobile gaming always stood out to me a bit more, as it seemed like an easier market to penetrate, and with the advent of smart phones and developer programs for iOS/Android, it lowered the bar for developers to get their work out there. I decided to research what was actually required to get a game to the app store.

So, did I want to build an native iOS game?

I had done some C/C++ in college, but having worked with Ruby On Rails and front end JavaScript frameworks (EmberJS, Backbone) for quite some time, I found that taking the leap back to these type of languages would only slow me down, or at least initially during the steep learning curve. I did not really feel the drive to learn either objective C or the new Swift programming language that will eventually take over the apple ecosystem. I thought that I might as well try to harness the skills I have at hand. Also, if I the game was to run on the android platform, I would have to port the code to Java and use the android SDK. Not so much fun!

Enter Phonegap, or now as it is known: Cordova. Cordova is a great little piece of software under the Apache licence that allows you to write a HTML/Javascript/CSS application (using any of the previously mentioned JS frameworks) and then simply build a native version of your application for multiple platforms such as Android/iOS/Windows Phone etc.

It all sounds too easy, right?
If you plan on writing a really heavy duty blockbuster 3D game then you might want to consider writing a native app, as with the performance of a native app over an app built with Cordova, there is simply no comparison.

For simplicity sake, however, I am going to stick with writing a simple 2D game from scratch. Well at least at first, and then include a 2D Javascript physics engine known as Box2D to do some of the heavy lifting. I will start from scratch with some simple animations and x/y coordinate manipulation so as to give you a better understanding of what the physics engine is actually doing for you once we hook it up! We will tinker with a framework called CanvasQuery which is a simple JS library for controlling your game run loop. This will allow you to read some input from the mouse/keyboard and control an on screen character, essentially creating a really simple game.
Once we have this up and running I will show you how to use Cordova to translate the game to an installable mobile app. I will show you how you can read from the devices sensors (Accelerometer), via the Cordova API.
Then we will dive into some really interesting stuff, and what I find most interesting in Computer Science. Artificial Intelligence. I will introduce some AI concepts into the games, such as hooking up a neural network to control other players.

This blog assumes some knowledge of HTML/Javscript/CSS and also some JS tools such as Grunt/RequireJS/Bower, but if you do not know these technologies too well, fear not. Our primary focus here is on the gaming side of things!

Knowledge of Vector maths might also be a bonus when we get into some more advanced graphic rendering and line of sight algorithms, but again not essential! I will link to the Box2D docs and any other required documentation for any plugins/frameworks I bring into the mix!

By the end of this, I hope to have a fairly playable mobile game written in Javascript that utilizes some sort of AI that performs reasonably well on a standard mobile device. It will never be as sharp as it's native counterpart, but for the simplicity and effort involved, I think that this route to creating a mobile game should be something you consider!

If you want to see a live demo of some of the things I have been playing around with, see:

http://canvasgames.herokuapp.com/game

Stay tuned!