Browse Source

Add tweening and ticker

Thomas Dy 11 years ago
parent
commit
5e95c3b48e
3 changed files with 194 additions and 30 deletions
  1. 9 16
      scripts/game.js
  2. 37 14
      scripts/games/safari.js
  3. 148 0
      scripts/util.js

+ 9 - 16
scripts/game.js

@@ -1,21 +1,14 @@
+Ticker.start();
+
 var Game = {
   canvas: document.getElementById('game'),
   keysDown: {},
   start: function() {
     Game.sceneManager.push(MainMenu);
-    this.then = Date.now();
-    this.time = 0;
-    setInterval(function() {
-      Game.loop();
-    }, 10);
-  },
-  loop: function() {
-    var now = Date.now();
-    var delta = now - this.then;
-    this.time += delta;
-    this.sceneManager.update(delta/1000);
-    this.sceneManager.draw();
-    this.then = now;
+    Ticker.addListener(function(dt) {
+      Game.sceneManager.update(dt);
+      Game.sceneManager.draw();
+    });
   },
   pause: function() {
     Game.sceneManager.push(PauseScreen);
@@ -91,13 +84,13 @@ var MainMenu = {
     ];
 
     Game.sceneManager.push(new SoundSafari(beats));
-  };
+  }
   MainMenu.load = MainMenu.resume = function() {
     addEventListener('keyup', onKeyUp);
-  }
+  };
   MainMenu.unload = MainMenu.pause = function() {
     removeEventListener('keyup', onKeyUp);
-  }
+  };
 })();
 
 var PauseScreen = {

+ 37 - 14
scripts/games/safari.js

@@ -355,7 +355,7 @@ function SoundSafari(beatInfo) {
 
     activeTarget = new Target(currentBeat);
     entities.push(activeTarget);
-  };
+  }
 
   function reset() {
     points = 0;
@@ -391,7 +391,7 @@ function SoundSafari(beatInfo) {
     }
 
     switchBeat(0);
-  };
+  }
 
   // Update
   this.update = function(dt) {
@@ -440,16 +440,10 @@ function SoundSafari(beatInfo) {
   };
 
   this.draw = function() {
-    ctx.fillStyle = "black";
-    ctx.fillRect(0, 0, canvas.width, canvas.height);
+    if(state.current != 'loading') {
+      ctx.fillStyle = "black";
+      ctx.fillRect(0, 0, canvas.width, canvas.height);
 
-    if(state.current == 'loading') {
-      ctx.fillStyle = 'white';
-      ctx.textAlign = 'center';
-      ctx.fillText("Loading...", canvas.width / 2, canvas.height / 2);
-      ctx.textAlign = 'start';
-    }
-    else {
       entities.map(function(elem) {
         elem.draw();
       });
@@ -462,6 +456,22 @@ function SoundSafari(beatInfo) {
         drawSpectrum();
       }
     }
+
+    if(this.coverAlphaTween.promise.isPending()) {
+      ctx.globalAlpha = this.coverAlphaTween.value;
+      ctx.fillStyle = "black";
+      ctx.fillRect(0, 0, canvas.width, canvas.height);
+      ctx.globalAlpha = 1;
+    }
+
+    if(state.current == 'loading') {
+      ctx.globalAlpha = this.textAlphaTween.value;
+      ctx.fillStyle = 'white';
+      ctx.textAlign = 'center';
+      ctx.fillText("sound safari", canvas.width / 2, canvas.height / 2);
+      ctx.textAlign = 'start';
+      ctx.globalAlpha = 1;
+    }
   };
 
   var onKeyUp = function(e) {
@@ -485,9 +495,22 @@ function SoundSafari(beatInfo) {
       return promise;
     });
     soundPromises.push(createSound('get', 'sound/get.mp3'));
-    Q.all(soundPromises).done(function() {
+
+    this.textAlphaTween = Tween
+      .from(0)
+      .to(1, 1.5)
+      .wait(1)
+      .waitFor(Q.all(soundPromises))
+      .to(0, 1.5)
+      .animate();
+    this.coverAlphaTween = Tween
+      .from(1)
+      .waitFor(this.textAlphaTween.promise)
+      .to(0, 1)
+      .animate();
+    this.textAlphaTween.promise.done(function() {
       state.ready();
-    })
+    });
   };
 
   this.unload = function() {
@@ -505,4 +528,4 @@ function SoundSafari(beatInfo) {
     addEventListener('keyup', onKeyUp);
     currentBeats.map(function(beat) {beat.sound.resume()});
   };
-};
+}

