wyrian/js/libs/soundmanager/demo/christmas-lights/christmaslights.js
Guillaume DE LA RUE 28e7b63568 Version 0.2b :
- Intro Screen
- Share buttons (Twitter/Facebook)
- SoundManager
- Add audio files
- Some CleanUp
2011-02-13 13:28:40 +01:00

645 lines
20 KiB
JavaScript

// Christmas Light Smashfest
// Adapted from XLSF 2007 as originally used on http://schillmania.com/?theme=2007&christmas=1
var Y = {
// shortcuts
A: YAHOO.util.Anim,
D: YAHOO.util.Dom,
E: YAHOO.util.Event,
UE: YAHOO.util.Easing,
CA: YAHOO.util.ColorAnim,
BG: YAHOO.util.BgPosAnim
}
function XLSF(oTarget) {
var writeDebug = soundManager._wD;
writeDebug('XLSF()');
var IS_MOON_COMPUTER = false;
var isIE = navigator.userAgent.match(/msie/i);
var isTouchDevice = navigator.userAgent.match(/ipad|ipod|iphone/i);
var self = this;
var xlsf = self;
var useAngle = window.location.href.match(/angle/i);
var useFollow = window.location.toString().match(/follow/i);
var classBase = 'xlsf-light'+(useAngle?' xlsf-angled':'');
var animDuration = 1;
var lastMouseX = 0;
var lastMouseY = 0;
var mmhTimer = null;
var activeLights = [];
var testDiv = document.createElement('div');
var transforms = {
ie: (typeof testDiv.style['-ms-transform'] !== 'undefined' ? '-ms-transform' : null),
moz: (typeof testDiv.style.MozTransform !== 'undefined' ? 'MozTransform' : null),
opera: (typeof testDiv.style['OTransform'] !== 'undefined' ? 'OTransform' : null),
webkit: (typeof testDiv.style.webkitTransform !== 'undefined' ? 'webkitTransform' : null),
prop: null
}
transforms.prop = (transforms.moz || transforms.webkit || transforms.ie || transforms.opera);
this.oFrag = document.createDocumentFragment();
this.oExplosionTarget = document.getElementById('explosion-box');
this.oTarget = (oTarget?oTarget:document.documentElement);
this.oExplosionBox = document.createElement('div');
this.oExplosionBox.className = 'xlsf-fragment-box';
this.oExplosionFrag = document.createElement('div');
this.oExplosionFrag.className = 'xlsf-fragment';
this.lights = [];
this.lightClasses = {
pico: 32,
tiny: 50,
small: 64,
medium: 72,
large: 96
}
this.lightClass = 'tiny'; // kind of light to show (32px to 96px square)
if (window.location.href.match(/size=/i)) {
this.lightClass = window.location.href.substr(window.location.href.indexOf('size=')+5);
if (this.lightClass.indexOf('#') !== -1) {
this.lightClass = this.lightClass.substr(0,this.lightClass.indexOf('#'));
}
}
this.lightXY = this.lightClasses[this.lightClass]; // shortcut to w/h
function rnd(n) {
return parseInt(Math.random()*n);
}
function plusMinus(n) {
return (parseInt(rnd(2),10)===1?n*-1:n);
}
this.lightGroups = {
left: [],
top: [],
right: [],
bottom: []
}
this.lightSmashCounter = 0;
this.lightIndex = 0;
this.lightInterval = 250;
this.timer = null;
this.bgBaseX = 0;
this.bgBaseY = 0;
this.soundIDs = 0;
this.soundPan = {
panValue: 75,
left: 0,
mid: 481,
right: 962
}
// this.beavis = null;
this.cover = document.createElement('div');
this.cover.className = 'xlsf-cover';
document.documentElement.appendChild(this.cover);
this.initSounds = function() {
if (!soundManager.supported()) {
return false;
}
for (var i=0; i<6; i++) {
soundManager.createSound({
id: 'smash'+i,
url: 'sound/glass'+i+'.mp3',
autoLoad: true,
multiShot: true,
volume:50
});
}
self.initSounds = function() {} // safety net
}
this.appendLights = function() {
writeDebug('xlsf.appendLights()');
self.oTarget.appendChild(self.oFrag);
// self.oFrag = document.createDocumentFragment();
}
function ExplosionFragment(nType,sClass,x,y,vX,vY) {
var self = this;
this.o = xlsf.oExplosionFrag.cloneNode(true);
this.nType = nType;
this.sClass = sClass;
this.x = x;
this.y = y;
this.w = 50;
this.h = 50;
this.bgBaseX = 0;
this.bgBaseY = this.h*this.nType;
this.vX = vX*(1.5+Math.random());
this.vY = vY*(1.5+Math.random());
this.oA = null;
this.oA2 = null;
this.burstPhase = 1; // starting background offset point
this.burstPhases = 4; // 1+offset (ignore large size)
this.o.style.backgroundPosition = ((this.w*-this.burstPhase)+'px '+(this.h*-nType)+'px');
// boundary checks
if (self.sClass == 'left') {
this.vX = Math.abs(this.vX);
} else if (self.sClass == 'right') {
this.vX = Math.abs(this.vX)*-1;
}
this.burstTween = function() {
// determine frame to show
var phase = 1+Math.floor((this.currentFrame/this.totalFrames)*self.burstPhases);
if (phase != self.burstPhase) {
self.burstPhase = phase;
self.o.style.backgroundPosition = ((self.w*-self.burstPhase)+'px '+(self.h*-nType)+'px');
}
}
this.burst = function() {
self.oA = new Y.A(self.o,{marginLeft:{to:(self.vX*(5+Math.random()*10))},marginTop:{to:(self.vY*(5+Math.random()*10))}},animDuration*0.75+(0.5*Math.random()),Y.UE.easeOutStrong);
self.oA.onTween.subscribe(self.burstTween);
// self.oA.onComplete.subscribe(self.hide);
self.oA.animate();
}
this.hide = function() {
if (!isIE) self.o.style.opacity = 0;
}
this.reset = function() {
self.o.style.left = '0px';
self.o.style.top = '0px';
self.o.style.marginLeft = '0px';
self.o.style.marginTop = '0px';
if (!isIE) self.o.style.opacity = 1;
}
this.animate = function() {
self.reset();
self.burst();
}
}
function Explosion(nType,sClass,x,y) {
var oParent = this;
var self = this;
this.o = null;
this.nType = nType;
this.sClass = sClass;
this.x = x;
this.y = y;
this.boxVX = 0;
this.boxVY = 0;
this.o = xlsf.oExplosionBox.cloneNode(true);
this.o.style.left = x+'px';
this.o.style.top = y+'px';
// this.oFrag = document.createDocumentFragment();
this.fragments = [];
var mX = x;
var mY = y;
var type = typeMap[nType+sClass];
var scale = 7.5
var shift = 2;
this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,-rnd(scale),-rnd(scale)));
this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,plusMinus(rnd(shift)),-rnd(scale)));
this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,rnd(scale),-rnd(scale)));
this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,-rnd(scale),plusMinus(rnd(shift))));
this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,plusMinus(rnd(shift)),plusMinus(rnd(shift))));
this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,rnd(scale),plusMinus(rnd(shift))));
this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,rnd(scale),-rnd(scale)));
this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,rnd(scale),plusMinus(rnd(shift))));
this.fragments.push(new ExplosionFragment(type,sClass,mX,mY,rnd(scale),rnd(scale)));
this.init = function() {
for (var i=self.fragments.length; i--;) {
self.o.appendChild(self.fragments[i].o);
}
if (!IS_MOON_COMPUTER) {
// faster rendering, particles get cropped
xlsf.oExplosionTarget.appendChild(self.o);
} else {
// slower rendering, can overlay body
xlsf.oExplosionTarget.appendChild(self.o);
}
}
this.reset = function() {
// clean-up
// self.o.parentNode.removeChild(self.o);
self.o.style.display = 'none';
self.o.style.marginLeft = '0px';
self.o.style.marginTop = '0px';
self.o.style.left = self.x+'px';
self.o.style.top = self.y+'px';
if (!isIE) self.o.style.opacity = 1;
for (var i=self.fragments.length; i--;) {
self.fragments[i].reset();
}
}
this.trigger = function(boxVX,boxVY) {
self.o.style.display = 'block';
self.boxVX = boxVX;
self.boxVY = boxVY;
// boundary checks
if (self.sClass == 'right') {
self.boxVX = Math.abs(self.boxVX)*-1;
} else if (self.sClass == 'left') {
self.boxVX = Math.abs(self.boxVX);
}
for (var i=self.fragments.length; i--;) {
self.fragments[i].animate();
}
if (!isIE && (IS_MOON_COMPUTER)) {
var oAExplode = new Y.A(self.o,{marginLeft:{to:100*self.boxVX},marginTop:{to:150*self.boxVY},opacity:{to:0.01}},animDuration,Y.UE.easeInStrong);
} else {
// even IE 7 sucks w/alpha-transparent PNG + CSS opacity. Boourns.
var oAExplode = new Y.A(self.o,{marginLeft:{to:100*self.boxVX},marginTop:{to:150*self.boxVY}},animDuration,Y.UE.easeInStrong);
}
oAExplode.onComplete.subscribe(self.reset);
oAExplode.animate();
// setTimeout(self.reset,animDuration*1000*1.5);
}
this.init();
}
function Light(sSizeClass,sClass,nType,x,y,row,col) {
var self = this;
this.o = document.createElement('div');
this.sClass = sClass;
this.sSizeClass = sSizeClass;
this.nType = (nType||0);
this.useY = (sClass == 'left' || sClass == 'right');
this.state = null;
this.broken = 0;
this.w = xlsf.lightClasses[sSizeClass];
this.h = xlsf.lightClasses[sSizeClass];
this.x = x;
this.y = y;
this.row = row;
this.col = col;
this.bg = 'image/bulbs-'+this.w+'x'+this.h+'-'+this.sClass+'.png';
this.o.style.width = this.w+'px';
this.o.style.height = this.h+'px';
this.o.style.background = 'url('+this.bg+') no-repeat 0px 0px';
this.bgBaseX = (self.useY?-self.w*this.nType:0);
this.bgBaseY = (!self.useY?-self.h*this.nType:0);
this.glassType = parseInt(Math.random()*6);
// this.bonusSounds = ['griffin-laugh','bblaff','bblaff2'];
// this.bonusSound = null;
this.oExplosion = null;
this.soundID = 'smash'+this.glassType;
var panValue = xlsf.soundPan.panValue; // eg. +/- 80%
this.pan = parseInt(this.x<=xlsf.soundPan.mid?-panValue+((this.x/xlsf.soundPan.mid)*panValue):(this.x-xlsf.soundPan.mid)/(xlsf.soundPan.right-xlsf.soundPan.mid)*panValue);
this.setBGPos = function(x,y) {
self.o.style.backgroundPosition = ((self.bgBaseX+x)+'px '+(self.bgBaseY+y)+'px');
}
this.setLight = function(bOn) {
if (self.broken || self.state == bOn) return false;
if (!self.w || !self.h) self.getDimensions();
self.state = bOn;
if (self.useY) {
self.setBGPos(0,-this.h*(bOn?0:1));
} else {
self.setBGPos(-this.w*(bOn?0:1),0);
}
}
this.getDimensions = function() {
self.w = self.o.offsetWidth;
self.h = self.o.offsetHeight;
self.bgBaseX = (self.useY?-self.w*self.nType:0);
self.bgBaseY = (!self.useY?-self.h*self.nType:0);
}
this.on = function() {
self.setLight(1);
}
this.off = function() {
self.setLight(0);
}
this.flickr = function() {
self.setLight(Math.random()>=0.5?1:0);
}
this.toggle = function() {
self.setLight(!self.state?1:0);
}
this.explode = function(e) {
self.oExplosion.trigger(0,1); // boooom!
}
this.smash = function(e) {
if (self.broken) return false;
self.broken = true;
if (soundManager && soundManager.supported()) {
soundManager.play(self.soundID,{pan:self.pan});
// soundManager.sounds[self.soundID].play({pan:self.pan});
// if (self.bonusSound != null) window.setTimeout(self.smashBonus,1000);
}
self.explode(e);
var rndFrame = 2; // +parseInt(Math.random()*3);
if (self.useY) {
self.setBGPos(0,self.h*-rndFrame);
} else {
self.setBGPos(self.w*-rndFrame,0);
}
if (!useFollow && !useAngle && transforms.prop) {
self.o.style[transforms.prop] = 'rotate('+Math.random()*plusMinus(20)+'deg)';
}
xlsf.lightSmashCounter++;
for (var i=activeLights.length; i--;) {
// find this in the active array, and take it out
if (activeLights[i] === self) {
activeLights.splice(i,1);
break;
}
}
// xlsf.doNukeCheck();
// window.setTimeout(self.reset,3000); // respawn
}
this.smashBonus = function() {
// soundManager.play(self.bonusSounds[self.bonusSound],urlBase+'sound/'+self.bonusSounds[self.bonusSound]+'.mp3');
}
this.reset = function() {
if (!self.broken) return false;
self.broken = false;
self.state = null;
xlsf.lightSmashCounter--;
// self.oExplosion.reset(); // may not be necessary
self.flickr();
}
this.init = function() {
self.o.className = classBase+' '+this.sizeClass+' '+this.sClass;
self.o.style.left = self.x+'px';
self.o.style.top = self.y+'px';
self.o.style.width = self.w+'px';
self.o.style.height = self.h+'px';
self.flickr();
xlsf.oFrag.appendChild(self.o);
self.oExplosion = new Explosion(self.nType,self.sClass,self.x,self.y);
}
this.init();
} // Light()
this.createLight = function(sClass,nType,x,y,row,col) {
var oLight = new Light(self.lightClass,sClass,nType,x,y,row,col);
activeLights.push(oLight);
self.lightGroups[sClass].push(oLight);
self.lights.push(oLight);
return oLight;
}
this.rotateLights = function() {
self.lights[self.lightIndex==self.lights.length?self.lights.length-1:self.lightIndex].off();
self.lightIndex++;
if (self.lightIndex == self.lights.length) {
self.lightIndex = 0;
}
self.lights[self.lightIndex].on();
}
this.randomLights = function() {
self.lights[parseInt(Math.random()*self.lights.length)].toggle();
}
this.destroyLights = function() {
// reset counter
self.lightSmashCounter = 0;
self.startSequence(Math.random()>0.75?self.destroyLight:self.destroyRandom,33);
}
this.destroyRandom = function() {
for (var i=2; i--;) {
if (activeLights.length) {
activeLights[parseInt(Math.random()*activeLights.length)].smash();
}
}
}
this.destroyLight = function() {
var groupSize = 2; // # to smash at a time
if (self.lightSmashCounter<self.lights.length) {
var limit = Math.min(self.lightSmashCounter+groupSize,self.lights.length);
var reverseLimit = Math.max(0, self.lights.length-self.lightSmashCounter-groupSize);
for (var i=self.lightSmashCounter; i<limit; i++) {
if (self.lights[self.lightSmashCounter]) {
self.lights[self.lightSmashCounter].smash();
}
self.lights[self.lights.length-self.lightSmashCounter].smash();
}
} else {
self.stopSequence();
}
}
this.uberSmash = function() {
// make everything explode - including your CPU.
self.stopSequence();
var ebCN = Y.D.getElementsByClassName;
/*
window.setTimeout(function(){self.smashGroup(self.lightGroups.left)},500);
window.setTimeout(function(){self.smashGroup(self.lightGroups.right)},2000);
window.setTimeout(function(){self.smashGroup(self.lightGroups.bottom)},4000);
window.setTimeout(function(){self.smashGroup(self.lightGroups.top)},6000);
*/
window.setTimeout(function(){self.smashGroup(self.lightGroups.bottom)},500);
window.setTimeout(function(){self.smashGroup(self.lightGroups.top)},3500);
}
this.smashGroup = function(oGroup) {
for (var i=oGroup.length; i--;) {
oGroup[i].smash();
}
}
this.startSequence = function(fSequence,nInterval) {
if (self.timer) self.stopSequence();
self.timer = window.setInterval(fSequence,(typeof nInterval != 'undefined'?nInterval:self.lightInterval));
}
this.stopSequence = function() {
if (self.timer) {
window.clearInterval(self.timer);
self.timer = null;
}
}
var typeMaps = {
'tiny': {
'0bottom': 0,
'0top': 3,
'1bottom': 1,
'1top': 2,
'2bottom': 2,
'2top': 1,
'3bottom': 3,
'3top': 0
},
'other': {
'0bottom': 3,
'0top': 3,
'1bottom': 2,
'1top': 2,
'2bottom': 1,
'2top': 1,
'3bottom': 0,
'3top': 0
}
}
var typeMap = typeMaps[(this.lightClass === 'tiny' ? 'tiny' : 'other')];
var i=0;
/*
for (i=0; i<6; i++) {
this.createLight('left',parseInt(Math.random()*4),-2,50+i*(self.lightXY*0.7));
this.createLight('right',parseInt(Math.random()*4),962,50+i*(self.lightXY*0.7));
}
for (i=0; i<27; i++) {
this.createLight('top',parseInt(Math.random()*4),20+i*(self.lightXY*0.7),23);
this.createLight('bottom',parseInt(Math.random()*4),20+i*(self.lightXY*0.7),253);
}
*/
var j=0;
if (window.innerWidth || window.innerHeight) {
var screenX = window.innerWidth; // -(!isIE?24:2);
var screenY = window.innerHeight;
} else {
var screenX = (document.documentElement.clientWidth||document.body.clientWidth||document.body.scrollWidth); // -(!isIE?8:0);
var screenY = (document.documentElement.clientHeight||document.body.clientHeight||document.body.scrollHeight);
}
var jMax = Math.floor((screenX)/self.lightXY);
var iMax = Math.floor((screenY-12)/self.lightXY);
for (i=0; i<iMax; i++) {
for (j=0; j<jMax; j++) {
this.createLight((i+1)%2==0?'bottom':'top',i%4,j*self.lightXY,i*self.lightXY,j,i);
}
}
/*
var bsCounter = 0;
for (i=0; i<8; i++) {
// plant a few random seeds.. er, sounds.
self.lights[parseInt(Math.random()*self.lights.length)].bonusSound = bsCounter++;
if (bsCounter>2) bsCounter = 0; // hack - loop through sounds
}
*/
this.appendLights();
function followMouseMove(e) {
if (!self.lights.length) {
return false;
}
var x = lastMouseX;
var y = lastMouseY;
var x2 = null;
var y2 = null;
var angle = 0;
var light = null;
for (var i=self.lights.length; i--;) {
light = self.lights[i];
if (light && !light.broken) {
x2 = light.x;
y2 = light.y;
angle = Math.atan2((y-y2),(x-x2))*(180/Math.PI);
if (light.col%2 === 0) {
angle += (270*180/Math.PI);
}
if (transforms.prop) {
light.o.style[transforms.prop] = 'rotate('+angle+'deg)';
}
}
}
mmhTimer = null;
}
function mouseOrTouchMove(e) {
// coordinate -> row/col check, smashy smash
var x, y, lightIndex;
if (e.targetTouches) {
if (e.targetTouches.length === 1) {
x = e.targetTouches[0].clientX;
y = e.targetTouches[0].clientY;
}
} else {
x = e.clientX;
y = e.clientY;
}
lightCol = Math.floor((x/(self.lightClasses[self.lightClass]*jMax)*jMax)),
lightRow = Math.floor((y/(self.lightClasses[self.lightClass]*iMax)*iMax))
lightIndex = (jMax*lightRow)+lightCol;
if (self.lights[lightIndex]) {
self.lights[lightIndex].smash();
}
if (useFollow) {
lastMouseX = x;
lastMouseY = y;
if (!mmhTimer) {
mmhTimer = window.setTimeout(followMouseMove, 33); // try to be nice and throttle this call, which may be expensive
}
}
}
if (isTouchDevice && self.oTarget !== document.documentElement) {
self.oTarget.addEventListener('touchstart', function(e) {
self.oTarget.addEventListener('touchmove', mouseOrTouchMove, false);
self.oTarget.addEventListener('touchend', function(e) {
self.oTarget.removeEventListener('touchMove', mouseOrTouchMove);
});
mouseOrTouchMove(e); // initial touch might be a smashy one, too
e.preventDefault();
return false;
}, false);
} else {
if (document.addEventListener) {
document.addEventListener('mousemove', mouseOrTouchMove, false);
} else if (document.attachEvent) {
document.attachEvent('onmousemove', mouseOrTouchMove);
}
}
this.startSequence(self.randomLights);
} // --- XLSF2007()
var xlsf = null;
function smashInit() {
xlsf = new XLSF(document.getElementById('lights'));
xlsf.initSounds();
document.getElementById('loading').style.display = 'none';
}
soundManager.url = '../../swf/';
soundManager.flashVersion = 9;
soundManager.useHighPerformance = true;
soundManager.wmode = 'transparent';
soundManager.debugMode = false;
// start in either case
soundManager.onready(smashInit);
soundManager.ontimeout(smashInit);