Javascript

RSS feed for this section

MultiRogue Dev Log – Level Refactoring

Since my last post, I’ve succeeded in creating functional AI beings in the level that have a mind of their own. They randomly wander the level, and start chasing players if they walk into their line of sight, using my own simple pathfinding algorithm. All this while maintaining my automated test suits and adding new ones.

Now, I’m at a point where I really need to refactor some things, because the complexity of my game server has gotten a bit out of hands. Particularly my level class, which has grown into a typical “manager” class.

http://aquablucondominium.com/

Typescript Dynamic Instantiation using Grunt

I run into a roadblock earlier today while working on my pet project. Turns out Typescript makes it very challenging to dynamically instantiate objects using reflection. The only useful post I found on the internet outlined a solution that doesn’t really fit my project constraints (project running in a NodeJS environment, using commonjs). I had to be creative.

Here’s the solution I came up with: I created a Grunt task called dynamic_class_loader that iterates through the classes in a certain directory. It then generates a Typescript class called DynamicClassLoader that imports all the classes, and exports a function that instantiates classes using a big switch statement. Using this handy automation step, I can always trust the DynamicClassLoader to instantiate any of my classes correctly, no matter how big my project gets. Here’s my script:

    grunt.registerMultiTask('dynamic_class_loader', '', function() {
        var done = this.async();
        var content = '';
        var i=0;
        var src = this.files[0];
        var dist = this.files[1];

        var classNames = [];

        src.src.forEach(function(f){
            var filename = path.basename(f);
            var className = filename.replace('.ts', '');
            if(grunt.file.read(f).match(new RegExp('interface[ ]+'+className+' ','g'))) {
                ++i;
                return;
            }
            classNames.push(className);
            content += 'import '+className+' = require(\'.\/'+className+'\'); \n\n';
            if( ++i >= src.src.length) {
                content += 'var createInstance = function(className, args) {\n'+
                    'switch(className) {\n';

                classNames.forEach(function(className) {
                   content += 'case "'+className+'":\n'+
                       '  var obj = Object.create('+className+'.prototype);\n' +
                       '  obj.constructor.apply(obj, args);\n'+
                       '  return obj;\n'+
                       'break;\n';
                });

                content += '   }\n'+
                '};\n\n'+

                'export = createInstance;\n';

                grunt.file.write(dist.orig.src[0], content)
                done(true);
            }
        });
    });

Here’s an example output:

import GameObject = require('./GameObject');
import Item = require('./Item');
import Message = require('./Message');
import Repository = require('./Repository');
import Vector2D = require('./Vector2D'); 

var createInstance = function(className, args) {
    switch(className) {
        case "GameObject":
          var obj = Object.create(GameObject.prototype);
          obj.constructor.apply(obj, args);
          return obj;
        break;
        case "Item":
          var obj = Object.create(Item.prototype);
          obj.constructor.apply(obj, args);
          return obj;
        break;
        case "Message":
          var obj = Object.create(Message.prototype);
          obj.constructor.apply(obj, args);
          return obj;
        break;
        case "Repository":
          var obj = Object.create(Repository.prototype);
          obj.constructor.apply(obj, args);
          return obj;
        break;
        case "Vector2D":
          var obj = Object.create(Vector2D.prototype);
          obj.constructor.apply(obj, args);
          return obj;
        break;
    }
};

export = createInstance;

One challenge I ran into was that if the script tried to use the import of an interface, my typescript transpiler would complain. This is naturally because interfaces only represent a contract, and can’t be instantiated. I had to add a small hack to avoid including those interfaces in my class loader.

Now, I can easily dynamically instantiate classes using this function anywhere inside my application:

declare module 'DynamicClassLoader' {
    export function DynamicClassLoader(className:string, args:Array):any;
}

///
var DynamicClassLoader:any = require('./DynamicClassLoader');
var newVector = DynamicClassLoader('Vector2D', [5,6]);

MultiRogue Dev Log – Visibility

Now that the automatic tests are in place, it’s time for me to focus on elements of fun in the game.

My next epic will be adding creatures into the level, and having them try to kill the players. Obviously this is a big step, so I’ll have to work many prerequisites features into the game to get to the point where this is possible with the engine. Here are some: server controller beings, attack actions, combat properties, health, the concept of dying, corpses, artificial intelligence (rudimentary), and visibility.

I’ve chosen to start working on visibility. At the moment, only the client has any concept of what’s visible and what’s not. This is a problem for many reasons:

  1. because the client is sent info about the entire level, hacking the client becomes an issue
  2. the server has no way of knowing which beings can see each other
  3. as a consequence of 2, notifications are sent to clients about events through-out the entire level, always

