Friday, February 28, 2014

Request Animation Frame Loops Demystified - How to get started

Today I'm going to start with using snowblower to make some request animation frame loops.

~function(window, define, module, Array, Object){
'use strict';
var slice = Array.slice, create = Object.create;
function partial(func) {
var args1 = slice.call(arguments, 1);
return function(){
return func.apply(this, args1.concat(slice.call(arguments)));
};
}
function mixIn(target, ref) {
for (var key in ref) {
if (ref.hasOwnProperty(key)) {
target[key] = ref[key];
}
}
return target;
}
function argsMixInExec(args, prev, next) {
typeof next === 'function' ? next.apply(prev, args) : mixIn(prev, next);
return prev;
}
function SnowBlower(proto) {
var closures;
proto = proto || {};
closures = slice.call(arguments,1);
return function() {
return closures.reduce(partial(argsMixInExec, slice.call(arguments)), create(proto));
};
}
SnowBlower.mixIn = mixIn;
SnowBlower.partial = partial;
if(define){
define(SnowBlower);
} else if(module) {
module.exports = SnowBlower;
} else {
window.SnowBlower = SnowBlower;
}
}(typeof window !== 'undefined'?window:{},typeof define==='function'?define:null,typeof module!=='undefined'?module:null,[], Object);
view raw SnowBlower.js hosted with ❤ by GitHub

In whatever context you want, make a SnowBlower factory for a stage. Your runtime should create one instance of a stage for every canvas you need.

function _animationFunctions(){
//locally cached reference for speed
var animationFunctions = this.animationFunctions = [],
slice = [].slice;
//we use this as a reference to a no Op function to give our API a way to remove animation functions later
function noOp(){}
//store these variable out of here so they never have to be allocated inside of your draw loop
var _funcIndex = -1, _animationIndex = 0, _len = 0;
requestAnimationFrame(function draw(){
_animationIndex = 0;
_len = animationFunctions.length;
for(;_animationIndex < _len;_animationIndex++) {
animationFunctions[_animationIndex]();//call the function!
}
//find noOps that were declared inside of the draw loop
_funcIndex = animationFunctions.indexOf(noOp);
while(_funcIndex > -1){
//Always remove EVERY noOp function reference outside of the loop
animationFunctions.splice(_funcIndex, 1);
//get the next index
_funcIndex = animationFunctions.indexOf(noOp);
}
});
this.removeAnimationFunctions = function(){
var idx = 0, funcIdx = -1, len = arguments.length;
for(;idx<len;idx++){
funcIdx = animationFunctions.indexOf(arguments[idx]);
if(funcIdx>0){
//this can be called INSIDE OF THE ANIMATION LOOP
animationFunctions = noOp;
//DO NOT SPLICE HERE
}
}
};
}
var Stage = SnowBlower({}, _animationFunctions);

Here it is folks. I did not write specific code for your rendering engine. You need to expose whatever stage to the objects your are creating so they can call this code:

var myStage = Stage();
function _drawFunc(options){
options.stage.animationFunctions.push(function(){
//do your draw stuff and animation here
})
}
var ObjectOnStage = SnowBlower({}, _drawFunc);
var obj = ObjectOnStage({
stage: myStage
});

Piece of cake. Now all you have to do is pick a rendering engine, render the view in the request animation loop, and create your game.

I suggest using PIXI.js or phaser.js because it's a really great API for canvas rendering. Make sure you do all the work before adding the item to the stage. Remove as many variable declarations outside of the draw function as possible to prevent as much resource allocation and memory leaking as possible. Keep it simple. If you want to pass the draw function a parameter or use "this" as the stage, you can modify your request animation loop like this:

//reference this for use in other functions
var self = this;
//modify loop....
requestAnimationFrame(function draw(){
_animationIndex = 0;
_len = animationFunctions.length;
for(;_animationIndex < _len;_animationIndex++) {
//call the function with a reference to the stage object and some arguments
//passing information to the animation functions can definitely be useful
animationFunctions[_animationIndex].call(self, arguments...);
}
//find noOps that were declared inside of the draw loop
_funcIndex = animationFunctions.indexOf(noOp);
while(_funcIndex > -1){
//Always remove EVERY noOp function reference outside of the loop
animationFunctions.splice(_funcIndex, 1);
//get the next index
_funcIndex = animationFunctions.indexOf(noOp);
}
});

In the end, everything is logical and fun.

Have any suggestions? Feel free to comment/post on Google Plus.

Thanks!

~function(){'use awesome';console.log('josh')}();

Monday, February 24, 2014

SnowBlower and Object Composition

