Running an AngularJS App in the Windows Store

My previous blog entry talked about my experiences writing an ‘AngularJS + HTML5 canvas’ game without a game engine. Now I’m not going to pretend that this was the greatest code of all time – it was very much a way of learning AngularJS – however I am pleased that I managed to complete the game.

For those interested you can play the game here and access the source code on GitHub.

However, I wanted to see if I could convert this to run as a Windows Store App…

By default it is not possible to run AngularJS code in a Windows Store App. If you try then you get the following error…

WinStoreJSUnsafeError

The problem is that various restrictions are put in place to stop malicious code from running – which unfortunately causes problems to anyone who wants to use many of the popular third party JavaScript frameworks out there – e.g. AngularJS.

As it happens there are actually a few different methods for overcoming this. Originally I found this blog post which used a custom version of jQuery. This worked fine, however I didn’t really want to have to include jQuery, so recently I found the winstore-jscompat library, on GitHub, which also solves the problem.

So, to convert our game to run as a Windows Store App we just add all our code to a new empty ‘Win Store App Visual Studio project’ and then make sure we include the winstore-jscompat library before the reference to the AngularJS script like so.

IncludeWinStoreJsCompat

Simples!

If you want to see the code to run the game as a Windows Store App then you can take a look at the WinStoreApp branch of my GitHub repository.

Note: You will not find this running in the Windows Store. It really isn’t good enough for that! πŸ™‚

Writing an HTML5 game with no game engine – Just AngularJS and the HTML5 Canvas!

TL;DR

I wrote a version of the Arcade classic Centipede using AngularJS and the HTML5 canvas. You can play the game here and view the source code on GitHub.

1GameScreenShot

Introduction

Normally I’m coding in c# and evangelising about MonoGame, however in recent times I’ve had to start using JavaScript, in particular AngularJS. As always when learning a new programming language I like to write a game – and so it was no different this time around. Back in 2002, learning c#, I wrote a version of Centipede. I still had this code and the ‘programmer art’ graphics I produced back then so decided to recreate it with AngularJS.

This blog post is about my experiences writing this game using AngularJS. The problems I overcame, lessons I learnt and the fun I had.

Note that all of the code for the game is available on GitHub for you to take a look at.

Code Structure

The first thing we’ll look at is the index.html – the only page in the game. It is pretty simple and looks as per below…

2IndexHtml

..with various other script tags following on from this for each code file in the game.

I’m not going to go into too much detail about AngularJS as there are lots of other resources on the web that already cover that, so we’ll just go with a quick summary of the above.
As per most AngularJS pages I have defined my ng-app at the top (gameApp). I also have one ng-controller (appController) and one directive (centipede-game).

The appController code (shown below) very simply handles the transition from the introduction (instructions) screen to the main game. As soon as the user presses a key then we set the $scope.instructionsDisplayed to true. Any further keypresses are then passed off to the keyPressHandlerService – More on this later!

3AppController

Once the instructions have been displayed, and dismissed via the key-press, then the centipede-game directive is displayed on screen.
This directive is the gateway into the game.

4GameDirective

You can see that the template just adds an instance of the HTML5 canvas element to the page, however the link function is the main area of interest as this handles our ‘game loop’. There are various (no doubt better) ways to program the game loop, however I have kept this implementation quite simple. Every 50 milliseconds the gameLoop method is invoked and the ‘animation’ variable incremented, continuously looping from zero to three. This animation value is then passed into our gameService and renderService to handle all the game logic and screen rendering respectively. (More on this later.)

One final point to note about this directive is I’m being a good boy, ensuring the promise created by the $interval service is correctly disposed of when the scope is destroyed. πŸ™‚

I don’t intend to go through every line of code in the code base – you’d soon get bored – So I’ll just go over some of the key parts to the code and let you browse the GitHub code at your leisure.

The full code base is shown below…

5ProjectStructure

The gameApp.js you have already seen. This defined the gameApp angular module along with the sole directive and controller in the app.
The constants folder contains all the ‘constant services’ in the game. Generally speaking these are pretty simple areas of the code, for example the characterDirection constant service defines each direction the character can move in. As is the nature of an AngularJS constant service, there isn’t really any logic to see!

6ConstantsCharacterDirection

The sprite.js file is worth a mention though – This contains a reference to every sprite in our sprite sheet. The first sprite is a ‘red mushroom’ at 100% health, then one at 75% health etc.

7ConstantsSprite 7SpriteSheet

