My Windows 8 HTML/JS App/Game Dev Setup

Oct 11 2012 Published by under Windows 8

Send to Kindle

As of this writing, I have three Windows 8 apps/games in the pipeline. Particle Art has been submitted. Falling Balls is 99% done and will be submitted by the weekend, and another game I’ve started is a bit past the prototype stage and starting real development. I wanted to share some of the basic setup principles I’ve been using and some of the things I’ve learned.

First of all, in Visual Studio 2012 (Pro or Express) I create a JavaScript Windows Store blank app. This gives you all of the needed frameworks and references along with a default.html, default.js and default.css file. Running this will give you a blank app with some text that says “Content goes here”.

Looking in default.html we see this:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Game101</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

    <!-- Game101 references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
</head>
<body>
    <p>Content goes here</p>
</body>
</html>

Pretty basic. I change that to add a canvas:

<body>
    <canvas id="canvas"></canvas>
</body>

Now, go into default.js and you’ll see something like this:

// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
    "use strict";

    WinJS.Binding.optimizeBindingReferences = true;

    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                // TODO: This application has been newly launched. Initialize
                // your application here.
            } else {
                // TODO: This application has been reactivated from suspension.
                // Restore application state here.
            }
            args.setPromise(WinJS.UI.processAll());
        }
    };

    app.oncheckpoint = function (args) {
        // TODO: This application is about to be suspended. Save any state
        // that needs to persist across suspensions here. You might use the
        // WinJS.Application.sessionState object, which is automatically
        // saved and restored across suspension. If you need to complete an
        // asynchronous operation before your application is suspended, call
        // args.setPromise().
    };

    app.start();
})();

App Lifecycle

Now somewhere in here we need to kick off our game or app. The basic lifecycle of a Windows 8 JavaScript app is:

1. The WinJS.Application is instantiated and start is called on it.

2. The onactivated callback on the application is called. This checks to see what kind of execution state the app is in. It can be A. a new activation which means it is being launched for the first time or it is being launched after the user explicitly shut it down the last time or B. a reactivation which probably means that the app was in the background and the system decided it needed to close it down to save memory or whatever. Here, you can choose to restore it’s state to what it was when it was suspended (assuming you have saved that state) so it looks like it was just sitting there waiting for you the whole time. Whether or not you choose to do that, you are now at the place where you can start your own app logic.

3. But there’s one more line there:

args.setPromise(WinJS.UI.processAll());

This processes all the custom controls on the page. In addition to standard HTML elements, Windows provides some additional custom ui elements. These are defined on the page like so:

<div data-win-control="SomeCustomControlClass" data-win-options="{option:'someoption'}"></div>

The processAll function finds those items and fills them with visible elements and logic. If you are not using any custom controls you can ignore this line or even remove it and start your game or app logic right there. But if you do have custom controls, it’s good to hold off until they are all completely instantiated. You might think that you could just put your app logic after that line, but notice that it’s a promise method, meaning that it may not complete immediately. The solution is to use the then handler of the promise, passing in a function like so:

args.setPromise(WinJS.UI.processAll().then( function () {
    // start your app here!!!
}));

In general, that’s what I do, just to close the door on any issues that could arise from controls not being ready.

Main Game / App Object

Actually, I don’t put any significant code at all in default.js other than that then handler and usually a single line to instantiate my main game or app object. As you may know from reading this blog, I’m not a big fan of pseudo-JavaScript classes, so I create an object with methods as a sort of template and instantiate a customized copy of it using Object.create. Here’s the pattern that I’ve grown very fond of:

WinJS.Namespace.define("bit101.game", {

    create: function () {
        var obj = Object.create(this);
        obj.init()
        return obj;
    },

    init: function () {

    }

});

At first I was doing it a bit more by hand like so:

var bit101 = bit101 || {};
bit101.game = {

    create: function () {
        var obj = Object.create(this);
        obj.init()
        return obj;
    },

    init: function () {

    }

});

But I discovered the WinJS.Namespace.define function which does the same thing a bit more concisely. Either way, this gives us a bit101.game object which has a create function on it. The create method clones the object with Object.create, calls init on the new clone and returns the result. I can now kick off my game or app like so:

args.setPromise(WinJS.UI.processAll().then( function () {
    bit101.game.create();
}));

Of course, don’t forget to add a script tag in default.html to load your new script:

<script src="/js/game.js"></script>

The init function becomes the “constructor” of the object. I usually start out with something like this:

    init: function () {
        var canvas = document.getElementById("canvas"),
            context = canvas.getContext("2d");

        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

    }

I then make a model, a view, and an input manager with the same exact object setup.

    init: function () {
        var canvas = document.getElementById("canvas"),
            context = canvas.getContext("2d");

        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        this.model = bit101.model.create(canvas.width, canvas.height);
        this.view = bit101.view.create(this.model, context);
        this.inputManager = bit101.inputManager.create();
    }

Here, the model needs to know the width and the height and the view needs a reference to the model and the context. Passing “constructor” arguments to the objects is easy, just supply them to create and pass them to init and generally save them there. Here’s the model:

