Programming

RSS feed for this section

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]);

Starting with jMonkeyEngine – 3D Game Development Terminology

jMonkeyEngine has always caught me eye as one of the most complete and community supported 3D game engines. My Java is beginning to be very rusty, so exploring this framework works to my advantage in many ways.

As outlined in the “Community Hub“, before undertaking the beginner tutorials, it’s important to understand basic 3D game development terminology (ex. mesh, shading, specular map). They actually provide such a documentation, which is wonderfully resumed for those of us who want to get down into the action, and not spend hours reading. The scene graph is among the most important concepts, on which they have an article dedicated to.