+ 148 - 0
scripts/util.js

@@ -19,6 +19,10 @@ function lerp(from, to, p) {
 
 function ease(v) { return v * v * (3 - 2 * v); }
 
+function easeLinear(t, b, c, d) {
+  return lerp(b, c, t/d);
+}
+
 function easeOutExpo(t, b, c, d) {
   return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
 }
@@ -26,3 +30,147 @@ function easeOutExpo(t, b, c, d) {
 function color(r,g,b,a) {
   return 'rgba('+r+','+g+','+b+','+a.toFixed(5)+')';
 }
+
+// Ticker
+var Ticker = {};
+(function(Ticker) {
+  var listeners = [];
+
+  Ticker.addListener = function(listener) {
+    listeners.push(listener);
+  }
+
+  Ticker.removeListener = function(listener) {
+    var index = listeners.indexOf(listener);
+    listeners.splice(index, 1);
+  }
+
+  var nextFrame =
+    window.requestAnimationFrame ||
+      window.webkitRequestAnimationFrame ||
+      window.mozRequestAnimationFrame ||
+      function (callback) {
+        setTimeout(function () {
+          callback(Date.now())
+        }, 10)
+      };
+
+  var then = Date.now();
+  function tick(now) {
+    var delta = (now - then) / 1000;
+    listeners.forEach(function(listener){
+      listener(delta);
+    })
+    then = now;
+    nextFrame(tick);
+  }
+
+  Ticker.start = function() {
+    nextFrame(tick);
+  }
+})(Ticker);
+
+// Tweens
+function BaseTween() {}
+BaseTween.prototype.animate = function() {
+  var self = this;
+  function tick(dt) {
+    self.update(dt);
+  }
+  Ticker.addListener(tick);
+  self.promise.then(function() {
+    Ticker.removeListener(tick);
+  });
+  self.update(0);
+  return self;
+};
+
+function Tween(duration, start, end, easing) {
+  this.duration = duration;
+  this.start = start;
+  this.end = end;
+  this.easing = easing || easeLinear;
+  this.deferred = Q.defer();
+  this.timer = 0;
+  this.promise = this.deferred.promise;
+};
+
+Tween.prototype = new BaseTween();
+
+Tween.prototype.update = function(dt) {
+  this.timer += dt;
+  if(this.timer >= this.duration) {
+    this.timer = this.duration;
+    this.deferred.resolve();
+  }
+  this.value = this.easing(this.timer, this.start, this.end, this.duration);
+};
+
+function PromiseTween(value, promise) {
+  this.value = value;
+  this.promise = promise;
+}
+
+PromiseTween.prototype.update = function() {};
+
+function ComposedTween(tweens) {
+  this.tweens = tweens;
+  this.promise = Q.all(this.tweens.map(function(t) { return t.promise }));
+  this.switch(0);
+}
+
+ComposedTween.prototype = new BaseTween();
+
+ComposedTween.prototype.switch = function(index) {
+  if(index >= this.tweens.length) return;
+  var self = this;
+  this.current = index;
+  this.tweens[index].promise.then(function() {
+    self.switch(index + 1);
+  });
+};
+
+ComposedTween.prototype.update = function(dt) {
+  if(this.current >= this.tweens.length) return;
+  var active = this.tweens[this.current];
+  active.update(dt);
+  this.value = active.value;
+};
+
+function DeferredTween(start) {
+  this.lastTarget = start;
+  this.tweens = [];
+}
+
+DeferredTween.prototype = new BaseTween();
+
+DeferredTween.prototype.addTween = function(tween) {
+  this.tweens.push(tween);
+  this.tween = new ComposedTween(this.tweens);
+  this.promise = this.tween.promise;
+  return this;
+}
+
+DeferredTween.prototype.to = function(target, duration, easing) {
+  easing = easing || easeLinear;
+  this.addTween(new Tween(duration, this.lastTarget, target, easing));
+  this.lastTarget = target;
+  return this;
+};
+
+DeferredTween.prototype.wait = function(duration) {
+  return this.to(this.lastTarget, duration);
+};
+
+DeferredTween.prototype.waitFor = function(promise) {
+  return this.addTween(new PromiseTween(this.lastTarget, promise));
+};
+
+DeferredTween.prototype.update = function(dt) {
+  this.tween.update(dt);
+  this.value = this.tween.value;
+};
+
+Tween.from = function(start) {
+  return new DeferredTween(start);
+};