|
@@ -1,559 +1,563 @@
|
|
|
-var canvas = document.getElementById('game');
|
|
|
-var ctx = canvas.getContext('2d');
|
|
|
-
|
|
|
-var beatUrls = [
|
|
|
- 'sound/b1.mp3',
|
|
|
- 'sound/b2.mp3',
|
|
|
- 'sound/b3.mp3',
|
|
|
- 'sound/b4.mp3',
|
|
|
- 'sound/b5.mp3'
|
|
|
-];
|
|
|
-
|
|
|
-var createSound = function(name, url) {
|
|
|
- var deferred = Q.defer();
|
|
|
- soundManager.createSound({
|
|
|
- id: name,
|
|
|
- url: url,
|
|
|
- autoLoad: true,
|
|
|
- onload: function() {
|
|
|
- deferred.resolve(this);
|
|
|
- }
|
|
|
- });
|
|
|
- return deferred.promise;
|
|
|
-};
|
|
|
-
|
|
|
-var starColors = [
|
|
|
- 'maroon',
|
|
|
- 'red',
|
|
|
- 'orange',
|
|
|
- 'yellow',
|
|
|
- 'olive',
|
|
|
- 'green',
|
|
|
- 'teal',
|
|
|
- 'blue',
|
|
|
- 'navy',
|
|
|
- 'purple'
|
|
|
-];
|
|
|
-
|
|
|
-var paused = false;
|
|
|
-var debug = false;
|
|
|
-var beats = [];
|
|
|
-var beatTime = 0;
|
|
|
-var currentBeats = [];
|
|
|
-var gotPoint = false;
|
|
|
-
|
|
|
-var switchBeat = function(index) {
|
|
|
- var currentBeat = beats[index];
|
|
|
- activeTarget.beat = currentBeat;
|
|
|
- currentBeats.push(currentBeat);
|
|
|
- if(currentBeats.length > 4) {
|
|
|
- currentBeats.splice(0, 1);
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-var soundDeferred = Q.defer();
|
|
|
-var soundPromise = soundDeferred.promise;
|
|
|
-soundManager.setup({
|
|
|
- url: 'swf/',
|
|
|
- flashVersion: 9,
|
|
|
- onready: function() {
|
|
|
- soundDeferred.resolve(this);
|
|
|
- }
|
|
|
-});
|
|
|
-
|
|
|
-soundPromise = soundPromise.then(function() {
|
|
|
- var beatPromises = [];
|
|
|
- beatUrls.map(function(elem, index) {
|
|
|
- beatPromises.push(createSound('beat'+index, elem));
|
|
|
- });
|
|
|
-
|
|
|
- return Q.spread([
|
|
|
- Q.all(beatPromises),
|
|
|
- createSound('get', 'sound/get.mp3')
|
|
|
- ], function(beatz) {
|
|
|
- beats = beatz;
|
|
|
- })
|
|
|
-});
|
|
|
-
|
|
|
-
|
|
|
-var keysDown = {};
|
|
|
-
|
|
|
-addEventListener('keydown', function(e) {
|
|
|
- keysDown[e.keyCode] = true;
|
|
|
-}, false);
|
|
|
-
|
|
|
-addEventListener('keyup', function(e) {
|
|
|
- if(e.keyCode == 68) {
|
|
|
- debug = !debug;
|
|
|
- }
|
|
|
- if(e.keyCode == 80) {
|
|
|
- pause();
|
|
|
- }
|
|
|
- delete keysDown[e.keyCode];
|
|
|
-}, false);
|
|
|
-
|
|
|
-addEventListener('blur', function() {
|
|
|
- if(!paused) pause();
|
|
|
-});
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-var RADIUS = 8;
|
|
|
-var LEAF_SIZE = 8;
|
|
|
-var LEVEL_SIZE = 800;
|
|
|
-var ALLOWANCE = (LEVEL_SIZE - canvas.width)/2;
|
|
|
-var METER_WIDTH = 120;
|
|
|
-var METER_HEIGHT = 40;
|
|
|
-var METER_SPEED = 10;
|
|
|
-var PLAYER_SPEED = 50;
|
|
|
-var STAGE_SPEED = 25;
|
|
|
-var RIPPLE_SIZE = 10;
|
|
|
-var RIPPLE_SPEED = 10;
|
|
|
-var DOT_SIZE = 3;
|
|
|
-var DOT_DISTANCE = 4 * 5;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-function drawCircle(point, r, w, color) {
|
|
|
- ctx.beginPath();
|
|
|
- ctx.arc(point.x, point.y, r, 0, 2*Math.PI, false);
|
|
|
- ctx.lineWidth = w;
|
|
|
- ctx.strokeStyle = color;
|
|
|
- ctx.stroke();
|
|
|
-}
|
|
|
-
|
|
|
-function drawLeafV(point, h, w) {
|
|
|
- ctx.beginPath();
|
|
|
- ctx.moveTo(point.x, point.y);
|
|
|
- ctx.quadraticCurveTo(point.x + w, point.y + h/2, point.x, point.y + h);
|
|
|
- ctx.quadraticCurveTo(point.x - w, point.y + h/2, point.x, point.y);
|
|
|
- ctx.fill();
|
|
|
-}
|
|
|
-
|
|
|
-function drawLeafH(point, w, h) {
|
|
|
- ctx.beginPath();
|
|
|
- ctx.moveTo(point.x, point.y);
|
|
|
- ctx.quadraticCurveTo(point.x + w/2, point.y + h, point.x + w, point.y);
|
|
|
- ctx.quadraticCurveTo(point.x + w/2, point.y - h, point.x, point.y);
|
|
|
- ctx.fill();
|
|
|
-}
|
|
|
-
|
|
|
-function drawPlayer(point) {
|
|
|
- drawCircle(point, RADIUS, 5, "#FFFFFF");
|
|
|
-}
|
|
|
-
|
|
|
-function drawSpectrum() {
|
|
|
- var barHeight = 30;
|
|
|
- var barWidth = 6;
|
|
|
- var barSpacing = 2;
|
|
|
- var margin = 5;
|
|
|
- ctx.strokeStyle = 'white';
|
|
|
- ctx.lineWidth = 2;
|
|
|
- ctx.beginPath();
|
|
|
- ctx.rect(
|
|
|
- margin - ctx.lineWidth,
|
|
|
- canvas.height - barHeight - ctx.lineWidth - margin,
|
|
|
- activeTarget.spectrum.length * (barWidth+barSpacing) + 2 * ctx.lineWidth - barSpacing,
|
|
|
- barHeight + 2 * ctx.lineWidth
|
|
|
- );
|
|
|
- ctx.stroke();
|
|
|
- for(var i = 0; i < activeTarget.spectrum.length; ++i) {
|
|
|
- var height = activeTarget.spectrum[i]*20;
|
|
|
- ctx.fillStyle = starColors[i];
|
|
|
- ctx.fillRect(i * (barWidth + barSpacing) + margin, canvas.height - height - margin, barWidth, height);
|
|
|
- }
|
|
|
+function createSound(name, url) {
|
|
|
+ var deferred = Q.defer();
|
|
|
+ soundManager.createSound({
|
|
|
+ id: name,
|
|
|
+ url: url,
|
|
|
+ autoLoad: true,
|
|
|
+ onload: function() {
|
|
|
+ deferred.resolve(this);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return deferred.promise;
|
|
|
}
|
|
|
|
|
|
function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }
|
|
|
|
|
|
function lerp(from, to, p) {
|
|
|
- return to * p + from * (1 - p);
|
|
|
+ return to * p + from * (1 - p);
|
|
|
}
|
|
|
|
|
|
function ease(v) { return v * v * (3 - 2 * v); }
|
|
|
|
|
|
function easeOutExpo(t, b, c, d) {
|
|
|
- return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
|
|
|
+ return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
|
|
|
}
|
|
|
|
|
|
function color(r,g,b,a) {
|
|
|
- return 'rgba('+r+','+g+','+b+','+a.toFixed(5)+')';
|
|
|
-}
|
|
|
-
|
|
|
-function distX(a, b) {
|
|
|
- var dx = a.x - b.x;
|
|
|
- if(dx > LEVEL_SIZE / 2) dx -= LEVEL_SIZE;
|
|
|
- if(dx < -LEVEL_SIZE / 2) dx += LEVEL_SIZE;
|
|
|
- return dx;
|
|
|
-}
|
|
|
-
|
|
|
-function distSq(a, b) {
|
|
|
- var c = distX(a, b);
|
|
|
- var d = a.y - b.y;
|
|
|
- return c * c + d * d;
|
|
|
-}
|
|
|
-
|
|
|
-function colliding(a, b) {
|
|
|
- return distSq(a, b) <= 4 * RADIUS * RADIUS;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-function Meter() {
|
|
|
- this.offset = 10;
|
|
|
- this.amp = 0;
|
|
|
- this.percentage = 0;
|
|
|
- this.direction = METER_SPEED;
|
|
|
+ return 'rgba('+r+','+g+','+b+','+a.toFixed(5)+')';
|
|
|
}
|
|
|
|
|
|
-Meter.prototype.draw = function() {
|
|
|
- var left = (canvas.width - METER_WIDTH) / 2;
|
|
|
- var vmid = this.offset + METER_HEIGHT / 2;
|
|
|
- var third = METER_WIDTH / 3;
|
|
|
- var peak = METER_HEIGHT / 2;
|
|
|
-
|
|
|
- ctx.fillStyle = 'black';
|
|
|
- ctx.rect(left, this.offset, METER_WIDTH, METER_HEIGHT);
|
|
|
- ctx.fill();
|
|
|
-
|
|
|
- var cpUp = lerp(vmid, vmid + peak * this.amp, this.percentage);
|
|
|
- var cpDown = lerp(vmid, vmid - peak * this.amp, this.percentage);
|
|
|
-
|
|
|
- ctx.lineWidth = 2;
|
|
|
- ctx.strokeStyle = 'red';
|
|
|
- ctx.beginPath();
|
|
|
- var pos = left;
|
|
|
- ctx.moveTo(left, vmid);
|
|
|
- ctx.quadraticCurveTo(pos+third/2, cpUp, pos+third, vmid);
|
|
|
- pos += third;
|
|
|
- ctx.quadraticCurveTo(pos+third/2, cpDown, pos+third, vmid);
|
|
|
- pos += third;
|
|
|
- ctx.quadraticCurveTo(pos+third/2, cpUp, pos+third, vmid);
|
|
|
- ctx.stroke();
|
|
|
-
|
|
|
- ctx.lineWidth = 3;
|
|
|
- ctx.strokeStyle = 'white';
|
|
|
- ctx.beginPath();
|
|
|
- ctx.rect(left, this.offset, METER_WIDTH, METER_HEIGHT);
|
|
|
- ctx.stroke();
|
|
|
-};
|
|
|
-
|
|
|
-Meter.prototype.onUpdate = function(dt) {
|
|
|
- if(this.percentage > 1) {
|
|
|
- this.direction = -METER_SPEED;
|
|
|
- }
|
|
|
- if(this.percentage < -1) {
|
|
|
- this.direction = METER_SPEED;
|
|
|
- }
|
|
|
- this.percentage += this.direction * dt;
|
|
|
- this.amp = 0.5 + lerp(0, 1, activeTarget.shimmerFactor);
|
|
|
-};
|
|
|
-
|
|
|
-function Star(x, y) {
|
|
|
- this.x = x;
|
|
|
- this.y = y;
|
|
|
- this.alpha = 0;
|
|
|
- this.randomize();
|
|
|
-}
|
|
|
-
|
|
|
-Star.prototype.randomize = function() {
|
|
|
- this.type = Math.floor(Math.random()*starColors.length);
|
|
|
- this.color = starColors[this.type];
|
|
|
-};
|
|
|
-
|
|
|
-Star.prototype.draw = function() {
|
|
|
- ctx.fillStyle = this.color;
|
|
|
- ctx.globalAlpha = this.alpha;
|
|
|
- var adjPosition = translatePoints(this);
|
|
|
- ctx.fillRect(adjPosition.x, adjPosition.y, DOT_SIZE, DOT_SIZE);
|
|
|
-
|
|
|
- var top = {x: adjPosition.x + DOT_SIZE/2, y: adjPosition.y - DOT_SIZE/2 };
|
|
|
- var bottom = {x: adjPosition.x + DOT_SIZE/2, y: adjPosition.y + DOT_SIZE/2*3};
|
|
|
- var left = {x: adjPosition.x - DOT_SIZE/2, y: adjPosition.y + DOT_SIZE/2 };
|
|
|
- var right = {x: adjPosition.x + DOT_SIZE/2*3, y: adjPosition.y + DOT_SIZE/2 };
|
|
|
-
|
|
|
- drawLeafH(left, -LEAF_SIZE, LEAF_SIZE/2);
|
|
|
- drawLeafH(right, LEAF_SIZE, LEAF_SIZE/2);
|
|
|
- drawLeafV(top, -LEAF_SIZE, LEAF_SIZE/2);
|
|
|
- drawLeafV(bottom, LEAF_SIZE, LEAF_SIZE/2);
|
|
|
- ctx.globalAlpha = 1;
|
|
|
-};
|
|
|
-
|
|
|
-Star.prototype.onUpdate = function() {
|
|
|
- if(gotPoint) {
|
|
|
- this.randomize();
|
|
|
- }
|
|
|
- if(this.y > canvas.height + DOT_DISTANCE * 2) {
|
|
|
- this.y -= canvas.height + DOT_DISTANCE * 4;
|
|
|
- }
|
|
|
- var newAlpha = 1.5 * activeTarget.spectrum[this.type];
|
|
|
- var a = 0.001;
|
|
|
- if(newAlpha > this.alpha) {
|
|
|
- a = 0.9;
|
|
|
+var SoundSafari = function(canvas, beatInfo, pSoundManager) {
|
|
|
+ var ctx = canvas.getContext('2d');
|
|
|
+
|
|
|
+
|
|
|
+ var RADIUS = 8;
|
|
|
+ var LEAF_SIZE = 8;
|
|
|
+ var LEVEL_SIZE = 800;
|
|
|
+ var ALLOWANCE = (LEVEL_SIZE - canvas.width)/2;
|
|
|
+ var METER_WIDTH = 120;
|
|
|
+ var METER_HEIGHT = 40;
|
|
|
+ var METER_SPEED = 10;
|
|
|
+ var PLAYER_SPEED = 50;
|
|
|
+ var STAGE_SPEED = 25;
|
|
|
+ var RIPPLE_SIZE = 10;
|
|
|
+ var RIPPLE_SPEED = 10;
|
|
|
+ var DOT_SIZE = 3;
|
|
|
+ var DOT_DISTANCE = 4 * 5;
|
|
|
+
|
|
|
+ var starColors = [
|
|
|
+ 'maroon',
|
|
|
+ 'red',
|
|
|
+ 'orange',
|
|
|
+ 'yellow',
|
|
|
+ 'olive',
|
|
|
+ 'green',
|
|
|
+ 'teal',
|
|
|
+ 'blue',
|
|
|
+ 'navy',
|
|
|
+ 'purple'
|
|
|
+ ];
|
|
|
+
|
|
|
+ var paused = false;
|
|
|
+ var debug = false;
|
|
|
+
|
|
|
+ var beats = [];
|
|
|
+ var gameTime = 0;
|
|
|
+ var currentBeats = [];
|
|
|
+ var gotPoint = false;
|
|
|
+
|
|
|
+ var switchBeat = function(index) {
|
|
|
+ var currentBeat = beats[index];
|
|
|
+ currentBeats.push(currentBeat);
|
|
|
+ if(currentBeats.length > 4) {
|
|
|
+ currentBeats.splice(0, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ activeTarget = new Target(currentBeat);
|
|
|
+ entities.push(activeTarget);
|
|
|
+ };
|
|
|
+
|
|
|
+ var soundPromise = pSoundManager.then(function() {
|
|
|
+ var soundPromises = beatInfo.map(function(elem, index) {
|
|
|
+ var beat = { info: elem, rounds: 0 };
|
|
|
+ var promise = createSound('beat'+index, elem.url).then(function(sound) {
|
|
|
+ beat.sound = sound;
|
|
|
+ });
|
|
|
+ beats.push(beat);
|
|
|
+ return promise;
|
|
|
+ });
|
|
|
+ soundPromises.push(createSound('get', 'sound/get.mp3'));
|
|
|
+
|
|
|
+ return Q.all(soundPromises);
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ var keysDown = {};
|
|
|
+
|
|
|
+ addEventListener('keydown', function(e) {
|
|
|
+ keysDown[e.keyCode] = true;
|
|
|
+ }, false);
|
|
|
+
|
|
|
+ addEventListener('keyup', function(e) {
|
|
|
+ if(e.keyCode == 68) {
|
|
|
+ debug = !debug;
|
|
|
+ }
|
|
|
+ if(e.keyCode == 80) {
|
|
|
+ pause();
|
|
|
+ }
|
|
|
+ delete keysDown[e.keyCode];
|
|
|
+ }, false);
|
|
|
+
|
|
|
+ addEventListener('blur', function() {
|
|
|
+ if(!paused) pause();
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ function drawCircle(point, r, w, color) {
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.arc(point.x, point.y, r, 0, 2*Math.PI, false);
|
|
|
+ ctx.lineWidth = w;
|
|
|
+ ctx.strokeStyle = color;
|
|
|
+ ctx.stroke();
|
|
|
}
|
|
|
- this.alpha = Math.min(1, activeTarget.shimmerFactor * (this.alpha * (1-a) + newAlpha * a));
|
|
|
-};
|
|
|
-
|
|
|
-function Dot(x, y) {
|
|
|
- this.x = x;
|
|
|
- this.y = y;
|
|
|
-}
|
|
|
-
|
|
|
-Dot.prototype.draw = function() {
|
|
|
- ctx.fillStyle = 'gray';
|
|
|
- var adjPosition = translatePoints(this);
|
|
|
- ctx.fillRect(adjPosition.x, adjPosition.y, DOT_SIZE, DOT_SIZE);
|
|
|
-};
|
|
|
|
|
|
-Dot.prototype.onUpdate = function() {
|
|
|
- if(this.y > canvas.height + DOT_DISTANCE * 2) {
|
|
|
- this.y -= canvas.height + DOT_DISTANCE * 4;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-function Target(beat) {
|
|
|
- this.reset();
|
|
|
- this.beat = beat;
|
|
|
- this.alpha = 0;
|
|
|
- if(points < 4) {
|
|
|
- this.alpha = ease(1-points/4);
|
|
|
+ function drawLeafV(point, h, w) {
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.moveTo(point.x, point.y);
|
|
|
+ ctx.quadraticCurveTo(point.x + w, point.y + h/2, point.x, point.y + h);
|
|
|
+ ctx.quadraticCurveTo(point.x - w, point.y + h/2, point.x, point.y);
|
|
|
+ ctx.fill();
|
|
|
}
|
|
|
- this.rippleCounter = 0;
|
|
|
-}
|
|
|
-
|
|
|
-Target.prototype.reset = function() {
|
|
|
- this.y = -20;
|
|
|
- this.x = Math.random()*LEVEL_SIZE;
|
|
|
-};
|
|
|
|
|
|
-Target.prototype.color = function(p) {
|
|
|
- return color(0, 255, 0, p*this.alpha);
|
|
|
-};
|
|
|
+ function drawLeafH(point, w, h) {
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.moveTo(point.x, point.y);
|
|
|
+ ctx.quadraticCurveTo(point.x + w/2, point.y + h, point.x + w, point.y);
|
|
|
+ ctx.quadraticCurveTo(point.x + w/2, point.y - h, point.x, point.y);
|
|
|
+ ctx.fill();
|
|
|
+ }
|
|
|
|
|
|
-Target.prototype.draw = function() {
|
|
|
- var adjPosition = translatePoints(this);
|
|
|
- drawCircle(adjPosition, RADIUS, 3, this.color(1));
|
|
|
- drawCircle(adjPosition, 2, 3, this.color(1));
|
|
|
+ function drawPlayer(point) {
|
|
|
+ drawCircle(point, RADIUS, 5, "#FFFFFF");
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
- var p = lerp(1, 0, ease(this.rippleCounter/RIPPLE_SIZE));
|
|
|
- drawCircle(adjPosition, RADIUS+7+this.rippleCounter, 1, this.color(p));
|
|
|
- drawCircle(adjPosition, RADIUS+4+this.rippleCounter, 1, this.color(p*0.8));
|
|
|
- drawCircle(adjPosition, RADIUS+1+this.rippleCounter, 1, this.color(p*0.5));
|
|
|
-};
|
|
|
+ function drawSpectrum() {
|
|
|
+ var barHeight = 30;
|
|
|
+ var barWidth = 6;
|
|
|
+ var barSpacing = 2;
|
|
|
+ var margin = 5;
|
|
|
+ ctx.strokeStyle = 'white';
|
|
|
+ ctx.lineWidth = 2;
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.rect(
|
|
|
+ margin - ctx.lineWidth,
|
|
|
+ canvas.height - barHeight - ctx.lineWidth - margin,
|
|
|
+ activeTarget.spectrum.length * (barWidth+barSpacing) + 2 * ctx.lineWidth - barSpacing,
|
|
|
+ barHeight + 2 * ctx.lineWidth
|
|
|
+ );
|
|
|
+ ctx.stroke();
|
|
|
+ for(var i = 0; i < activeTarget.spectrum.length; ++i) {
|
|
|
+ var height = activeTarget.spectrum[i]*20;
|
|
|
+ ctx.fillStyle = starColors[i];
|
|
|
+ ctx.fillRect(i * (barWidth + barSpacing) + margin, canvas.height - height - margin, barWidth, height);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-Target.prototype.onUpdate = function(dt, t) {
|
|
|
- this.rippleCounter += RIPPLE_SPEED * dt;
|
|
|
- if(this.rippleCounter > RIPPLE_SIZE) {
|
|
|
- this.rippleCounter = 0;
|
|
|
- }
|
|
|
-
|
|
|
- if(gotPoint) {
|
|
|
- gotPoint = false;
|
|
|
- }
|
|
|
-
|
|
|
- if(colliding(player, this)) {
|
|
|
- gotPoint = true;
|
|
|
- this.beat.setPan(0);
|
|
|
- this.beat.setVolume(100);
|
|
|
- this.shouldDelete = true;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if(this.y > canvas.height + 20) {
|
|
|
- this.reset();
|
|
|
- }
|
|
|
-
|
|
|
- var xDist = distX(this, player);
|
|
|
- var s = sign(xDist);
|
|
|
- var xDistAbs = easeOutExpo(Math.abs(xDist), 0, 100, LEVEL_SIZE/2);
|
|
|
-
|
|
|
- var yDist = this.y - player.y;
|
|
|
- var angle = 0;
|
|
|
- if(yDist != 0) {
|
|
|
- angle = easeOutExpo(Math.abs(Math.atan2(Math.abs(yDist), xDist) - Math.PI/2), 0, 100, Math.PI);
|
|
|
- }
|
|
|
- else {
|
|
|
- angle = s * 100;
|
|
|
- }
|
|
|
- this.beat.setPan(Math.max(xDistAbs, angle) * s);
|
|
|
-
|
|
|
- var rDist = xDist*xDist + yDist*yDist;
|
|
|
- if(rDist >= 250000) {
|
|
|
- rDist = 250000;
|
|
|
- }
|
|
|
- rDist = 250000 - rDist;
|
|
|
- rDist /= 2500;
|
|
|
- this.beat.setVolume(rDist);
|
|
|
-
|
|
|
- this.shimmerFactor = easeOutExpo(Math.abs(xDist), 1, -1, LEVEL_SIZE/2) * rDist / 100;
|
|
|
- if(isNaN(this.shimmerFactor) || this.shimmerFactor < 0) {
|
|
|
- this.shimmerFactor = 0;
|
|
|
- }
|
|
|
-
|
|
|
- this.spectrum = this.beat.getSpectrum(t*1000);
|
|
|
-};
|
|
|
+ function distX(a, b) {
|
|
|
+ var dx = a.x - b.x;
|
|
|
+ if(dx > LEVEL_SIZE / 2) dx -= LEVEL_SIZE;
|
|
|
+ if(dx < -LEVEL_SIZE / 2) dx += LEVEL_SIZE;
|
|
|
+ return dx;
|
|
|
+ }
|
|
|
|
|
|
-var player = {
|
|
|
- x: 0,
|
|
|
- y: canvas.height - 20,
|
|
|
- dx: PLAYER_SPEED
|
|
|
-};
|
|
|
+ function distSq(a, b) {
|
|
|
+ var c = distX(a, b);
|
|
|
+ var d = a.y - b.y;
|
|
|
+ return c * c + d * d;
|
|
|
+ }
|
|
|
|
|
|
-var meter = new Meter();
|
|
|
+ function colliding(a, b) {
|
|
|
+ return distSq(a, b) <= 4 * RADIUS * RADIUS;
|
|
|
+ }
|
|
|
|
|
|
-var points;
|
|
|
-var entities;
|
|
|
-var activeTarget;
|
|
|
+
|
|
|
+ function Meter() {
|
|
|
+ this.offset = 10;
|
|
|
+ this.amp = 0;
|
|
|
+ this.percentage = 0;
|
|
|
+ this.direction = METER_SPEED;
|
|
|
+ }
|
|
|
|
|
|
-var respawnTarget = function() {
|
|
|
- activeTarget = new Target();
|
|
|
- entities.push(activeTarget);
|
|
|
-};
|
|
|
+ Meter.prototype.draw = function() {
|
|
|
+ var left = (canvas.width - METER_WIDTH) / 2;
|
|
|
+ var vmid = this.offset + METER_HEIGHT / 2;
|
|
|
+ var third = METER_WIDTH / 3;
|
|
|
+ var peak = METER_HEIGHT / 2;
|
|
|
+
|
|
|
+ ctx.fillStyle = 'black';
|
|
|
+ ctx.rect(left, this.offset, METER_WIDTH, METER_HEIGHT);
|
|
|
+ ctx.fill();
|
|
|
+
|
|
|
+ var cpUp = lerp(vmid, vmid + peak * this.amp, this.percentage);
|
|
|
+ var cpDown = lerp(vmid, vmid - peak * this.amp, this.percentage);
|
|
|
+
|
|
|
+ ctx.lineWidth = 2;
|
|
|
+ ctx.strokeStyle = 'red';
|
|
|
+ ctx.beginPath();
|
|
|
+ var pos = left;
|
|
|
+ ctx.moveTo(left, vmid);
|
|
|
+ ctx.quadraticCurveTo(pos+third/2, cpUp, pos+third, vmid);
|
|
|
+ pos += third;
|
|
|
+ ctx.quadraticCurveTo(pos+third/2, cpDown, pos+third, vmid);
|
|
|
+ pos += third;
|
|
|
+ ctx.quadraticCurveTo(pos+third/2, cpUp, pos+third, vmid);
|
|
|
+ ctx.stroke();
|
|
|
+
|
|
|
+ ctx.lineWidth = 3;
|
|
|
+ ctx.strokeStyle = 'white';
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.rect(left, this.offset, METER_WIDTH, METER_HEIGHT);
|
|
|
+ ctx.stroke();
|
|
|
+ };
|
|
|
+
|
|
|
+ Meter.prototype.onUpdate = function(dt) {
|
|
|
+ if(this.percentage > 1) {
|
|
|
+ this.direction = -METER_SPEED;
|
|
|
+ }
|
|
|
+ if(this.percentage < -1) {
|
|
|
+ this.direction = METER_SPEED;
|
|
|
+ }
|
|
|
+ this.percentage += this.direction * dt;
|
|
|
+ this.amp = 0.5 + lerp(0, 1, activeTarget.shimmerFactor);
|
|
|
+ };
|
|
|
+
|
|
|
+ function Star(x, y) {
|
|
|
+ this.x = x;
|
|
|
+ this.y = y;
|
|
|
+ this.alpha = 0;
|
|
|
+ this.randomize();
|
|
|
+ }
|
|
|
|
|
|
-var reset = function() {
|
|
|
- points = 0;
|
|
|
- entities = [];
|
|
|
-
|
|
|
- for(var j = 0; j < canvas.height / DOT_DISTANCE + 4; ++j) {
|
|
|
- for(var i = 0; i < LEVEL_SIZE / DOT_DISTANCE; ++i) {
|
|
|
- var x = i * DOT_DISTANCE;
|
|
|
- var y = (j-4) * DOT_DISTANCE;
|
|
|
- if(j % 2 == 0 && i % 2 == 0) {
|
|
|
- entities.push(new Dot(x, y));
|
|
|
- }
|
|
|
-
|
|
|
- if(j % 4 == 1) {
|
|
|
- if(i % 4 == 0) {
|
|
|
- entities.push(new Star(x, y));
|
|
|
- }
|
|
|
- else {
|
|
|
- entities.push(new Dot(x, y));
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if(j % 4 == 3) {
|
|
|
- if(i % 4 == 2) {
|
|
|
- entities.push(new Star(x, y));
|
|
|
- }
|
|
|
- else {
|
|
|
- entities.push(new Dot(x, y));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- respawnTarget();
|
|
|
-};
|
|
|
+ Star.prototype.randomize = function() {
|
|
|
+ this.type = Math.floor(Math.random()*starColors.length);
|
|
|
+ this.color = starColors[this.type];
|
|
|
+ };
|
|
|
+
|
|
|
+ Star.prototype.draw = function() {
|
|
|
+ ctx.fillStyle = this.color;
|
|
|
+ ctx.globalAlpha = this.alpha;
|
|
|
+ var adjPosition = translatePoints(this);
|
|
|
+ ctx.fillRect(adjPosition.x, adjPosition.y, DOT_SIZE, DOT_SIZE);
|
|
|
+
|
|
|
+ var top = {x: adjPosition.x + DOT_SIZE/2, y: adjPosition.y - DOT_SIZE/2 };
|
|
|
+ var bottom = {x: adjPosition.x + DOT_SIZE/2, y: adjPosition.y + DOT_SIZE/2*3};
|
|
|
+ var left = {x: adjPosition.x - DOT_SIZE/2, y: adjPosition.y + DOT_SIZE/2 };
|
|
|
+ var right = {x: adjPosition.x + DOT_SIZE/2*3, y: adjPosition.y + DOT_SIZE/2 };
|
|
|
+
|
|
|
+ drawLeafH(left, -LEAF_SIZE, LEAF_SIZE/2);
|
|
|
+ drawLeafH(right, LEAF_SIZE, LEAF_SIZE/2);
|
|
|
+ drawLeafV(top, -LEAF_SIZE, LEAF_SIZE/2);
|
|
|
+ drawLeafV(bottom, LEAF_SIZE, LEAF_SIZE/2);
|
|
|
+ ctx.globalAlpha = 1;
|
|
|
+ };
|
|
|
+
|
|
|
+ Star.prototype.onUpdate = function() {
|
|
|
+ if(gotPoint) {
|
|
|
+ this.randomize();
|
|
|
+ }
|
|
|
+ if(this.y > canvas.height + DOT_DISTANCE * 2) {
|
|
|
+ this.y -= canvas.height + DOT_DISTANCE * 4;
|
|
|
+ }
|
|
|
+ var newAlpha = 1.5 * activeTarget.spectrum[this.type];
|
|
|
+ var a = 0.001;
|
|
|
+ if(newAlpha > this.alpha) {
|
|
|
+ a = 0.9;
|
|
|
+ }
|
|
|
+ this.alpha = Math.min(1, activeTarget.shimmerFactor * (this.alpha * (1-a) + newAlpha * a));
|
|
|
+ };
|
|
|
+
|
|
|
+ function Dot(x, y) {
|
|
|
+ this.x = x;
|
|
|
+ this.y = y;
|
|
|
+ }
|
|
|
|
|
|
-reset();
|
|
|
+ Dot.prototype.draw = function() {
|
|
|
+ ctx.fillStyle = 'gray';
|
|
|
+ var adjPosition = translatePoints(this);
|
|
|
+ ctx.fillRect(adjPosition.x, adjPosition.y, DOT_SIZE, DOT_SIZE);
|
|
|
+ };
|
|
|
+
|
|
|
+ Dot.prototype.onUpdate = function() {
|
|
|
+ if(this.y > canvas.height + DOT_DISTANCE * 2) {
|
|
|
+ this.y -= canvas.height + DOT_DISTANCE * 4;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ function Target(beat) {
|
|
|
+ this.beat = beat;
|
|
|
+ this.alpha = 0;
|
|
|
+ if(points < 4) {
|
|
|
+ this.alpha = ease(1-points/4);
|
|
|
+ }
|
|
|
+ this.rippleCounter = 0;
|
|
|
+ this.reset();
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
-var update = function(dt) {
|
|
|
- if(paused) return;
|
|
|
- var repeat = false;
|
|
|
- beatTime += dt;
|
|
|
- while(beatTime > 4) {
|
|
|
- repeat = true;
|
|
|
- beatTime -= 4;
|
|
|
- }
|
|
|
+ Target.prototype.reset = function() {
|
|
|
+ this.y = -20;
|
|
|
+ this.x = Math.random()*LEVEL_SIZE;
|
|
|
+ };
|
|
|
+
|
|
|
+ Target.prototype.color = function(p) {
|
|
|
+ return color(0, 255, 0, p*this.alpha);
|
|
|
+ };
|
|
|
+
|
|
|
+ Target.prototype.draw = function() {
|
|
|
+ var adjPosition = translatePoints(this);
|
|
|
+ drawCircle(adjPosition, RADIUS, 3, this.color(1));
|
|
|
+ drawCircle(adjPosition, 2, 3, this.color(1));
|
|
|
+
|
|
|
+
|
|
|
+ var p = lerp(1, 0, ease(this.rippleCounter/RIPPLE_SIZE));
|
|
|
+ drawCircle(adjPosition, RADIUS+7+this.rippleCounter, 1, this.color(p));
|
|
|
+ drawCircle(adjPosition, RADIUS+4+this.rippleCounter, 1, this.color(p*0.8));
|
|
|
+ drawCircle(adjPosition, RADIUS+1+this.rippleCounter, 1, this.color(p*0.5));
|
|
|
+ };
|
|
|
+
|
|
|
+ Target.prototype.onUpdate = function(dt, t) {
|
|
|
+ this.rippleCounter += RIPPLE_SPEED * dt;
|
|
|
+ if(this.rippleCounter > RIPPLE_SIZE) {
|
|
|
+ this.rippleCounter = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(gotPoint) {
|
|
|
+ gotPoint = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(colliding(player, this)) {
|
|
|
+ gotPoint = true;
|
|
|
+ this.beat.sound.setPan(0);
|
|
|
+ this.beat.sound.setVolume(100);
|
|
|
+ this.shouldDelete = true;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(this.y > canvas.height + 20) {
|
|
|
+ this.reset();
|
|
|
+ }
|
|
|
+
|
|
|
+ var xDist = distX(this, player);
|
|
|
+ var s = sign(xDist);
|
|
|
+ var xDistAbs = easeOutExpo(Math.abs(xDist), 0, 100, LEVEL_SIZE/2);
|
|
|
+
|
|
|
+ var yDist = this.y - player.y;
|
|
|
+ var angle = 0;
|
|
|
+ if(yDist != 0) {
|
|
|
+ angle = easeOutExpo(Math.abs(Math.atan2(Math.abs(yDist), xDist) - Math.PI/2), 0, 100, Math.PI);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ angle = s * 100;
|
|
|
+ }
|
|
|
+ this.beat.sound.setPan(Math.max(xDistAbs, angle) * s);
|
|
|
+
|
|
|
+ var rDist = xDist*xDist + yDist*yDist;
|
|
|
+ if(rDist >= 250000) {
|
|
|
+ rDist = 250000;
|
|
|
+ }
|
|
|
+ rDist = 250000 - rDist;
|
|
|
+ rDist /= 2500;
|
|
|
+ this.beat.sound.setVolume(rDist);
|
|
|
+
|
|
|
+ this.shimmerFactor = easeOutExpo(Math.abs(xDist), 1, -1, LEVEL_SIZE/2) * rDist / 100;
|
|
|
+ if(isNaN(this.shimmerFactor) || this.shimmerFactor < 0) {
|
|
|
+ this.shimmerFactor = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.spectrum = this.beat.sound.getSpectrum(t%this.beat.info.duration);
|
|
|
+ };
|
|
|
+
|
|
|
+ var player = {
|
|
|
+ x: 0,
|
|
|
+ y: canvas.height - 20,
|
|
|
+ dx: PLAYER_SPEED
|
|
|
+ };
|
|
|
+
|
|
|
+ var meter = new Meter();
|
|
|
+
|
|
|
+ var points;
|
|
|
+ var entities;
|
|
|
+ var activeTarget;
|
|
|
+
|
|
|
+ var reset = function() {
|
|
|
+ points = 0;
|
|
|
+ entities = [];
|
|
|
+
|
|
|
+ for(var j = 0; j < canvas.height / DOT_DISTANCE + 4; ++j) {
|
|
|
+ for(var i = 0; i < LEVEL_SIZE / DOT_DISTANCE; ++i) {
|
|
|
+ var x = i * DOT_DISTANCE;
|
|
|
+ var y = (j-4) * DOT_DISTANCE;
|
|
|
+ if(j % 2 == 0 && i % 2 == 0) {
|
|
|
+ entities.push(new Dot(x, y));
|
|
|
+ }
|
|
|
+
|
|
|
+ if(j % 4 == 1) {
|
|
|
+ if(i % 4 == 0) {
|
|
|
+ entities.push(new Star(x, y));
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ entities.push(new Dot(x, y));
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if(j % 4 == 3) {
|
|
|
+ if(i % 4 == 2) {
|
|
|
+ entities.push(new Star(x, y));
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ entities.push(new Dot(x, y));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ var update = function(delta) {
|
|
|
+ if(paused) return;
|
|
|
+ var dt = delta / 1000;
|
|
|
|
|
|
- if(repeat) {
|
|
|
currentBeats.map(function(beat) {
|
|
|
- beat.play();
|
|
|
+ if(beat.repeat) {
|
|
|
+ beat.repeat = false;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if(gameTime + delta > Math.ceil(gameTime / beat.info.duration) * beat.info.duration) {
|
|
|
+ beat.repeat = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
});
|
|
|
- }
|
|
|
-
|
|
|
- if(37 in keysDown) {
|
|
|
- player.x -= player.dx * dt;
|
|
|
- }
|
|
|
- if(39 in keysDown) {
|
|
|
- player.x += player.dx * dt;
|
|
|
- }
|
|
|
- player.x = (player.x + LEVEL_SIZE) % LEVEL_SIZE;
|
|
|
-
|
|
|
- for(var i = entities.length - 1; i >= 0; --i) {
|
|
|
- var entity = entities[i];
|
|
|
- entity.y += STAGE_SPEED * dt;
|
|
|
- entity.onUpdate(dt, beatTime);
|
|
|
- if(entity.shouldDelete) {
|
|
|
- entities.splice(i, 1);
|
|
|
- }
|
|
|
- }
|
|
|
- meter.onUpdate(dt);
|
|
|
-
|
|
|
- if(gotPoint) {
|
|
|
- ++points;
|
|
|
- soundManager.play('get');
|
|
|
- if(beats.length > 0) {
|
|
|
- respawnTarget();
|
|
|
- switchBeat(points % beats.length);
|
|
|
- }
|
|
|
- }
|
|
|
-};
|
|
|
|
|
|
-
|
|
|
-var translatePoints = function(point) {
|
|
|
- var x = point.x - player.x + canvas.width/2;
|
|
|
- if(x < -ALLOWANCE) x += LEVEL_SIZE;
|
|
|
- if(x > LEVEL_SIZE - ALLOWANCE) x -= LEVEL_SIZE;
|
|
|
- return {x:x, y:point.y};
|
|
|
-};
|
|
|
-
|
|
|
-var render = function() {
|
|
|
- ctx.fillStyle = "black";
|
|
|
- ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
|
- entities.map(function(elem) {
|
|
|
- elem.draw();
|
|
|
- });
|
|
|
- drawPlayer(translatePoints(player));
|
|
|
- meter.draw();
|
|
|
- ctx.fillStyle = "white";
|
|
|
- ctx.fillText(points+"", 5, 15);
|
|
|
-
|
|
|
- if(debug) {
|
|
|
- drawSpectrum();
|
|
|
- }
|
|
|
-
|
|
|
- if(paused) {
|
|
|
- ctx.textAlign = 'center';
|
|
|
- ctx.fillText("Paused (P to unpause)", canvas.width / 2, canvas.height / 2);
|
|
|
- ctx.textAlign = 'start';
|
|
|
- }
|
|
|
-};
|
|
|
|
|
|
+ currentBeats.map(function(beat) {
|
|
|
+ if(beat.repeat) beat.sound.play();
|
|
|
+ });
|
|
|
|
|
|
-var main = function() {
|
|
|
- var now = Date.now();
|
|
|
- var delta = (now - then);
|
|
|
- delta /= 1000;
|
|
|
- update(delta);
|
|
|
- render();
|
|
|
- then = now;
|
|
|
+ if(37 in keysDown) {
|
|
|
+ player.x -= player.dx * dt;
|
|
|
+ }
|
|
|
+ if(39 in keysDown) {
|
|
|
+ player.x += player.dx * dt;
|
|
|
+ }
|
|
|
+ player.x = (player.x + LEVEL_SIZE) % LEVEL_SIZE;
|
|
|
+
|
|
|
+ for(var i = entities.length - 1; i >= 0; --i) {
|
|
|
+ var entity = entities[i];
|
|
|
+ entity.y += STAGE_SPEED * dt;
|
|
|
+ entity.onUpdate(dt, gameTime);
|
|
|
+ if(entity.shouldDelete) {
|
|
|
+ entities.splice(i, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ meter.onUpdate(dt);
|
|
|
+
|
|
|
+ if(gotPoint) {
|
|
|
+ ++points;
|
|
|
+ soundManager.play('get');
|
|
|
+ if(beats.length > 0) {
|
|
|
+ switchBeat(points % beats.length);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ gameTime += delta;
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ var translatePoints = function(point) {
|
|
|
+ var x = point.x - player.x + canvas.width/2;
|
|
|
+ if(x < -ALLOWANCE) x += LEVEL_SIZE;
|
|
|
+ if(x > LEVEL_SIZE - ALLOWANCE) x -= LEVEL_SIZE;
|
|
|
+ return {x:x, y:point.y};
|
|
|
+ };
|
|
|
+
|
|
|
+ var render = function() {
|
|
|
+ ctx.fillStyle = "black";
|
|
|
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
|
+ entities.map(function(elem) {
|
|
|
+ elem.draw();
|
|
|
+ });
|
|
|
+ drawPlayer(translatePoints(player));
|
|
|
+ meter.draw();
|
|
|
+ ctx.fillStyle = "white";
|
|
|
+ ctx.fillText(points+"", 5, 15);
|
|
|
+
|
|
|
+ if(debug) {
|
|
|
+ drawSpectrum();
|
|
|
+ }
|
|
|
+
|
|
|
+ if(paused) {
|
|
|
+ ctx.fillStyle = 'white';
|
|
|
+ ctx.textAlign = 'center';
|
|
|
+ ctx.fillText("Paused (P to unpause)", canvas.width / 2, canvas.height / 2);
|
|
|
+ ctx.textAlign = 'start';
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ var then;
|
|
|
+
|
|
|
+ var main = function() {
|
|
|
+ var now = Date.now();
|
|
|
+ var delta = (now - then);
|
|
|
+ update(delta);
|
|
|
+ render();
|
|
|
+ then = now;
|
|
|
+ };
|
|
|
+
|
|
|
+ var start = function() {
|
|
|
+ reset();
|
|
|
+ switchBeat(0);
|
|
|
+ then = Date.now();
|
|
|
+ setInterval(main, 10);
|
|
|
+ };
|
|
|
+
|
|
|
+ var pause = function() {
|
|
|
+ paused = !paused;
|
|
|
+ if(paused) {
|
|
|
+ currentBeats.map(function(beat) {beat.sound.pause()});
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ currentBeats.map(function(beat) {beat.sound.resume()});
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ ctx.textAlign = 'center';
|
|
|
+ ctx.fillText("Loading...", canvas.width / 2, canvas.height / 2);
|
|
|
+ ctx.textAlign = 'start';
|
|
|
+
|
|
|
+ Q.all([soundPromise]).done(function() {
|
|
|
+ start();
|
|
|
+ });
|
|
|
};
|
|
|
|
|
|
-var then;
|
|
|
+var canvas = document.getElementById('game');
|
|
|
|
|
|
-var start = function() {
|
|
|
- then = Date.now();
|
|
|
- setInterval(main, 10);
|
|
|
-};
|
|
|
+var beats = [
|
|
|
+ {url: 'sound/b1.mp3', duration: 4000},
|
|
|
+ {url: 'sound/b2.mp3', duration: 4000},
|
|
|
+ {url: 'sound/b3.mp3', duration: 4000},
|
|
|
+ {url: 'sound/b4.mp3', duration: 4000},
|
|
|
+ {url: 'sound/b5.mp3', duration: 4000}
|
|
|
+];
|
|
|
|
|
|
-var pause = function() {
|
|
|
- paused = !paused;
|
|
|
- if(paused) {
|
|
|
- currentBeats.map(function(beat) {beat.pause()});
|
|
|
- }
|
|
|
- else {
|
|
|
- currentBeats.map(function(beat) {beat.resume()});
|
|
|
+var soundDeferred = Q.defer();
|
|
|
+var pSoundManager = soundDeferred.promise;
|
|
|
+soundManager.setup({
|
|
|
+ url: 'swf/',
|
|
|
+ flashVersion: 9,
|
|
|
+ onready: function() {
|
|
|
+ soundDeferred.resolve(this);
|
|
|
}
|
|
|
-};
|
|
|
+});
|
|
|
|
|
|
-ctx.textAlign = 'center';
|
|
|
-ctx.fillText("Loading...", canvas.width / 2, canvas.height / 2);
|
|
|
-ctx.textAlign = 'start';
|
|
|
+SoundSafari(canvas, beats, pSoundManager);
|
|
|
|
|
|
-Q.all([soundPromise]).done(function() {
|
|
|
- switchBeat(0);
|
|
|
- start();
|
|
|
-});
|