Whenever we want to render a particular sprite to the screen we reference it as defined in sprite.js. For example, if we wanted to render the full strength purple mushroom at screen co-ordinates 100, 200 then we would use the below code.

8GraphicsEngineDrawImageCall

This leads us nicely on to our graphicsEngineService which is the first of the ‘Angular factory services’ we will look at.
The graphicsEngineService holds a reference to our HTML5 canvas and handles all the rendering to that canvas – any text that needs to be displayed and/or sprites from our sprite sheet.

Let’s take a look at the drawImage function. A function that allows us to render a particular image at a specific location (x and y co-ordinate).

9GraphicsEngineDrawImageImplementation

The first thing to note is we check whether the caller is passing us ‘screen’ or ‘world’ co-ordinates. This is a common concept in games development. If working in ‘screen’ co-ordinates then we are working on a pixel by pixel basis, however if working in ‘world’ co-ordinates then we are working on the basis of each mushroom/player/enemy taking up one space on the board. As we need to work in pixels when accessing the HTML5 canvas then we convert any world co-ordinates to screen co-ordinates.

Finally we just need to render the chosen image (sprite) on to the canvas. The canvas drawImage function handles this for us – all we have to do is pass in the following parameters…

  • [1] A reference to our sprite sheet
  • [2, 3] The location of the sprite, within the sprite sheet
  • [4, 5] The sprite width and height as defined in the sprite sheet
  • [6, 7] The location on screen we wish to render the sprite
  • [8, 9] The size to render the sprite as on screen (In this case the same size as defined in our sprite sheet, however we could alter these values to stretch or shrink the image).

For those that don’t know about sprite sheets I refer you to the following video by Code And Web (The makers of TexturePacker)…

SpriteSheets – TheMovie – Part 1 by CodeAndWeb

Animation

So, assuming you are still reading this, I’m guessing you have already tried playing the game? As such you will notice the various characters on screen ‘animate’ as they move around – for example the centipede’s legs move back and forth. Also you may have noticed that the characters transition (relatively) smoothly from one location to the next as opposed to suddenly jumping to the next location. This is where the ‘animation’ variable in our centipedeGame directive (mentioned earlier) plays its part…

Every iteration of the game loop (every 50 milliseconds), we increment our animation count by one – looping from zero to three and then back to zero again. Think of this as the ‘frame count’ for each movement sequence – where there are four frames for each movement. So, if the spider moves left one space then this is handled over 4 frames – each frame the spider will move an extra quarter of the distance to the desired location. Combine this with displaying a slightly different graphic for each of the frames ensures that the movement is smooth and the spider looks like it is walking. Although this has simplified the explanation, this is pretty much what is happening!
Similarly the other moving entities in the game (the player, bullets fired, centipede, flea and snail) are handled in the same way – The only difference might be the speed they travel. The player moves twice as fast as the spider, moving to its new location within 2 frames, whereas the bullets travel an entire space each frame.

Let’s take a look at how this works…

Earlier we saw our game loop within the directive.

10GameLoop

This passes the animation into the gameService.update() function. If you take a look at that code then you’ll see there is a check on the current state of the game – e.g. are we handling the ‘player death sequence’ or a ‘transition to the next level’. Assuming we are in ‘normal game mode’ then we ultimately call the moveCharacters() function, which in turn calls update() on each ‘moving character’ service…

11MoveCharacters

Thus each service can handle the logic for updating its own state itself – e.g. the bulletService will move all the bullets and check for collisions, the centipedeService will move all the centipedes, the fleaService will move the flea down, or if the flea doesn’t exist then perform a check to see if it should be created.

At this stage we are not rendering anything to the screen, however this is immediately handled after all services have handled their above movement phase. Taking a look at the gameLoop you can see the call to the renderService.draw() function…

10GameLoop

…which simply offloads the rendering to each service…

12DrawFunction

Again you’ll notice that the ‘animation’ value is passed into the draw method. This is so that each service can determine how far the character(s) have moved in this animation sequence and thus position the correct sprite at the appropriate location. For example the snailService will use a different sprite depending on the animation value – and increase the x co-ordinate more for each animation, thus animating the snail across the screen.

13DrawFunction

(Note: You will also see that two images are drawn because the snail is bigger and takes up 2 sprites.)

Now, I’m not saying this is the ‘best way’ to implement basic animation within a game, but it’s relatively simple and works for me :). If you want to delve deeper into this sort of thing then I’d suggest reading this article which goes into depth about implementing movement logic within 2D platform games. And if you want to read about how a game loop should be implemented then I definitely recommend reading the game loop article at Code inComplete. In fact anyone interested in writing their own JavaScript games without a game engine should take a look at the games on the Code inComplete Games site as they are pretty amazing!

