js: the requestAnimationFrame() game loop

Historically, web/js based apps had to basically set their own “loop” using setInterval or setTimeout. There’s actually not a huge downside to using those, except when framerate becomes an issue. So now we can use requestAnimationFrame(). It has a number of uses, but the simplest is just to have it handle the entire game loop.

Essentially RAF calls a callback function every time the interpreter can come up for air. This combined with tracking the delta in time between frames can allow you to handle changes in framerate more smoothly.

In the implementation below calling myGame.actionLoop() calls recurse(), which then has requestAnimationFrame call the recurse loop repeatedly. I’ve broken the specific game logic out into the function var doThisEveryFrame just to clearly illustrate the effect.

myGame.actionLoop = function() {
    var lastFrameTime;
    var deltaT;
    var lowEnd = 1;
    var highEnd = 160;

    var doThisEveryFrame = function(timeDiff){
      myGame.updatePhysics(timeDiff);
      myGame.updateLogic(timeDiff);
      myGame.renderChangesToScreen();
    };

    function recurse( thisFrameTime ) {
        window.requestAnimationFrame(recurse);
        thisFrameTime = thisFrameTime && thisFrameTime > 5000 ? thisFrameTime : window.performance.now();
        lastFrameTime = lastFrameTime || thisFrameTime;
        deltaT = thisFrameTime - lastFrameTime;

        if (deltaT >  highEnd){
          deltaT = highEnd;
        }
        if(deltaT > lowEnd){
          doThisEveryFrame(deltaT);
          lastFrameTime = thisFrameTime;
        }
    }
  recurse();
};

mysql: early testing & foreign key syntax

Early on in a local project, I kept finding out of date, or strange references to setting up Foreign Keys in various complicated situations in MySQL, this resulted in not only me being confused, but in constantly needing to drop tables and rebuild them. Which was annoying.

Using Node as the backend framework, it dawned on me, that I could just have three terminals open, one running the Node server, one using the mysql> prompt, and the third running terminal commands to rebuild the database using the schema.sql file. Failing quickly is always better than failing slowly.

So the order went:
1. Test something, screw up database.
2. Terminal 1: mysql> drop database people;
3. Terminal 2: $: mysql -u root < schema.sql
4. Terminal 3: execute stuff on server
5. Go back to 1.

Here's an example schema file, in case you came here just looking for Foreign Key syntax:

CREATE DATABASE people;
USE people;

CREATE TABLE parents(
  id INT NOT NULL AUTO_INCREMENT,
  name VARCHAR(20) NULL DEFAULT NULL,
  PRIMARY KEY(id)
);

CREATE TABLE locations(
  id INT NOT NULL AUTO_INCREMENT,
  name VARCHAR(20) NULL DEFAULT NULL,
  PRIMARY KEY(id)
);

CREATE TABLE children(
  id INT NOT NULL AUTO_INCREMENT,
  name VARCHAR(140) NULL DEFAULT NULL,
  parentId INT,
  locationId INT,
  PRIMARY KEY(id),
  INDEX(parentId, locationId),
  FOREIGN KEY (parentId) REFERENCES parents(id) ON DELETE CASCADE,
  FOREIGN KEY (locationId) REFERENCES locations(id) ON DELETE CASCADE
);

js: window.performance on mobile

I’d been playing around with some graphically intensive tests in javascript and openGL, but when I went to test them on various mobile devices, huge aspects of them were failing. After a few minutes I realized that window.performance.now was missing. Here’s a shim I found that does the trick.

(function(){
  if ("performance" in window == false) {
      window.performance = {};
  }
  Date.now = (Date.now || function () {
    return new Date().getTime();
  });
  if ("now" in window.performance == false){
    var nowOffset = Date.now();
    if (performance.timing && performance.timing.navigationStart){
      nowOffset = performance.timing.navigationStart
    }
    window.performance.now = function now(){
      return Date.now() - nowOffset;
    }
  }
})();

the above polyfill is // copyright Paul Irish 2015