WinJS.Namespace.define("bit101.model", {

    create: function (w, h) {
        var obj = Object.create(this);
        obj.init(w, h)
        return obj;
    },

    init: function (w, h) {
        this.width = w;
        this.height = h;
        this.circle = {
            x: this.width / 2,
            y: this.height / 2,
            radius: 20,
            velocity: 0
        };
    },
    
    update: function () {
        this.circle.x += this.circle.velocity;
    }

});

I’ve added another object, circle, in there, along with an update function that updates the circle.

Here’s what the view might look like:

WinJS.Namespace.define("bit101.view", {

    create: function (model, context) {
        var obj = Object.create(this);
        obj.init(model, context)
        return obj;
    },

    init: function (model, context) {
        this.model = model;
        this.context = context;
    },

    draw: function () {
        this.context.clearRect(0, 0, this.model.width, this.model.height);
        this.context.beginPath();
        this.context.strokeStyle = "red";
        this.context.arc(this.model.circle.x,
                         this.model.circle.y,
                         this.model.circle.radius,
                         0, Math.PI * 2, false);
        this.context.stroke();
    }

});

I save the model and context and in a draw method I clear the context and draw the circle based on the current data in the model.

Then there’s the input manager. This listens for key events and sets a couple of variables, left and right, depending on what keys were pressed or released:

WinJS.Namespace.define("bit101.inputManager", {

    create: function () {
        var obj = Object.create(this);
        obj.init()
        return obj;
    },

    init: function () {
        this.onKeyDown = this.onKeyDown.bind(this);
        this.onKeyUp = this.onKeyUp.bind(this);

        document.body.addEventListener("keydown", this.onKeyDown, false);
        document.body.addEventListener("keyup", this.onKeyUp, false);
    },

    onKeyDown: function (event) {
        switch (event.keyCode) {
            case 37: // left
                this.left = true;
                break;

            case 39: // right
                this.right = true;
                break;
        }
    },

    onKeyUp: function (event) {
        switch (event.keyCode) {
            case 37: // left
                this.left = false;
                break;

            case 39: // right
                this.right = false;
                break;
        }
    }

});

And finally, the completed game object:

WinJS.Namespace.define("bit101.game", {

    create: function () {
        var obj = Object.create(this);
        obj.init()
        return obj;
    },

    init: function () {
        var canvas = document.getElementById("canvas"),
            context = canvas.getContext("2d");

        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        this.model = bit101.model.create(canvas.width, canvas.height);
        this.view = bit101.view.create(this.model, context);
        this.inputManager = bit101.inputManager.create();

        this.update = this.update.bind(this);
        window.requestAnimationFrame(this.update);
    },

    update: function () {
        this.getInput();
        this.model.update();
        this.view.draw();
        window.requestAnimationFrame(this.update);
    },

    getInput: function () {
        if (this.inputManager.left) {
            this.model.circle.velocity = -3;
        }
        else if (this.inputManager.right) {
            this.model.circle.velocity = 3;
        }
        else {
            this.model.circle.velocity = 0;
        }
    }

});

After creating all the objects, init sets up a call to update through requestAnimationFrame. The update method calls getInput, then updates the model and tells the view to draw. The getInput function checks the state of the inputManager and sets the velocity of the circle in the model accordingly. If this is all set up right you should see a red circle at center screen. Pressing left and right keys will move it back and forth.

Summary

Of course, this is vastly oversimplified, but is exactly how I would start a game. The model would gain many more objects and other methods to manipulate them. Many of those model objects would be defined in their own file with create, init, and other methods. Similarly, there may be several other views – player view, enemy view, score view, etc. These can all draw to the same context, but would have different logic for exactly what to draw and where. And the input manager would of course be very customized based on what kind of controls are being used.

newobj Snippet

As I’m using the same basic setup for every new object I make, I created a Visual Studio snippet to make it a bit quicker. This is a text file that goes in the following location:

C:\Users\<username>\Documents\Visual Studio 2012\Code Snippets\JavaScript\My Code Snippets

I’ve named it “new_object.snippet”. Here’s what it looks like:

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets
    xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>New Object</Title>
      <Shortcut>newobj</Shortcut>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>namespace</ID>
          <ToolTip>Replace with a valid namespace.</ToolTip>
          <Default>namespace</Default>
        </Literal>
      </Declarations>
      <Code Language="JavaScript">
        <![CDATA[WinJS.Namespace.define("$namespace$", {

    create: function () {
        var obj = Object.create(this);
        obj.init()
        return obj;
    },

    init: function () {

    }

});]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

Once that’s in place, you just type newobj and hit tab and you get the full expanded code, with the namespace highlighted and ready for you to type your actual namespace. I’ll be making more of these, I’m sure.

Send to Kindle

2 responses so far. Comments will be closed after post is one year old.

  • felix says:

    Slightly off-topic but have you looked at Unity? Seems like a good choice for game dev since it outputs to all platforms. C# is pretty nice, similar to AS in some ways. Matt Rix has a nice 2D Unity framework called Futile.

  • Thanks for sharing this! I’ve been looking for a good kick-starter example