~function(window, define, module, Array, Object){
'use strict';
var slice = Array.slice, create = Object.create;
function partial(func) {
var args1 = slice.call(arguments, 1);
return function(){
return func.apply(this, args1.concat(slice.call(arguments)));
};
}
function mixIn(target, ref) {
for (var key in ref) {
if (ref.hasOwnProperty(key)) {
target[key] = ref[key];
}
}
return target;
}
function argsMixInExec(args, prev, next) {
typeof next === 'function' ? next.apply(prev, args) : mixIn(prev, next);
return prev;
}
function SnowBlower(proto) {
var closures;
proto = proto || {};
closures = slice.call(arguments,1);
return function() {
return closures.reduce(partial(argsMixInExec, slice.call(arguments)), create(proto));
};
}
SnowBlower.mixIn = mixIn;
SnowBlower.partial = partial;
if(define){
define(SnowBlower);
} else if(module) {
module.exports = SnowBlower;
} else {
window.SnowBlower = SnowBlower;
}
}(typeof window !== 'undefined'?window:{},typeof define==='function'?define:null,typeof module!=='undefined'?module:null,[], Object);
view raw SnowBlower.js hosted with ❤ by GitHub

I'm going to talk about this "library" and why it's very useful. It takes a lot of the compositional techniques of objects and makes it really fun.

Here's an example of how to use SnowBlower.

~function(window, SnowBlower){
var Proto = {
//prototype stuff here
};
function _defaultParameters(options) {
if(!options){
throw new Error("options is not defined");
}
options.x = options.x || 0;
options.y = options.y || 0;
options.width = options.width || 100;
options.height = options.height || 100;
}
function _sprite () {
//"this" is the sprite you are making
this.x = options.x;
this.y = options.y;
this.width = options.width;
this.height = options.height;
}
var SpriteFactory = SnowBlower(Proto, _defaultParameters, _sprite);
window.SpriteFactory = SpriteFactory;
}(window, SnowBlower);
view raw Sprite.js hosted with ❤ by GitHub

It takes all the functions and objects that you pass to it, and either executes it in the context of your new object, or mixes it into your new object. If you need polyfills for your environment, just define Array.prototype.reduce, Object.create, and replace the Object.prototype.hasOwnProperty function to reflect your environment.

It's designed to be small and SnowBlower assumes you have all the pieces and closures that define your object up front. If you need to compose factories, you can just create a function that does it for you.

var proto = {};
function PartialFactory() {
var args1 = [proto].concat([].slice.call(arguments));
return function(){
return SnowBlower.apply(this, args1.concat([].slice.call(arguments)));
};
}
//Now pass some arguments to PartialFactory to predefine your factory

This is a DRY method of reusing functions you have already defined to compose objects. The sky is the limit! Just thought I would share this compositional technique with you.

~function(){console.log('josh')}();

Wednesday, February 19, 2014

Your Instatouch Library is Cute

I love the JS community. In fact, I think it's the best community to be in programming wise. There is so much support when you need help, especially if you have no idea what you are talking about.

I just want to point out a few things that have taken steps backwards in the past few years when it comes to mobile web experience.

There are at least a dozen different libraries like this: https://github.com/ftlabs/fastclick where the goal is to make the web more responsive. As a mobile phone user, these packages make my experience WORSE. There, I said it.

The reason why it's worse, I've found, is because I like to scroll and read content on the page. If my finger happens to press a link while I am swiping on the page, it fires the click event! This is definitely not good if that link happens to do something very permanent. At best, I found myself pressing the back button so much I gave up completely frustrated with my experience.

My recent experience on cheezburger was rather frustrating because the links take up the whole screen! Maybe I'm just too slow, or JS wasn't designed to do this. I'm willing to accept either, but I'm definitely used to the way browsers work on my phone.

Your Instatouch library is cute, but it makes my user experience more difficult in some cases, and only marginally faster in others. Thanks but no thanks guys, I'll take the DOM as it is.

-Josh

Tuesday, February 18, 2014

Installing Node.js on my Android Phone

I have the LG Optimus G on Sprint (LS970) and had to do a couple of things to my phone before I could start using node from the command line. I had to root, install TWRP, and then install DebianKit (the biggest offender on being a Pain In my Rear.)

Anyway, here is the steps I took to get everything working.

Some notes I had:
  1. I could not install anything useful on my phone using apt-get until I resized the debian.img file on the sdcard.
  2. I had to do a lot of trial and error before I could finally get the debian image resized correctly
  3. Installing nvm was easy once I had space
  4. I had fun

In functional health:
~function(){console.log('Josh')}()