<script src="js/vendor/jquery.min.js"></script> <script src="js/vendor/yepnope.1.5.4-min.js"></script> <script src="js/myYepnope.min.js"></script>
var isWebGLSupported, canvas = document.getElementById('checkwebgl'); if (!window.WebGLRenderingContext) { // Browser has no idea what WebGL is isWebGLSupported = false; } else if (canvas.getContext("webgl") || canvas.getContext("webGlCanvas") || canvas.getContext("moz-webgl") || canvas.getContext("webkit-3d") || canvas.getContext("experimental-webgl")) { // Can get context isWebGLSupported = true; } else { // Can't get context isWebGLSupported = false; }
-webkit-filter: blur()
properties. The property is perfectly animated. Firefox uses svg filter, the radius of which is dynamically changed and used as a css filter: 'url()'
property filter: 'url()'
, while the data url
generated by the script and updated every 20% of the load. if (isWebGLSupported) { var $body = $('body'), $cc = $('.choose_control'), maxBlur = 100, steps = 4, isWebkitBlurSupported; if ($body[0].style.webkitFilter === undefined) { isWebkitBlurSupported = false; $cc.css({filter: "url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\"><filter id=\"blur-overlay\"><feGaussianBlur stdDeviation=\"" + maxBlur + "\"/></filter></svg>#blur-overlay')"}); } else { isWebkitBlurSupported = true; $body[0].style.webkitFilter = 'blur(' + maxBlur + 'px)'; } $('#loader').css({display: 'table'}); $cc.css({display: 'table'}); yepnope.loadCounter = 0; yepnope.percent = 0; yepnope.showLoading = function (n) { yepnope.percent += maxBlur/steps; yepnope.loadCounter += 1; $(".loader").animate({minWidth: Math.round(yepnope.percent)+"px"}, { duration: 1000, progress: function () { var current = parseInt($(".loader").css("minWidth"), 10) * 100/maxBlur; $("title").html(Math.floor(current) + "% " + "digital trip"); if (isWebkitBlurSupported) { $body[0].style.webkitFilter = 'blur('+ (maxBlur - current)+ 'px)'; } if (!isWebkitBlurSupported && current % 20 === 0) { $cc.css({filter: "url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\"><filter id=\"blur-overlay\"><feGaussianBlur stdDeviation=\"" + (maxBlur - maxBlur/(steps+1)*n) + "\"/></filter></svg>#blur-overlay')"}); } if (current === 100) { $("title").html("digital trip"); if (!isWebkitBlurSupported && current % 20 === 0) $cc.css({filter: "url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\"><filter id=\"blur-overlay\"><feGaussianBlur stdDeviation=\"" + 0 + "\"/></filter></svg>#blur-overlay')"}); } }, complete: function () { if (n === steps) { DT.runApp(); } } }); }; yepnope([{ load: [ "js/vendor/three.min.js", "js/DT.min.js", "../socket.io/socket.io.js" ], callback: {} }]); } else { $('#nogame').css({display: 'table'}); }
document
element, calling the appropriate handlers, for example: DT.$document.trigger('gameOver', {cause: 'death'}); DT.$document.on('gameOver', function (e, data) { if (data.cause === 'death') { DT.audio.sounds.gameover.play(); } });
'blur'
and 'focus'
events are triggered in a window
and are used to turn off the sound and pause when the window with the game loses focus. DT.$window.on('blur', function() { if (DT.game.wasStarted && !DT.game.wasPaused && !DT.game.wasOver) { DT.$document.trigger('pauseGame', {}); } DT.setVolume(0); });
three.js
: a scene, camera, game space, light sources, background are created. DT.scene = new THREE.Scene();
DT.splineCamera = new THREE.PerspectiveCamera( 84, window.innerWidth / window.innerHeight, 0.01, 1000 );
var extrudePath = new THREE.Curves.TorusKnot(); DT.tube = new THREE.TubeGeometry(extrudePath, 100, 3, 8, true, true);
DT.lights = { light: new THREE.PointLight(0xffffff, 0.75, 100), directionalLight: new THREE.DirectionalLight(0xffffff, 0.5) };
var geomBG = new THREE.SphereGeometry(500, 32, 32), matBG = new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture('img/background5.jpg'), }), worldBG = new THREE.Mesh(geomBG, matBG); worldBG.material.side = THREE.BackSide;
DT.Game
), Player ( DT.Player
), and Game Object ( DT.GameObject
). They have their own methods (update, reset, etc.), called by the appropriate handlers in response to the triggering of an event. The game object contains various parameters (speed, acceleration), constants (minimum distance between stones and information about their state ( wasStarted
, wasPaused
). Player object contains information about the current state of the player (score, life, invulnerability), as well as the state of the player model (sphere, rings (contours, which are indicators of health) around the sphere.) All other objects are subclasses of the Game object (particles, shield on the player, bonuses). this.sphere = new THREE.Mesh(new THREE.SphereGeometry(0.5, 32, 32), new THREE.MeshPhongMaterial({}));
this.emitter = Fireworks.createEmitter({nParticles : 100}) .effectsStackBuilder() .spawnerSteadyRate(30) .position(Fireworks.createShapePoint(0, 0, 0)) .velocity(Fireworks.createShapePoint(0, 0, 0)) .lifeTime(0.2, 0.7) .renderToThreejsParticleSystem({ ... }) .back() .start();
DT.listOfModels = [{ name: 'bonusH1', scale: 0.1, rotaion: new THREE.Vector3(0, 0, 0), color: 0xff0000, }, { name: 'bonusI', scale: 0.02, rotaion: new THREE.Vector3(0, 0, 0), color: 0x606060, '5': 0xffffff, 'html': 0xffffff, 'orange': 0xD0671F, 'shield': 0xC35020, }, { name: 'bonusE1', scale: 0.75, rotaion: new THREE.Vector3(0, 0, 0), color: 0x606060, }, { name: 'bonusH2', scale: 0.1, rotaion: new THREE.Vector3(0, 0, 0), color: 0xff0000, }, { name: 'shield', scale: 0.16, rotaion: new THREE.Vector3(0, 0, 0), color: 0x606060, }, { name: 'bonusE2', scale: 0.75, rotaion: new THREE.Vector3(0, 0, 0), color: 0x606060, } ];
var manager = new THREE.LoadingManager(), loader = new THREE.OBJLoader(manager); manager.onProgress = function (item, loaded, total) { console.info('loaded item', loaded, 'of', total, '('+item+')'); }; DT.listOfModels.forEach(function (el, i, a) { loader.load('objects/' + el.name + '.obj', function ( object ) { object.traverse( function ( child ) { var color = el[child.name] || el.color; child.material = new THREE.MeshPhongMaterial({ color: color, shading: THREE.SmoothShading, emissive: new THREE.Color(color).multiplyScalar(0.5), shininess: 100, }); }); if (i === 1) { a[i].object = object } else { a[i].object = object.children[0]; } DT.$document.trigger('externalObjectLoaded', {index: i}); }); });
DT.listOfModels[index].object
and are used in the bonus constructor.morphTargets
geometry. The current state of the object is determined by the level of the morphTargetInfluences
object. DT.createGeometry = function (circumradius) { var geometry = new THREE.Geometry(), x, innerradius = circumradius * 0.97, n = 60; function setMainVert (rad, numb) { var vert = []; for (var i = 0; i < numb; i++) { var vec3 = new THREE.Vector3( rad * Math.sin((Math.PI / numb) + (i * ((2 * Math.PI)/ numb))), rad * Math.cos((Math.PI / numb) + (i * ((2 * Math.PI)/ numb))), 0 ); vert.push(vec3); } return vert; } function fillVert (vert) { var nFilled, nUnfilled, result = []; nFilled = vert.length; nUnfilled = n/nFilled; vert.forEach(function (el, i, arr) { var nextInd = i === arr.length - 1 ? 0 : i + 1; var vec = el.clone().sub(arr[nextInd]); for (var j = 0; j < nUnfilled; j++) { result.push(vec.clone().multiplyScalar(1/nUnfilled).add(el)); } }); return result; } // set morph targets [60, 5, 4, 3, 2].forEach(function (el, i, arr) { var vert, vertOuter, vertInner; vertOuter = fillVert(setMainVert(circumradius, el).slice(0)).slice(0); vertInner = fillVert(setMainVert(innerradius, el).slice(0)).slice(0); vert = vertOuter.concat(vertInner); geometry.morphTargets.push({name: 'vert'+i, vertices: vert}); if (i === 0) { geometry.vertices = vert.slice(0); } }); // Generate the faces of the n-gon. for (x = 0; x < n; x++) { var next = x === n - 1 ? 0 : x + 1; geometry.faces.push(new THREE.Face3(x, next, x + n)); geometry.faces.push(new THREE.Face3(x + n, next, next + n)); } return geometry; };
DT.effectComposer = new THREE.EffectComposer( DT.renderer ); DT.effectComposer.addPass( new THREE.RenderPass( DT.scene, DT.splineCamera ) ); DT.effectComposer.on = false; var badTVParams = { mute:true, show: true, distortion: 3.0, distortion2: 1.0, speed: 0.3, rollSpeed: 0.1 } var badTVPass = new THREE.ShaderPass( THREE.BadTVShader ); badTVPass.on = false; badTVPass.renderToScreen = true; DT.effectComposer.addPass(badTVPass);
DT.$document.on('update', function (e, data) { if (DT.effectComposer.on) { badTVPass.uniforms[ "distortion" ].value = badTVParams.distortion; badTVPass.uniforms[ "distortion2" ].value = badTVParams.distortion2; badTVPass.uniforms[ "speed" ].value = badTVParams.speed; badTVPass.uniforms[ "rollSpeed" ].value = badTVParams.rollSpeed; DT.effectComposer.render(); badTVParams.distortion+=0.15; badTVParams.distortion2+=0.05; badTVParams.speed+=0.015; badTVParams.rollSpeed+=0.005; }; });
'gameOver'
DT.$document.on('gameOver', function (e, data) { DT.effectComposer.on = true; });
DT.$document.on('resetGame', function (e, data) { DT.effectComposer.on = false; badTVParams = { distortion: 3.0, distortion2: 1.0, speed: 0.3, rollSpeed: 0.1 } });
DT.audio.valueAudio
) is currently defined in the render buffer as follows. var getFrequencyValue = function(frequency, bufferIndex) { if (!DT.isAudioCtxSupp) return; var nyquist = DT.audio.context.sampleRate/2, index = Math.round(frequency/nyquist * freqDomain[bufferIndex].length); return freqDomain[bufferIndex][index]; }; var visualize = function(index) { if (!DT.isAudioCtxSupp) return; freqDomain[index] = new Uint8Array(analysers[index].frequencyBinCount); analysers[index].getByteFrequencyData(freqDomain[index]); DT.audio.valueAudio = getFrequencyValue(DT.audio.frequency[index], index); };
DT.audio.valueAudio
value DT.audio.valueAudio
used to update the state of particle transparency: DT.$document.on('update', function (e, data) { DT.dust.updateMaterial({ isFun: DT.player.isFun, valueAudio: DT.audio.valueAudio, color: DT.player.sphere.material.color }); });
updateMaterial
method updateMaterial
: DT.Dust.prototype.updateMaterial = function (options) { if (!this.material.visible) { this.material.visible = true; } this.material.color = options.isFun ? options.color : new THREE.Color().setRGB(1,0,0); this.material.opacity = 0.5 + options.valueAudio/255; return this; };
<link rel="icon" type="image/gif" href="fav.gif">
var favicon = document.getElementsByTagName('link')[1], giffav = document.createElement('link'), head = document.getElementsByTagName('head')[0], isChrome = navigator.userAgent.indexOf('Chrome') !== -1; giffav.setAttribute('rel', 'icon'); giffav.setAttribute('type', 'image/gif'); giffav.setAttribute('href', 'img/fav.gif'); DT.$document.on('update', function (e, data) { if (isChrome && DT.player.isFun && DT.animate.id % 10 === 0) favicon.setAttribute('href', 'img/' + (DT.animate.id % 18 + 1) + '.png'); }); DT.$document.on('showFun', function (e, data) { if (!data.isFun) { if (isChrome) { favicon.setAttribute('href', 'img/0.png'); } else { $(giffav).remove(); head.appendChild(favicon); } } else { if (!isChrome) { $(favicon).remove(); head.appendChild(giffav); } } });
'update'
is the event of updating the state of objects, 'showFun'
is the event of the start of the seal mode (deceleration), DT.player.isFun
is the state of the seal mode, DT.animate.id
is the number of the current frame (frame). The total number of possible favicon options is 19. Unfortunately, there is no favicon animation in Safari.'deviceOrientation'
event. In the absence of a gyroscope or access to it, use the control by pressing the control buttons. // Technique from Juriy Zaytsev // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ var eventSupported = function( eventName ) { var el = document.createElement("div"); eventName = "on" + eventName; var isSupported = (eventName in el); if ( !isSupported ) { el.setAttribute(eventName, "return;"); isSupported = typeof el[eventName] === "function"; } el = null; return isSupported; }; // device orientation function orientationTest (event) { if (!turned && event.gamma) turned = true; window.removeEventListener('deviceorientation', orientationTest, false); window.removeEventListener('MozOrientation', orientationTest, false); } window.addEventListener('deviceorientation', orientationTest, false); window.addEventListener('MozOrientation', orientationTest, false); setTimeout(function () { if (!turned) { $("#btnLeft").on('touchstart',function () { socket.emit("click", {"click":"toTheLeft"}); }); $("#btnRight").on('touchstart',function () { socket.emit("click", {"click":"toTheRight"}); }); $status.html("push buttons to control"); } else { $status.html("tilt your device to control"); } if (!eventSupported('touchstart')) { $status.html("sorry your device not supported"); } }, 1000);
'deviceOrientation'
implemented via setTimeout
, and not similar to eventSupported
, since there are devices (for example, HTC One V) that support 'deviceOrientation'
nominally, but the event itself does not occur. In fact, we are waiting for the occurrence of an event (which should definitely occur) for some period of time, and if it does not occur, we conclude that the event is not supported. Such a check is actually a hack.'touchstart'
event, but supports the higher 'click'
event. We refused to support such devices, since the response time when using the 'click'
event (300 ms) is much longer than that of the 'touchstart'
and it is not possible to provide the necessary level of response for monitoring using such devices. <audio id="audioloop" src="../sounds/loop.mp3" onended="this.play();" autobuffer></audio>
$('#btnSphere').on('touchstart',function () { socket.emit('click', {'click':'pause'}); $('#audioloop').trigger('play'); });
getUserMedia()
method. app.use('/webhook', hookshot('refs/heads/master', 'git pull'));
dogecoin.exec('getbalance', function(err, balance) { console.log(err, balance); });
var checkCoins = function (timeStart, timeEnd, coinsCollect) { var time = (timeEnd - timeStart)/1000, maxCoins = calcMaxCoins(time); // if client recieve more coins than it may return coinsCollect <= maxCoins; }; var calcMaxCoins = function (time) { var speedStart = 1/60, acceleration = 1/2500, maxPath = 0, maxCoins = 0, t = 0.25, // coins position in the tube dt = 0.004, // coins position offset n = 10; // number of coins in a row maxPath = (speedStart + acceleration * Math.sqrt(time * 60)) * time; maxCoins = Math.floor(maxPath / (t + dt * (n - 1)) * n)/10; console.log('time:' + time, 'maxCoins:' + maxCoins, 'maxPath:' + maxPath); return maxCoins; };
var checkClient = function (clients, currentClient) { console.log("Handle clients from Array[" + clients.length + "]") var IPpaymentsCounter = 0, UIDpaymentsCounter = 0, IPtimeCounter = 60 * 1000, checkup = null; clients.forEach(function(client, i) { if (client.clientIp === currentClient.clientIp && client.paymentRequest) { IPpaymentsCounter += client.paymentRequest; if (currentClient.timeEnd && currentClient.cientId !== client.cientId) { Math.min(IPtimeCounter, currentClient.timeEnd - client.timeEnd); } } if (client.cookieUID === currentClient.cookieUID && client.paymentRequest) { UIDpaymentsCounter += client.paymentRequest; } // console.log("handle client #" + i); }); console.log('IPtimeCounter', IPtimeCounter); if (currentClient.checkup === false || currentClient.maxCoinsCheck === false || IPpaymentsCounter > 1000 || UIDpaymentsCounter > 100 || IPtimeCounter < 20 * 1000) { checkup = false; } else { checkup = true; } return checkup; };
Source: https://habr.com/ru/post/230323/
All Articles