UNPKG

threex

Version:

Game Extensions for three.js http://www.threejsgames.com/extensions/

379 lines (341 loc) 11.9 kB
<!DOCTYPE html> <script src='../../../vendor/three.js/build/three.min.js'></script> <script src="../../../vendor/require.js/require.js"></script> <script src='js/threex.textureutils.js'></script> <script src='js/fartscroll.js'></script> <script src='bower_components/threex.nyancat/threex.nyancat.js'></script> <script src='bower_components/threex.nyancat/threex.nyancatsound.js'></script> <script src='bower_components/threex.nyancat/threex.nyancatstars.js'></script> <script src='bower_components/threex.nyancat/threex.nyancatrainbow.js'></script> <body style='margin: 0px; background-color: #003366; overflow: hidden;'><script> require([ '../../threex.effectcomposer/package.require.js' ], function(){ var renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); renderer.setClearColor('#003366') var updateFcts = []; var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 1000 ); camera.position.z = 3; scene.fog = new THREE.FogExp2( 0x003366, 0.0095 ); var pointLight = new THREE.PointLight( 0xFFFFFF ); pointLight.position.z = 10; scene.add(pointLight); ////////////////////////////////////////////////////////////////////////////////// // comment // ////////////////////////////////////////////////////////////////////////////////// var paused = false; var nyanCat = new THREEx.NyanCat() nyanCat.container.scale.multiplyScalar(1/20) scene.add( nyanCat.container ) updateFcts.push(function(delta, now){ if( paused ) return nyanCat.update(delta, now) }) // var sound = new THREEx.NyanCatSound() // document.body.addEventListener('mousedown', function(){ // paused = paused ? false : true // sound.toggle() // }) var nyanStars = new THREEx.NyanCatStars() nyanStars.container.scale.multiplyScalar(1/20) scene.add( nyanStars.container ) updateFcts.push(function(delta, now){ if( paused ) return nyanStars.update(delta, now) }) var nyanRainbow = new THREEx.NyanCatRainbow() nyanRainbow.container.scale.multiplyScalar(1/20) window.nyanRainbow = nyanRainbow scene.add( nyanRainbow.container ) updateFcts.push(function(delta, now){ if( paused ) return nyanRainbow.update(delta, now) }) ////////////////////////////////////////////////////////////////////////////////// // Camera Controls // ////////////////////////////////////////////////////////////////////////////////// var mouse = {x : 0, y : 0} document.addEventListener('mousemove', function(event){ mouse.x = (event.clientX / window.innerWidth ) - 0.5 mouse.y = (event.clientY / window.innerHeight) - 0.5 }, false) updateFcts.push(function(delta, now){ camera.position.x += (mouse.x*15 - camera.position.x) * 0.01 camera.position.y += (mouse.y*15 - camera.position.y) * 0.01 camera.lookAt( scene.position ) }) ////////////////////////////////////////////////////////////////////////////////// // comment // ////////////////////////////////////////////////////////////////////////////////// var urls = [ // 'images/flame/flame00.png', // 'images/flame/flame01.png', // 'images/flame/flame02.png', // 'images/flame/flame03.png', // 'images/flame/flame04.png', // 'images/flame/flame05.png', // 'images/flame/flame06.png', // 'images/flame/flame07.png', // 'images/flame/flame08.png', // 'images/flame/flame09.png', // 'images/flame/flame10.png', // 'images/flame/flame11.png', 'images/flame/flame12.png', 'images/flame/flame13.png', 'images/flame/flame14.png', 'images/flame/flame15.png', 'images/flame/flame16.png', 'images/flame/flame17.png', 'images/flame/flame18.png', 'images/flame/flame19.png', 'images/flame/flame20.png', 'images/flame/flame21.png', 'images/flame/flame22.png', 'images/flame/flame23.png', 'images/flame/flame24.png' ]; ////////////////////////////////////////////////////////////////////////////////// // handle trigger // ////////////////////////////////////////////////////////////////////////////////// // TODO put that in the particle itself ? // handle emit rate with a MidiTrigger var emitTrigger = new MidiTrigger(0.2, 0.2) /** * trigger with a attack, a sustain and a release. like midi notes * * @param {Number} attackDelay nb second for the attack phase * @param {Number} releaseDelay nb second for the release phase * @param {Number} maxValue the maximum value of the intensity */ function MidiTrigger(attackDelay, releaseDelay){ var lastStart = 0, lastStop = 0; this.start = function(){ lastStart = Date.now()/1000 } this.stop = function(){ lastStop = Date.now()/1000 } this.intensity = function(){ var present = Date.now()/1000 if( lastStop >= lastStart ){ // release in-progress or overs if(present - lastStop >= releaseDelay) return 0 // release over return 1 - (present - lastStop) / releaseDelay // release inprogress }else if( present - lastStart <= attackDelay ){ // attack in-progress return (present - lastStart) / attackDelay }else return 1; // sustain in-progress } } var fartScroll = new FartScroll(); document.addEventListener('mousedown' , function(){ emitTrigger.start() var soundIdx = fartScroll.play() var durations = [ 0.5, 0.2, 0.4, 0.1, 0.4, 0.8, 0.6, 0.1, 0.1, 0.5, ]; var duration = durations[soundIdx] scene.remove( nyanRainbow.container ) setTimeout(function(){ console.log('stop emit', duration) emitTrigger.stop() scene.add( nyanRainbow.container ) }, duration*1000) }) ////////////////////////////////////////////////////////////////////////////////// // comment // ////////////////////////////////////////////////////////////////////////////////// // TODO put that in the particle itself ? loadTremulousFlameParticules(urls, function(texture, urls){ // create emitter var emitter = new FlameThrower(texture, urls.length, scene) // emit based on rate var lastEmit = 0; updateFcts.push(function(delta, now){ // rate limiter emition var rate = 15 * emitTrigger.intensity(); if( rate === 0 || now - lastEmit < 1/rate ) return; lastEmit = now; var position = new THREE.Vector3(0,0,0) position.copy( nyanCat.container.position ) position.add(new THREE.Vector3(-0.2,0,0.05)) var velocity = new THREE.Vector3(-7, 0, 0) // var velocity = new THREE.Vector3(0, 1, -6) emitter.emit(position, velocity); }); // update emitter updateFcts.push(function(delta, now){ emitter.update(delta, now); }) }) function loadTremulousFlameParticules(urls, onReady){ // load all the images from urls THREEx.TextureUtils.loadImages(urls, function(images, urls){ // build a tiled spreadsheet canvas with images var canvas = THREEx.TextureUtils.buildTiledSpriteSheet({ images : images, spriteW : images[0].width, spriteH : images[0].height, nSpriteX: 1 }); // create the texture var texture = new THREE.Texture( canvas ); texture.needsUpdate = true; // generate Alpha as it got no alpha THREEx.TextureUtils.generateAlphaFromLuminance(texture, 16, 1); // notify caller onReady(texture, urls) }) } ////////////////////////////////////////////////////////////////////////////////// // render the scene // ////////////////////////////////////////////////////////////////////////////////// // updateFcts.push(function(){ // renderer.render( scene, camera ); // }) var composer = new THREEx.EffectComposer(renderer) .renderPass(scene, camera) // .film() .motionBlur(0.7) .vignette() .copy() .finish() updateFcts.push(function(delta, now){ composer.update(delta); }) ////////////////////////////////////////////////////////////////////////////////// // loop runner // ////////////////////////////////////////////////////////////////////////////////// var lastTimeMsec= null requestAnimationFrame(function animate(nowMsec){ // keep looping requestAnimationFrame( animate ); // measure time lastTimeMsec = lastTimeMsec || nowMsec-1000/60 var deltaMsec = Math.min(200, nowMsec - lastTimeMsec) lastTimeMsec = nowMsec // call each update function updateFcts.forEach(function(updateFn){ updateFn(deltaMsec/1000, nowMsec/1000) }) }) ////////////////////////////////////////////////////////////////////////////////// // comment // ////////////////////////////////////////////////////////////////////////////////// function FlameThrower(texture, nTiles, container){ // handle local loop var updateFcts = []; this.update = function(delta, now){ updateFcts.forEach(function(updateFct){ updateFct(delta, now) }) } // handle tweening var age2Friction= (function(){ var gradient = createLinearGradient([ {x : 0.00, y: 1.00}, {x : 0.50, y: 1.00}, {x : 0.70, y: 0.95}, {x : 1.00, y: 0.95} ]); return function(age, maxAge){ return gradient(age/maxAge) } })(); var age2Opacity = (function(){ var tween = createTweenMidi(1, 0.1, 0.5) return function(age, maxAge){ return tween(age/maxAge) } })(); var age2uvOffset= function(age, maxAge){ var imageIdx = Math.floor(age/maxAge * nTiles); var uvOffsetY = 1 - imageIdx * 1/nTiles; return uvOffsetY } // put the emmiter this.emit = function(position, velocity){ // randomize the initial position position = position.clone() // init sprite material var material = new THREE.SpriteMaterial({ map : texture, useScreenCoordinates : false, transparent : true, blending : THREE.AdditiveBlending }) material.uvScale.set(1, 1/nTiles) // init sprite var sprite = new THREE.Sprite(material) sprite.position.copy(position) sprite.rotation = Math.random()*Math.PI*2 sprite.scale.set(1,1,1).multiplyScalar(2) container.add( sprite ) // init age2OffsetY var uvOffset = age2uvOffset(0, maxAge) material.uvOffset.set(0, uvOffset) var maxAge = 0.8 + (Math.random()-0.5)*0 // set velocity var speed = velocity.length() velocity = velocity.clone().normalize() velocity.x += (Math.random()-0.5)*0.0 velocity.y += (Math.random()-0.5)*0.2 velocity.z += (Math.random()-0.5)*0.0 velocity.setLength(speed) // set acceleration var acceleration= new THREE.Vector3(0, 2, 0) // init opacity material.opacity= age2Opacity(0, maxAge) var birthDate = Date.now()/1000 updateFcts.push(function callback(delta, now){ var age = Date.now()/1000 - birthDate if( age >= maxAge ){ sprite.parent.remove(sprite) updateFcts.splice(updateFcts.indexOf(callback),1) return; } // handle acceleration velocity.add(acceleration.clone().multiplyScalar(delta)) // handle friction velocity.multiplyScalar( age2Friction(age, maxAge) ) // move by velocity sprite.position.add( velocity.clone().multiplyScalar(delta) ) // make it grow sprite.scale.multiplyScalar( 1.015 ) // handle opacity material.opacity= age2Opacity(age, maxAge) // init uvOffset material.uvOffset.set(0, age2uvOffset(age, maxAge)) }) } function createTweenMidi(maxAge, attackTime, releaseTime){ return function(age){ if( age < attackTime ){ return age / attackTime }else if( age < maxAge - releaseTime ){ return 1; }else{ return (maxAge - age) / releaseTime } } } function createLinearGradient(keyPoints){ return function(x){ // find the keyPoints for( var i = 0; i < keyPoints.length; i++ ){ if( x <= keyPoints[i].x ) break; } if( i === 0 ) return keyPoints[0].y; // sanity check console.assert(i < keyPoints.length ); // compute the y var previous = keyPoints[i-1]; var next = keyPoints[i]; var ratio = (x - previous.x) / (next.x - previous.x) var y = previous.y + ratio * (next.y - previous.y) // return y return y; } } } }) </script></body>