The start, I’m going to have to refactor the way the server sends info about the level to the client. It’ll have to send only info that’s necessary for the client to render what’s visible to the player. If I send more, this leaves the client prone to hackers. The engine being as it is, this is already a pretty big step.

Stay tuned

Source: https://github.com/MichelCarroll/MultiRogue

MultiRogue Dev Logs – Mocha Tests

I’ve been spending the last two days building up the test framework to make tests as legible and easy to make as possible. From experience, this is the only way automated tests can even make their way into a project… if they’re dead simple.

I’m using a fluent interface and simple action verbs to send commands to the client. Here’s an example of one of my tests:

describe('client picking up and dropping stick', function() {
    var client;
    beforeEach(function(){
        client = Simulator.serverBoots().clientConnects();
    });
    it('should see the stick on the ground before', function() {
        should(client.getTileTokenAt(46, 27)).be.eql('/');
    });
    it('should not be holding stick at first', function() {
        should(client.isHoldingItem('Wooden Stick')).be.false();
        should(client.hasInLog('You pick up the Wooden Stick.')).be.false();
    });
    it('should be holding stick after picking it up', function() {
        client.moveLeft().moveLeft().moveDown().moveLeft()
            .picksUpOffFloor();
        should(client.isHoldingItem('Wooden Stick')).be.true();
        should(client.hasInLog('You pick up the Wooden Stick.')).be.true();
    });
    it('should not see the stick on the ground after picking it up', function() {
        client.moveLeft().moveLeft().moveDown().moveLeft()
            .picksUpOffFloor().moveLeft();
        should(client.getTileTokenAt(46, 27)).not.be.eql('/');
    });
    //... . .. ..

Next I’m going to be making a couple of tests suits to represent all the features that my game currently has. Once that’s done, I’ll be able to refactor and add new features without being afraid of causing regression bugs.

MultiRogue Dev Log – Testing Strategy Implementation

To get to the point where I can easily write blackbox tests for the engine, I’ll first need to setup some interfaces so that my tests can communicate the test parameters and expectations in a straight-forward manner. I’ll also need to provide the client/server junction with an interface so that I can swap out the usual socket messaging with direct function calls so that my tests can run in a CLI environment without any complicated network setup.

From these requirements, here’s the list of interfaces that I’ll need to define:

  • client input (player commands)
  • client output (player feedback)
  • client socket inlet/outlet
  • server socket inlet/outlet
  • server world bootstrapping
  • server random seed

The world bootstrapping will provide a starting state for the server environment, which might vary from test suite to test suite. The random seed will provide deterministic values for the server to output, given certain inputs.

Source: https://github.com/MichelCarroll/MultiRogue

MultiRogue Dev Log – Blackbox Testing Strategy

So far I’ve successfully created a build process in Grunt. Nothing too complicated so far… typescript compilation, watch, appending files into one, uglify, and browserify for the client. This will help streamline development.

Blackbox Testing

I’ve also been doing some thinking about how to leverage automatic tests to ensure that I don’t introduce regression bugs as I make major refactorings. Given that I have some ambitious ideas on how to generalize my engine to many classes of multiplayer rogue-like games, this is an investment that I think will pay off big time.

Because both the client and the server are implemented in Javascript using CommonJS for dependency management, this makes integrating both client-side and server-side code easily into same integration tests. This is giving me some very brilliant ideas. Imagine setting up a complete game scenario, including players connecting and interacting with the world, all done without the need for a complicated test setup. The client/server communication can be mocked by using direct messaging instead of sockets.

Stay tuned.

Source: https://github.com/MichelCarroll/MultiRogue

MultiRogue Dev Log – Grunt, client/server architecture

Grunt & Build Process

It’s definitely time I apply my knowledge of grunt to this project. My build cycle has become dependent on PHPStorm to compile my Typescript files on save. Also, my client-side code is including all my source files in a traditional manner inside the index html file. It’s become a major pain-point, so putting in the time to make a decent build script will definitely pay off in the end.

Client/Server Architecture

I’ve started seriously thinking about the client/server architecture of the game. Up until now I’ve let those bigger-picture questions slide in favour of getting something playable up and running sooner rather than later. However, I’ve reached that point where new features have just enough complexity to potentially create lots of technical debt if not conceptualized intelligently.

After reading a couple of articles on multiplayer architectures (this one in particular), I’ve decided to split responsibilities this way: The server will handle all the game logic, including chat, connection, and arbitrating turns. The client will handle all player input management, user interface management, and decide on how to display the game. The server will only share information about a particular game state to a client if according to the game logic, the client is allowed to know about it (example, the server will dispatch a monster’s location only if it’s within visual range). This will minimize cheating.

There may be analogs between client and server logic (example: visual range computations), but I don’t think this can be avoided if I want to keep responsibilities in their correct places. One way to eliminate duplication would have been to make a completely dumb client, but this would be at the expense of a good user interface. MUD games, for example, have a pure client/server architecture, and a pretty lousy UI. I don’t want to fall into that trap.

Source: https://github.com/MichelCarroll/MultiRogue

HTML5 Tower Defense Game using EaselJS – Part 2 – Path to Castle

In the last post, we initiated the project, drafted how the game’s overall look & feel, and drew a red circle as proof that EaselJS is working. In this part, we’re going to render the path to the castle.

The Path to the Castle – Concept

First, let’s give ourselves an idea of what the path is going to need to be, so that we’re better prepared to code it.

Conceptually, here’s what its role is in the game:

  • A logical set of way-points for the orcs to follow in order to reach the castle
  • A logical separation between the orcs and the archers
  • A visual path, so that the player knows where it begins and where it ends

Let’s try to keep the code as simple as possible, so that we don’t get tangled in our own logic. In my opinion, the simplest way to represent a path here is as a set of way-points. Here’s an illustration of what I mean:

The big dots represents coordinate points, which we’re going to represent logically as an array of points. The dotted lines mean that the points are connected sequentially in our game logic to form a linear path.

In order to have a nice background, and to not have to worry about rendering a castle later on, let’s use a static image background in which to display the game on. We need to keep in mind the size of the image when creating/using a background image, because shrinking/growing it might distort the image. I’m going to make my image 640 x 480, which will also be the size of my game stage.

Using my master programmer artistic abilities, I present to you with my map:


(if you find it too embarrassing, feel free to make/use your own)

Notice how I tried my best to keep the width of the path constant, so that we have an easier time mapping the way-points with the image later on.

It’s now time to get down to the code.

The Path to the Castle – Coding

First of all, lets move the image file into our project, and render the map to our browser.

Let’s create a new folder inside the root of our project called images, in which we’ll move map.jpg to:

Then, lets modify our existing code a bit to render the map using an Image class and a Bitmap EaselJS object. An Image object is equivalent to an img HTML tag; Javascript uses it to link to images. The Bitmap object is part of the EaselJS namespace; it’s responsible for knowing what to display and where to display it on the stage:

loadGame = function() {
	var canvas = document.getElementById('main');
	stage = new Stage(canvas);

	var mapImg = new Image();
	mapImg.src = "images/map.jpg";

	var mapBitmap = new Bitmap(mapImg);
	mapBitmap.regX = 0;
	mapBitmap.regY = 0;

	stage.addChild(mapBitmap);
	stage.update();
};


After refreshing, you should now see the map render on your browser.

Now, using an image editor, I’ve determined where our path coordinate points are going to be . Essentially, using the pixel coordinates (x,y), I took note of where each node is situated. Here they are, in Javascript list form:

var coordinates = [
	[200, 0],
	[177, 127],
	[289, 152],
	[480, 100],
	[566, 131],
	[575, 250],
	[362, 262],
	[78, 310],
	[80, 394],
	[288, 400]
];


Using this list, and a simple looping function, lets render lines where the path is going to be, so that we can validate that the waypoints are accurate. Here, I’m creating a line for each pair of coordinates. Each line is a separate shape that needs to be added separately to the stage in order to render correctly.

Think of the Graphics object as the computer’s pen. Here’s what I’m doing step by step:

  1. I change the thickness (setStrokeStyle) of the pen to 1
  2. I move the pen to a new location (point 1), without actually drawing (moveTo)
  3. I put my pen down, and give it a red color (beginStroke)
  4. I draw all the way to point 2 (lineTo)
  5. I commit the Shape to the stage (addChild) before drawing a new one

var g = new Graphics();

for(var i = 1; i < coordinates.length; i++)
{
	var s = new Shape(g);
	s.x = 0;
	s.y = 0;

	var point1 = coordinates[i-1];
	var point2 = coordinates[i];

	s.graphics
		.setStrokeStyle(1)
		.moveTo(point1[0], point1[1])
		.beginStroke(Graphics.getRGB(255,0,0))
		.lineTo(point2[0], point2[1]);

	stage.addChild(s);
}

stage.update();


I put this logic right after the code that renders the map, so that the lines appear on top of the map, and not under.

Here’s what should be the results:

Success! Our coordinates are very accurate!

Conclusion

Now we’re ready drawing orcs, and make them follow the path. This is going to be the next part. Until then, feel free to try it out on your own using what you know so far.

Here’s the source code of my project at this point: Source Code

HTML5 Tower Defense Game using EaselJS – Part 1 – Planning & Setup

You’ve been entrusted by a great and mighty game designer with the task of bringing his original game idea to life.
Because of the slow death of Flash technology, and its replacement with canvas HTML5 technology, you have chosen to learn and use it.
You also chose EaselJS
as Javascript library to make your transition into the canvas world easier.

Game Concept

Orcs are coming to destroy your castle. You must train and position archers to slow their advance until the cavalry come.

Game Elements

  • Orcs come in waves.  At the end of the wave, if the castle is still standing, the player wins.
  • Orcs come in different varieties: slow, fast, strong, weak, gold loot.
  • Archers come in different varieties: strong, long range, slowing effect, cost.
  • Orcs follow a predetermined path leading to the castle.
  • Archers stay from one round to the next, but can be sold back for half its cost.
  • Archers can be positioned anywhere on the map not within X feet from the path.

Now that the requirements are put down on paper, let’s make a quick sketch of how this game is going to look like.
This will give us some insight on which visual elements will need to be defined, and their relationship to one another.

After some quick white-boarding, the game’s concept is much clearer in everybody’s mind. This is often a good way of brainstorming an interface and game flow, especially for visually dominant people like me. If you don’t already have a white-board in your office, I strongly recommend you purchase one.

Please note that for the sake of simplicity, I’m not putting a lot of emphasis on the game assets, such as the images. In other words, I know I’m a crappy artist, give me a break here…

Setting up your project

I’ve chosen to use WebStorm, an IDE specializing in Javascript. You can, of course, use whichever environment you’re comfortable with.

Important!!

In order to correctly run this application, it’s going to need to be accessed through a web server (even your localhost will do). The reason for this being that the application will fetch image files in a different way than a normal HTML website. What I did was download an use WAMP, an easy to install Windows linux server. I then moved my project folder inside C:/wamp/www/, and access it through the address http://localhost/tower_defense/.

I like keeping my file hierarchies simple and standard. Generally, I’ll keep all my source files inside a folder called src, and I’ll have a folder called vendor in the root of my project where I’ll put all third-party libraries inside. You can download the EaselJS library from either their Github repository or directly from their website. You can then place the contents of the library inside a folder called easeljs inside vendor.

This being a Javascript project, we’ll only need one HTML page to display the canvas. Per convention, we should call that one index.html.

Here’s a quick look at the file structure so far:

The index page will need to reference both the EaselJS library as well as our own game code. EaselJS ships with a minified file  containing the entire library. One of the reasons they do this to make it easy for programmers to include it in their project. The minified file is contained inside the lib folder, and is called something similar to easeljs-0.4.2.min.js (yours might be a different version).

Lets also create a blank Javascript file inside src called main.js which will later be responsible for initiating the game, and putting all the game components together.

Lets modify the index.html file to include both easeljs and our main JS file:

<html>
<head>
    <title>HTML5 Tower Defense</title>

    <script src="vendor/easeljs/lib/easeljs-0.4.2.min.js"></script>
    <script src="src/main.js"></script>
</head>
<body>
</body>
</html>

So far so good. To complete the setup, lets initiate a canvas, and draw a shape into it using an EaselJS function to make sure our pieces are working well together.

We’re going to add a canvas to the index file, call it main by setting it an ID. We’re all going to run a function called loadGame on body load. Here’s what it will look like:

<body onload="loadGame()">
    <canvas id="main" width="800" height="600"></canvas>
</body>

In our main.js, we’ll create a loadGame function that will simply initiate the canvas scene and draw a circle inside of it.
Don’t worry if you don’t understand what’s going on in this function yet; the tutorial will go more in depth in the later posts.
This is mainly used as a test to make sure the setup is correct.

loadGame = function() {
    var canvas = document.getElementById('main');
    stage = new Stage(canvas);

    var g = new Graphics();
    g.setStrokeStyle(1);
    g.beginStroke(Graphics.getRGB(0,0,0));
    g.beginFill(Graphics.getRGB(255,0,0));
    g.drawCircle(0,0,3);
    var s = new Shape(g);
    s.x = 100;
    s.y = 100;
    stage.addChild(s);
    stage.update();
};

If when you visit the web adresse (http://localhost/tower_defense/ in my case), you see a small red circle, your setup is complete. If not, open up the Javascript console (Ctrl-Shift-J in Chrome), and verify that the page isn’t throwing any errors.

That was the first part of the tutorial. Let me know in the comments if you have any comments, suggestions, or need help.

Here’s a link to part 2.

Simple Javascript HTML5 game example using EaselJS

I made a simple canvas game today as a way of getting my feet wet using EaselJS library.

You may download the source code here: https://github.com/MichelCarroll/SimpleEaselJSGame

Here’s the game embedded inside the page, as a demonstration of how easy HTML5 games are to publish seamlessly on the web: