Typescript

It’s not been the first time I have to deal with a gigantic Javascript codebase. While most of the side projects I’ve been writing are no more than 5K loc, CAAT was near 30K, and in my current job I will likely end up managing a codebase between 50-100k loc.
It is fairly complicated to keep things up and running in such a big codebase when I have to defer error checking to the runtime environment and different people contribute code. The nature of the code I write is mostly visual. Things that a human being won’t be able to spot whether they are right or wrong tend to be quite complicated to automate, either at unit or functional testing levels. For example, is that gradient-filled shape right ?, etc.
While writing CAAT, I had to manage all the basic platform stuff on my own: (prototypical) inheritance, module management, dependencies, … all had to be either solved on my own, or by using external libraries, not by the language itself. Good news is that Javascript can mostly fix itself.
Basic features for a typed language, like code refactor, keeping up with correct VM code for performance or hinting code for performance is something so tied to the core of my development that I simply don’t want to deal with it on my own.
For this and so many other reasons I took a shot on Typescript.

Conclusion: it pays by itself after 10 minutes of using it. Specially when putting the stress in long-term maintainability and code quality.

Let me enumerate some of the goods I get while writing Typescript code:

  • Refactor: my IDE recognizes the code semantically. It allows for deep type and elements refactor on-the-fly.
  • ES6: Typescript brings to the table many ES6 language features. By the time ES6 is around, all my typescript code will almost be a one-to-one mapping which does not need any change.
  • Strong typed. Modern Javascript VM make deep type inference to JIT the code. While Typescript is not executable in the browser and has to be transpiled to javascript, since it is strong typed will guarantee type consistency, something that will for sure help to your codebase performance.
  • Javascript VM-friendly transpiled code. While some time ago it was expected to define properties in prototypes, but at the same time, keeping prototype chains sort, today, if you want to take advantage of hidden classes and already optimized code, properties should be injected in constructor functions.
  • Solved extension mechanism. It ships with a very simple prototypical extension mechanism.
  • Solved modularity. Module information will be written for you.
  • Super light overhead. Resulting code is just the original code without the type information.
  • Since 1.4, union types and type aliases will leverage the Typescript capabilities, switching from type:any to a union type.
  • No learning curve at all.

Nowadays, there are Typescript mapping files for all major libraries around: webgl, nodejs, (node io ?? :), webaudio, etc. And being myself so close to HTL5 gaming, most modern HTML5 engines are either written in Typescript, like CocosJS or Egret, or have Typescript mappings like Phaser.

I’d rather have a compiler on my side. Ever.

Dinamically Proxying objects and Wrapping functions.

It’s been some time ago since I needed some mechanism to make debugging in CAAT and other javascript projects I’m working on easier. I’ve an strong Java background and I’m used to dynamically proxying most of my core objects, mainly for safety reasons but as well for the ease of development and to do some aspect-oriented programming.
So I’ve come up with a javascript proxy solution which will allow me upon a call to evaluate whatever object’s method , hook that call at least in three stages:

  • Pre method call, which allows to wrap, change or modify method call parameters.
  • Post method call, which allows to modify method call’s return value.
  • On exception throw call, which allows to return values on exception preventing exception toss.
  • Of course, these are just some examples of why I would be willing to use proxies. But one more compelling reason is that of log code activity without sprouting alert/console.log sentences all around my beautifully crafted code.

    While in Java we’ve incredibly powerful introspection mechanisms as well as an InvocationHanlder ready to be used, the javascript implementation will be a little bit less ambitious, I mean, the code security concerns of Java’s dynamic proxy will be left out the implementation.
    The use of this proxy to wrap a whole object be as follows:

    // Define a module/namespace whatever you call it.
    Meetup= Meetup || {};
    
    // Define an 'object class'
    (function() {
     Meetup.C1= function(p) {
       this.a= p;
       return this;
     }
    
     Meetup.C1.prototype= {
       a: 5,
       b: function() {
         return this.a*this.a;
       },
       c: function(p1,p2) {
          return this.a+p1/p2;
       },
       err: function() {
           throw 'mal';
       }
     };
     })();
    
    var c0= new Meetup.C1(10);
    
    // Instantiate and wrap the object into a proxy:
    // This cp0 object will behave exactly as c0 object does.
    var cp0= proxy(
            c0,
            function(ctx) {
                console.log('pre method on object: ',
                        ctx.object.toString(),
                        ctx.method,
                        ctx.arguments );
            },
            function(ctx) {
                console.log('post method on object: ',
                        ctx.object.toString(),
                        ctx.method,
                        ctx.arguments );
    
            },
            function(ctx) {
                console.log('exception on object: ',
                        ctx.object.toString(),
                        ctx.method,
                        ctx.arguments,
                        ctx.exception);
    
                return -1;
            });
    
            

    With this code, by calling cp0.b(); the following method calls will be performed:

  • Call anonymous function pre-method.
  • Call proxied object’s ‘b’ method
  • If the proxied object’s method call went rightm call anonymous function post-method, otherwise (on execption toss) call anonymous function on-method-exception.
  • This, with some little extra work, could be considered aspect oriented function calls. These hook functions receive as their parameters one object of the form:


    {
      object: the-proxied-object,
      method: evaluated-proxied-object-method-name,
      arguments: the-evaluated-method-arguments,
      exception: if-exception-thrown-on-error-hook--the-exception-thrown
    }

    It is up to the developer what to do with these information for each hook function, but in the example, they’ve been set up as activity logging functions. An example of the result of the execution of cp0.c(1,2) will be:


    pre method on object: Meetup.C1 {a: 10} c [ 1, 2 ]
    post method on object: Meetup.C1 {a: 10} c [ 1, 2 ]
    10.5

    (which should be read as pre-method call on object XX, method ‘b’, with method arguments ‘[]’ (none in this case).)

    When proxying a simple function, the code downgrades to a function wrapping. In this case I’m keeping the same call scheeme. An example will be as follows:

    function ninja(){
      console.log("ninja running" );
    };
    
    var pninja= proxy(
            ninja,
            function(context) {
                console.log('pre method on function: ',
                        context.fn,
                        context.arguments );
            },
            function(context) {
                console.log('post method on function: ',
                        context.fn,
                        context.arguments );
            },
            function(context) {
                console.log('exception on function: ',
                        context.fn,
                        context.arguments );
                return -1;
            });
            

    As you can see, when wrapping functions, the context supplied to hook functions is of the form:

    {
      fn: the-wrapped-function,
      arguments: the-wrapperd-function-arguments
    }

    The proxy function itself is the following:

    function proxy(object, preMethod, postMethod, errorMethod) {
    
        // proxy a function
        if ( typeof object=='function' ) {
    
            if ( object.__isProxy ) {
                return object;
            }
    
            return (function(fn) {
                var proxyfn= function() {
                    if ( preMethod ) {
                        preMethod({
                                fn: fn,
                                arguments:  Array.prototype.slice.call(arguments)} );
                    }
                    var retValue= null;
                    try {
                        // apply original function call with itself as context
                        retValue= fn.apply(fn, Array.prototype.slice.call(arguments));
                        // everything went right on function call, then call
                        // post-method hook if present
                        if ( postMethod ) {
                            postMethod({
                                    fn: fn,
                                    arguments:  Array.prototype.slice.call(arguments)} );
                        }
                    } catch(e) {
                        // an exeception was thrown, call exception-method hook if
                        // present and return its result as execution result.
                        if( errorMethod ) {
                            retValue= errorMethod({
                                fn: fn,
                                arguments:  Array.prototype.slice.call(arguments),
                                exception:  e} );
                        } else {
                            // since there's no error hook, just throw the exception
                            throw e;
                        }
                    }
    
                    // return original returned value to the caller.
                    return retValue;
                }
                proxyfn.__isProxy= true;
                return proxyfn;
    
            })(object);
        }
    
        /**
         * If not a function then only non privitive objects can be proxied.
         * If it is a previously created proxy, return the proxy itself.
         */
        if ( !typeof object=="object" ||
                object.constructor==Array ||
                object.constructor==String ||
                object.__isProxy ) {
    
            return object;
        }
    
        // Our proxy object class.
        var cproxy= function() {};
        // A new proxy instance.
        var proxy= new cproxy();
        // hold the proxied object as member. Needed to assign proper
        // context on proxy method call.
        proxy.__object= object;
        proxy.__isProxy= true;
    
        // For every element in the object to be proxied
        for( var method in object ) {
            // only function members
            if ( typeof object[method]=="function" ) {
                // add to the proxy object a method of equal signature to the
                // method present at the object to be proxied.
                // cache references of object, function and function name.
                proxy[method]= (function(proxy,fn,method) {
                    return function() {
                        // call pre-method hook if present.
                        if ( preMethod ) {
                            preMethod({
                                    object:     proxy.__object,
                                    method:     method,
                                    arguments:  Array.prototype.slice.call(arguments)} );
                        }
                        var retValue= null;
                        try {
                            // apply original object call with proxied object as
                            // function context.
                            retValue= fn.apply( proxy.__object, arguments );
                            // everything went right on function call, the call
                            // post-method hook if present
                            if ( postMethod ) {
                                postMethod({
                                        object:     proxy.__object,
                                        method:     method,
                                        arguments:  Array.prototype.slice.call(arguments)} );
                            }
                        } catch(e) {
                            // an exeception was thrown, call exception-method hook if
                            // present and return its result as execution result.
                            if( errorMethod ) {
                                retValue= errorMethod({
                                    object:     proxy.__object,
                                    method:     method,
                                    arguments:  Array.prototype.slice.call(arguments),
                                    exception:  e} );
                            } else {
                                // since there's no error hook, just throw the exception
                                throw e;
                            }
                        }
    
                        // return original returned value to the caller.
                        return retValue;
                    }
                })(proxy,object[method],method);
            }
        }
    
        // return our newly created and populated of functions proxy object.
        return proxy;
    }
            

    Despite being a powerful beast, the proxy model has some drawbacks. In example, attributes (object’s non function elements) can’t be proxied, since they can’t be evaluated by function call (Will have to take a look at __define_getter and setters functions tough). Also, newly dynamically added methods to an object won’t be proxied by an already defined proxy object, but you always have the opportunity of creating a new proxy for that object.
    Also, not every object type can be proxied. Concretely, String and Array primitive object types can’t, so the proxy function is checking at first instance whether the supplied object is elligible to be proxied. If not, the unchanged object will be returned.

    One more thing to tell about the proxy function is its own definition. It is defined as a global function because it makes no sense adding it to Object’s prototype since as I said, not every object type is elligible to be proxied.

    This technique has shown very useful to me. While developing, I’m just passing object’s proxies back and forth throught the code which seamlessly behave as regular objects. Given that one single object can have more that one proxy, I’ve the abbility to hook different extra behaviors to the original object by passing different proxies for different situations. In the end, when I’m finished with the development/debug phase, I simply disable the proxy functionality by supplying with a proxy function which just returns the passed object. Maybe this technique is only suitable for very object centric developments, but I’ve found it very valuable.

    Maybe I’m wrong, let me know what you think.

    Fishpond

    The fishpond is a CAAT based experiments.
    It is a test of building procedurally generated content, in this case fish. Each fish is composed of 4 bezier curves, 2 cubic curves to make the body, and 2 quadric curves to build the head.
    Here it is an sketch of the first fish type where its curves can be seen:

    This simple curves lead to a rich procedural parameterized fish, where tail width and height, fish width and height, head curvature, etc. can be procedurally set to create many different fish types.
    With the very same curves, and only by moving some control points around, new fish breeds can be very easily created. In example, with the following curves setup a sort of fish-cat can be created:

    Parameters such as eyes size or fin position, fin size and fin movement are also procedurally set. Also tail movement frecuency and bending angle is parametric.

    All these handlers alltogether lead to a really rich result. In addition, every fish on screen follows a cubic bezier path with is as well randomly generated. Here’s a screenshot of the whole result. I’m playing with new fish breeds which will enrich the fishpond with new life forms. Here are two examples of such that new creatures:


    An screenshot of the fishpond:

    See the fishpond in action.

    CAAT’s WebGL implementation notes.

    It’s been some time since I’ve coding to provide CAAT with transparent seamless WebGL integration.
    A 2D rendering engine is not one of the best scenarios for 3D acceleration, and here I’m showing some techniques I must have had to develop to provide the best acceleration scenario possible.

    It’s needed to be said that CAAT will be using hardware acceleration if available, and will transparently fall back to canvas if not. Here you can find a mathmayhem game implementation which tries to use WebGL as its renderer. The game suffered no changes at all. You just can tell CAAT to use WebGL by calling Director’s initializeGL method. All the other development issues will be covered by CAAT itself.

    First of all, some notes about WebGL needs. Despite us (developers) being thorough regarding our class hierarchies and animation actors collections, the hardware acceleration layer is not aware of or interested at all about our data organization. WebGL is a rasterizer (a very efficient one indeed) so to keep it at high FPS rates, I must have made a switch from object oriented development to data oriented development. In any professional 3D engine it is a must to keep shader switch operations to the minimum, that is sorting your scene assets by shader and by geometry. Achieve this objective’s been priority nº 1 in CAAT.

    Texture packing

    One of the most obvious ways to lose performance with WebGL rendering is using tons of textures to apply to different scene actors. Instrumenting your shaders to change from texture to texture will immediately drop your scene’s FPS. Besides, not any texture size will be suitable to be used by WebGL. Firefox 4 complaints about not 2^n sized texture sizes (needed to mipmap btw) and Chrome drops performance when no such texture sizes are used (MacOS X, Chrome 10 stable).

    CAAT’s solution it to package textures automatically in glTextures of programmers desired size (2048×2048 by default). So the system, will try to pack textures in different ‘texture pages’ transparently keeping track of texture elements in glTexture space so that when selecting a texture for an sprite the programmer has nothing to take into account. This process minimizes absolutely texture switching, having its best efficiency when one one texture page is created (a 2048×2048 texture space should be enough). Mathmayhem game, despite not having its images optimized at all in size, fit perfectly in one single texture page.

    ZOrder

    A 2D rendering engine must perform back to front pixel overwriting rendering, so depth Z must be disabled. Blending must be enabled so that transparent/translucid images could be properly renderer. One oddity about blending is that the background color of the DOM element the canvas is embedded in will make blending function to saturate to that color. So if you just have a page with the canvas, and the body is white, will make you blending function show wrongly. You should embed the canvas in a div and set this div’s style bgcolor to black (#000) otherwise, your blending won’t showas expected.

    Transformations

    The bad news about a 2D rendering engine is the fact that every single sprite on screen can have its own transformation. This means a huge processor use devoted to matrix computations. CAAT has translation, rotation by rotation pivot and scale by scale pivot. That means 7 matrix multiplications for each Actor on Scene. In fact, the matrix operations MUST be performed regardless the scene’s complexity. In an scenario in which you have let’s say a 100K polygon fixed model, only one matrix must be calculated and uploaded to the graphics card via uniform parameters. But in a Scene with 1000 different actors (2000K triangles), 1000 matrices must be calculated and uploaded to the graphics card. That undoubtfully will kill you frame rate. So CAAT’s approximation is different.

    CAAT simply transforms 2D coordinates to Screen/World space via JS code, and buffers these coordinates in a GL buffer. These coordinates are rendered at once either because an actor requests an image of a different texture page than the one that it is currently selected, an actor’s paintGL method request a flush or a different alpha value different than the currently set one is requested . I’ve made some tests and this is by far more efficient than uploading matrices via uniform parameters.

    Every actor in CAAT is drawn by 2 triangles so the possibility of using triangle strips is not a real possibility.

    Also, to minimize matrix calculation processor sink, CAAT tracks two different transformation matrices for each Scene actor. One regarding local transformation called modelViewMatrix which tracks (translate/rotate/scale), and for world transformation called worldModelViewMatrix which handles positioning in world coordinates. In a 2D world, a normal scenario is that of containers of actors which compose their transformation to that of its contained children. So whenever a container is in example rotated, this transformation must be propagated to every contained actor. CAAT implements a matrix caching plus dirtiness flags which will keep matrix operation to its minimum.

    A test in which 1000 sprites are rotating/scaling is not a real one but a stress test.

    Shaders

    CAAT does the whole process with one single shader which is able to render from texture space calculated from texture packer or a color. These values can be complemented by the alpha composition component set. The idea as before is interacting the minimum with the shader to avoid gl driver penalty.

    One more action I recommend when using this gl implementation is creating sprite sheets with different alpha applications for small images. Thus avoiding to flush the current geometry by the need of setting the alpha channel and instead, selecting another image index from the sprite sheet. This should be done for small textures though.

    At this point, I just can suggest you going to the game implementation and watch all these processes in action. Let me know how sumon-webgl performs for you. Needeless to be said that all these processes are worthless if we face a bad gl driver implementation.

    HTML5 Audio – Implementation notes.

    Recently i’ve been messing around with the idea of adding sound capabilities to CAAT. The idea is pretty straightforward, play a sound at any given time, or simply have a looping audio channel playing forever. Here are some lessons i’ve learnt from my sound implementation.

    First of all, not all major browser vendors support audio tags. Microsoft’s internet explorer, while giving a neat and always improving canvas support lacks absolutely of audio support. Even worse, neither the object Audio nor HTMLAudioElement are known, so either wrap between try/catch your code to avoid exception throwing, or perform a document.createElement(‘HTMLAudioElement’) and check for null return values.

    The other Audio supporting browsers do not support all sound formats. There’s a function to realize whether your browser will be able to play a sound format. Well, not really. Depending on the browser, return values from this method could be: ‘yes’, ‘no’, ‘maybe’, … Yes, ‘maybe’ is a possible value. So the bad news is that you better have your sounds in all available formats, so you feed your audio elements until the call to audio.canPlayType( extension {string} ) returns ‘yes’. My implementation deals with these formats:

    • ‘mp3’: ‘audio/mpeg;’
    • ‘ogg’: ‘audio/ogg; codecs=”vorbis”‘
    • ‘wav’: ‘audio/wav; codecs=”1″‘
    • ‘mp4’: ‘audio/mp4; codecs=”mp4a.40.2″‘

    In example, safari is well known for not giving support for ogg/vorbis sound format. Something unacceptable btw.
    Wav format seems to be accepted by all browsers able to play sound I’ve tested so far.

    Another problem arises when trying to loop a sound. To any given audio tag or Audio/HTMLAudioElement object you can set the property ‘loop’ to true, and the sound is supposed to loop forever. Not really, at least in Firefox 3.x and 4.x Beta. Firefox will loop the sound exactly once, and stop playing. Fortunately, there’re some audio events out-of-the-box which come to the rescue. So to make this audio loop, I execute the following code:

    audioNode.addEventListener(
      'ended',
      // on sound end, trigger this function
      function(audioEvent) {
        // get the audioNode element
        var target= audioEvent.target;
        // and make it loop by setting audio time to 0.
        target.currentTime=0;
      },
      false);


    This code sets audio time to 0 on audio end which has (more or less) the effect of looping the sound. I manage to attach that function only for Firefox browsers though. The other browsers that honor loop attribute, loop sound with different grades of accuracy. In my Mac OSX 10.6+, chrome seems to loop little time before it ends playing the sound, and FF4+ sometimes has a noticeable pause before looping with the end event function method.

    Another issue i found was the possibility to play multiple instances of the same audio element. To do so, I must have to create new Audio elements on the fly, assign sources and related resources to it and then play the sound. This operation led to some misbehaviors, making the browser (chrome concretely) to lag and pause up to unacceptable levels. Then, I decided to pre-create an Audio elements pool to borrow from pre-cached audio elements. The drawback is that this pool has a limited number of potential concurrent sounds, but I’ve set the number to 8. I think eight concurrent sounds should be enough.
    When playing a sound, an element from this pool is borrowed, and added to a temporary pool of working audio elements. After ending audio play the audio element is pushed back from working to available pool for future reuse. Looping audio elements, create their own audio channels, and are stored and managed in a totally different structure than that of regular audio elements.
    This is a code snippet for my AudioManager class initialization:

    
    // Allocate 'numChannels' audio channels. An audio channel is just an Audio or 
    // HTMLAudioElement object.
    for( var i=0; i<numChannels; i++ ) {
        // create an audio channel.
        var channel= document.createElement('audio');
    
        if ( null!=channel ) {
            // store this channel in the available audio channels.
            this.channels.push( channel );
            // hack to reference AudioManager instance inside audio's ended 
            // event listener function.
            // scope in javascript deserves a whole thesis by itself.
            var me= this;
    
            channel.addEventListener(
                    'ended',
                    // on audio end
                    function(audioEvent) {
                        // identify ending audio element
                        var target= audioEvent.target;
                        var i;
    
                        // identify and remove from workingChannels
                        for( i=0; i<me.workingChannels.length; i++ ) {
                            if (me.workingChannels[i]==target ) {
                                me.workingChannels.splice(i,1);
                                break;
                            }
                        }
    
                        // and get it back to available channels for reuse.
                        me.channels.push(target);
                    },
                    false
            );
        }
    }
    


    With this audio element reusing scheeme, I can manage to easily assign the same sound to different channels and concurrently play the very same sound. I found out that in example, chrome would crash or get irresponsive when creating many concurrent audio elements. With this pooling strategy, I managed to get a consistent Audio Manager.

    Another thing to take into account is that of creating Audio elements (either by executing new Audio() or by document.createElement(‘audio’) ) or by integrating audio tags in the html file by using . Personally i’d prefer embedding the audio tags into the html and marking them as preload=’auto’ so that the browser will start the job of preloading sounds. This will be saved time since by the time your javascript’s been loaded some audio can have been preloaded as well. As it is a preference, in CAAT’s AudioManager implementation, you can pass in either an html or a DOM audio node to the adding sound function. The function needs an id, url_or_node and an optional end playing callback function. This function won’t add the sound to the available catalog of playable audio files unless the browser responds something different to ‘no’ on a call to the audio object’s function canPlayType( audioTypes[extension] ). This is how my AudioManager implementation handles the two audio sources:

    
    addAudio : function( id, url_or_node, endplaying_callback ) {
        ...
        // if a string, interpret the url_or_node as a url.
        if ( typeof url_or_node == "string" ) {
            audio= document.createElement('audio');
            if ( null!=audio ) {
                ...
            }
        } else {
            // not all browsers have the HTMLAudioElement or Audio object 
            // present, so better wrap it up.
            try {
                // url_or_node is a html node ?. Then treat it as an embedded 
                // audio tag.
                if ( url_or_node instanceof HTMLAudioElement ) {
                    ...
                }
            } catch(e) {
            }
        }
    }
    
    

    Apart from all that hacking with the sound API, the api itself some strange behaviors. In example there’s no stop playing method, just a pause method. If embedding an audio tag into the html, you can set some properties up like
    autoplay, loop (not all browsers will honor that), volume, etc.

    So in the end, and as a conclusion imho, the audio API is buggy and incomplete, with very different support flavours, so better wrap it all into a hacky class, and pray for future improved support.

    Here’s it is my final AudioManager implementation. If you something to improve, please let me know.

    
    /**
     * @author  Hyperandroid  ||  http://hyperandroid.com/
     *
     * Sound implementation.
     */
    
    (function() {
    
        /**
         * This class is a sound manager implementation which can play at least 'numChannels' sounds at the same time.
         * By default, CAAT.Director instances will set eight channels to play sound.
         * 

    * If more than 'numChannels' sounds want to be played at the same time the requests will be dropped, * so no more than 'numChannels' sounds can be concurrently played. *

    * Available sounds to be played must be supplied to every CAAT.Director instance by calling addSound * method. The default implementation will accept a URL/URI or a HTMLAudioElement as source. *

    * The cached elements can be played, or looped. The loop method will return a handler to * give the opportunity of cancelling the sound. *

    * Be aware of Audio.canPlay, is able to return 'yes', 'no', 'maybe', ..., so anything different from * '' and 'no' will do. * * @constructor * */ CAAT.AudioManager= function() { this.browserInfo= new CAAT.BrowserDetect(); return this; }; CAAT.AudioManager.prototype= { browserInfo: null, musicEnabled: true, fxEnabled: true, audioCache: null, // audio elements. channels: null, // available playing channels. workingChannels: null, // currently playing channels. loopingChannels: [], audioTypes: { // supported audio formats. Don't remember where i took them from :S "mp3": "audio/mpeg;", "ogg": "audio/ogg; codecs='vorbis'", "wav": "audio/wav; codecs='1'", "mp4": "audio/mp4; codecs='mp4a.40.2'" }, /**' * Initializes the sound subsystem by creating a fixed number of Audio channels. * Every channel registers a handler for sound playing finalization. If a callback is set, the * callback function will be called with the associated sound id in the cache. * * @param numChannels {number} number of channels to pre-create. 8 by default. * * @return this. */ initialize : function(numChannels) { this.audioCache= []; this.channels= []; this.workingChannels= []; for( var i=0; i<numChannels; i++ ) { var channel= document.createElement('audio'); if ( null!=channel ) { channel.finished= -1; this.channels.push( channel ); var me= this; channel.addEventListener( 'ended', // on sound end, set channel to available channels list. function(audioEvent) { var target= audioEvent.target; var i; // remove from workingChannels for( i=0; i<me.workingChannels.length; i++ ) { if (me.workingChannels[i]==target ) { me.workingChannels.splice(i,1); break; } } if ( target.caat_callback ) { target.caat_callback(target.caat_id); } // set back to channels. me.channels.push(target); }, false ); } } return this; }, /** * creates an Audio object and adds it to the audio cache in case the url points to a * suitable audio file to be played. *

    * If this method returns false, that sound won't be available for play, and you should try with another * sound format. * * @param id {object} an object to reference the audio object. Tipically a string. * @param url {string|HTMLElement} an url pointing to an audio resource or an HTMLAudioElement * object. * @param endplaying_callback {function} a callback function to notify on audio finalization. The * function is of the form function(id{string}). The id parameter is the associated id * in the cache. * * @return {boolean} a boolean value indicating whether the sound's been added to the catalog of playable * audio elements. A value of false means either the browser does not support audio elements, or responds 'no' * to audio object's function 'canPlayType()'. */ addAudio : function( id, url, endplaying_callback ) { var audio= null; var extension= null; if ( typeof url == "string" ) { audio= document.createElement("audio"); if ( null!=audio ) { if(!audio.canPlayType) { return false; } extension= url.substr(url.lastIndexOf(".")+1); var canplay= audio.canPlayType(this.audioTypes[extension]); if(canplay!=="" && canplay!=="no") { audio.src= url; audio.preload = "auto"; audio.load(); if ( endplaying_callback ) { audio.caat_callback= endplaying_callback; audio.caat_id= id; } this.audioCache.push( { id:id, audio:audio } ); return true; } } } else { try { if ( url instanceof HTMLAudioElement ) { audio= url; extension= audio.src.substr(audio.src.lastIndexOf(".")+1); if ( audio.canPlayType(this.audioTypes[extension]) ) { if ( endplaying_callback ) { audio.caat_callback= endplaying_callback; audio.caat_id= id; } this.audioCache.push( { id:id, audio:audio } ); return true; } } } catch(e) { } } return false; }, /** * Returns an audio object. * @param aId {object} the id associated to the target Audio object. * @return {object} the HTMLAudioElement addociated to the given id. */ getAudio : function(aId) { for( var i=0; i<this.audioCache.length; i++ ) { if ( this.audioCache[i].id==aId ) { return this.audioCache[i].audio; } } return null; }, /** * Plays an audio file from the cache if any sound channel is available. * The playing sound will occupy a sound channel and when ends playing will leave * the channel free for any other sound to be played in. * @param id {object} an object identifying a sound in the sound cache. * @return this. */ play : function( id ) { if ( !this.fxEnabled ) { return this; } var audio= this.getAudio(id); // existe el audio, y ademas hay un canal de audio disponible. if ( null!=audio && this.channels.length>0 ) { var channel= this.channels.shift(); channel.src= audio.src; channel.load(); channel.play(); this.workingChannels.push(channel); } return this; }, /** * This method creates a new AudioChannel to loop the sound with. * It returns an Audio object so that the developer can cancel the sound loop at will. * The user must call pause() method to stop playing a loop. *

    * Firefox does not honor the loop property, so looping is performed by attending end playing * event on audio elements. * * @return {HTMLElement|null} an Audio instance if a valid sound id is supplied. Null otherwise */ loop : function( id ) { if (!this.musicEnabled) { return this; } var audio_in_cache= this.getAudio(id); // existe el audio, y ademas hay un canal de audio disponible. if ( null!=audio_in_cache ) { var audio= document.createElement('audio'); if ( null!=audio ) { audio.src= audio_in_cache.src; audio.preload = "auto"; if ( this.browserInfo.browser=='Firefox') { audio.addEventListener( 'ended', // on sound end, set channel to available channels list. function(audioEvent) { var target= audioEvent.target; target.currentTime=0; }, false ); } else { audio.loop= true; } audio.load(); audio.play(); this.loopingChannels.push(audio); return audio; } } return null; }, /** * Cancel all playing audio channels * Get back the playing channels to available channel list. * * @return this */ endSound : function() { for( var i=0; i<this.workingChannels.length; i++ ) { this.workingChannels[i].pause(); this.channels.push( this.workingChannels[i] ); } for( var i=0; i<this.loopingChannels.length; i++ ) { this.loopingChannels[i].pause(); } return this; }, setSoundEffectsEnabled : function( enable ) { this.fxEnabled= enable; return this; }, isSoundEffectsEnabled : function() { return this.fxEnabled; }, setMusicEnabled : function( enable ) { this.musicEnabled= enable; for( var i=0; i<this.loopingChannels.length; i++ ) { if ( enable ) { this.loopingChannels[i].play(); } else { this.loopingChannels[i].pause(); } } return this; }, isMusicEnabled : function() { return this.musicEnabled; } }; })();

    Enjoy!!!.

    Generating documentation. JSDoc toolkit.

    For some time now, I’ve been watching for the possibility of generating CAAT’s documentation automatically, but been unable to.
    It’s not been until today, that after some deeply look at my own code and some tweaks that i’ve produced CAAT’s first automatic documentation. And it looks neat.

    In CAAT everything tries to be object oriented. At first instance I got some code from Kevin Roast’s http://www.kevs3d.co.uk/dev/canvask3d/scripts/mathlib.js. That helped me a lot to understand some concepts on javascript functions and based all my inheritance strategy from that code. So thank’s Kevin.

    But it was the use of this inheritance strategy which was preventing me from getting that pursued automatic documentation. The class definition was performed like this:


    (function() {

      // Constructor
      CAAT.class1= function() {
      };

      // Class definition
      extend( CAAT.class1, CAAT.baseclass, {
        <
          put here your overriden and new
          methods/attributes definition/implementation
        >
      });

    })();

    So, what really happeded, was:

    1. that JSDoc toolkit won’t document anything contained inside the call to extend method.
    2. contrary to what I expected, a comment out of the block (function() {})() will be totally ignored.
    3. I moved the class description comment above the constructor block previously mentioned, but the documentation still was not created. I got only the class definition comment.

    Many problems, with very simple solution.
    First of all, I’ve changed the implicit extend function to a not so nice (or yet cooler, it depends who will read this) way. The extend method, contains no overrides anymore, and these overrides are substituted by the class prototype definition:


    (function() {

      // Constructor
      CAAT.class1= function() {
      };

      CAAT.class1.prototype= {
        <
          Overrides and new attributes/methods definition.
        >
      }

      // Class extension
      extend( CAAT.class1, CAAT.baseclass );

    })();

    Rearrange the clases that way implied besides changing every class signature to conform to that syntax, refurbishing the implementation of the class method. A risky operation since the extend function is the core of class inheritance in CAAT. I’m proud to inform that javascript is an incredibly powerful languaje, so making that core change did not imply any impact on the rest of the code.
    So by changing the extend function call, and defining the prototype that way, comments for every method should have bene created, but unfortunately that is not the case yet.
    So as well as it’s nice for Closure Compiler to annotate your code with hints regarding type safety and function description it is for JSDoc toolkit as well. So by including the following annotations in the class definition comment, surprisingly for me comments started to be shown.

    @constructor

    Include also the following:
    @extends CAAT.ActorContainer
    and the inheritance information for the class definition will be shown as well, so in the end, the class definition loos like this:


    (function() {
      /**
       * Class description. Yes, it is above the expected constructor class.
       * @constructor
       * @extends CAAT.baseclass
       */
      CAAT.class1= function() {
      };

      CAAT.class1.prototype= {
      ...
      }

      // Class extension, complement the prototype and
         define superclass/constructor attributes.
      extend( CAAT.class1, CAAT.baseclass );
    })();

    Some more annotations that will enrich your sourcecode comments will be:

    • @private to mark method as private in the documentation.
    • @protected to mark method as protected in the documentation.
    • @param {type} to describe a method parameter. The type part is optional and will
      help determining what type the parameter is. Closure compiler will take care of this type.

    • etc.