Of course, you could use a game engine like Phaser and write a lot less code and produce something much quicker – it depends what your goals are – for me this was about playing with AngularJS and seeing what I could do with it and the HTML5 canvas element.

Player Interaction

Now, one thing we haven’t talked about yet is how to control the player. Interestingly this is an area where I encountered a few problems!
To control the player I decided to keep it simple – arrow keys for moving and the space-bar for firing. If we take a look at the index.html then you’ll see I am using the AngularJS ng-keydown and ng-keyup built in directives to capture the keyboard interaction.

14KeyDown

And, looking in the controller, you may recall from earlier, we are simply handing this information off to a specific service (keyPressHandlerService) to handle the keyboard interaction. That same service can then be queried by the playerService to determine which direction the player should move.

3AppController

I haven’t included the code from the keyPressHandler service here because it is actually quite long and more complex than one would have hoped! When I first started implementing the game I just monitored the keydown event and moved the character whenever it fired, however this meant a very ‘user unfriendly experience’ because holding down the left arrow (for example) would move the character to the left once, then pause, and then continually move the player left. This is because there is a delay between the first keydown event and the second, but then all others come in quick succession. Try it now for yourself in any input box or word processing app etc – you will experience the same behaviour. What I wanted was for the character to continually move all the time the key was pressed. I therefore took a slightly different approach of tracking all the keys currently being pressed, and then on each game loop, we could check which keys are being pressed.

That almost gave me the final solution – I just had one more issue – If the user quickly pressed and released a button then the keydown and keyup would fire before the playerService had a chance to check what key was being pressed, so I had to also track whether the key press had been handled. If on keyup it had not been handled by the playerService then the keyPressHandlerService would keep track of that keypress until it had been handled by the playerService.

One good thing about this though is that I took the opportunity to learn a bit about AngularJS unit testing using Jasmine! You’ll see I have a Tests folder in the solution with a SpecRunner.html page which runs all the tests in my KeyPressHandlerSpec.js file.

15KeyPressHandlerProjectList

16KeyPressHandlerSpecTests

Now, if I was using a game engine like Phaser, then this is the sort of thing that is completely handled for us – However my intention was to write this purely in AngularJS without any game engines – and that I achieved! πŸ™‚

Conclusion

In terms of what I set out to do, I am happy. I have successfully written a simple game using AngularJS and the HTML5 canvas. Before I started on this project I had never written anything in JavaScript let alone AngularJS before. Looking back at the commit history I started working on this in July 2013, doing a bit here and there as time allowed, took a break in August (summer holiday time) and then ‘finished’ it in September. However, at that stage the code was a complete mess! Some of the code was AngularJS but a lot of it was pure JavaScript – and as such there were loads of messy callbacks all over the place. Coming from a c# background I probably made every mistake listed on the numerous “Top 10 mistakes made by .net developers when programming in JavaScript” web-sites.
With more experience, and the determination to write this blog post, I revisited the repository in October 2014 and converted it to be 100% AngularJS – and although the repository is by no means a master class in AngularJS, it is certainly a lot neater than it was – which I believe is a testament to how great AngularJS is!

So, would I recommend writing a game in AngularJS with no game engine?
Answer: It depends on your goal!

If you want to produce a HTML5 game quickly (e.g. you are entering a Ludum Dare type game jam) then I’d probably recommend using a game engine like Phaser. Phaser would let you concentrate on the game without worrying about handling keypresses – You wouldn’t even have to worry about things like collision detection as there are built in physics engines within Phaser.

However if you want to get involved in every low level aspect of the game then, as this blog post shows, it is possible to complete a game using just AngularJS and no games engine.

In the future I see myself using Phaser when time is of the essence (e.g Game Jam Event) – However I certainly see myself taking a similar approach to this blog post again, as you ultimately have more power over the mechanics of the game – and indeed I could reuse some of the logic from this game for future games anyway.

Something Extra

My next blog post talks about an extra direction I went with this project – Still using AngularJS, but converting the game to run as a Windows Store App.

Links

  • If you want to learn how to do HTML5 games from scratch properly then I would highly recommend Jake Gordons web site Code inComplete
  • If you want to read about HTML5 game development in general then I’d recommend signing up to the GameDevJSWeekly mailing list.
  • If you want to learn about AngularJS then there are loads of resources out there now, however my favourite is the Dan Wahlin weekly newsletter.