Guest User

Let it Snow! Full Code

a guest
Nov 25th, 2017
285
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. (function() {
  2.     /**
  3.      * Basic timer/stopwatch class
  4.      * @author Rock
  5.      */
  6.     class Timer {
  7.         /**
  8.          * @param {number} duration The duration of the timer. Not really needed if using as a stopwatch
  9.          * @param {boolean} auto_start
  10.          */
  11.         constructor(duration, auto_start = true) {
  12.             /**
  13.              * Technically this is the "start time" but it's really just used for the offset to get `time_running` and `time_remaining` because pausing will cause this to change
  14.              */
  15.             this._start_time = Date.now();
  16.             this._paused = true;
  17.             this._paused_at = Date.now();
  18.    
  19.             this.duration = duration;
  20.    
  21.             if(auto_start) this.start();
  22.         }
  23.    
  24.         /** Returns the current elapsed time of the timer */
  25.         get elapsed_time() {
  26.             if(!this.paused) return Date.now() - this._start_time;
  27.             return this._paused_at - this._start_time;
  28.         }
  29.    
  30.         /** Returns the time remaining */
  31.         get remaining_time() {
  32.             return Math.max(0, this.duration - this.elapsed_time);
  33.         }
  34.    
  35.         /** Retruns whether the timer is paused or not */
  36.         get paused() {
  37.             return this._paused;
  38.         }
  39.    
  40.         /** Returns whether the timer has completed (reached 0ms) */
  41.         get is_complete() {
  42.             return this.elapsed_time >= this.duration;
  43.         }
  44.    
  45.         /**
  46.          * Returns a promise that resolves once the timer has completed.
  47.          *
  48.          * **EVEN IF THE TIMER IS EDITED, THIS WILL STILL RESOLVE AT THE SAME TIME**
  49.          */
  50.         get completion() {
  51.             return module.exports.wait(this.remaining_time);
  52.         }
  53.    
  54.         /** Starts or resumes the timer. */
  55.         start() {
  56.             this._start_time = Date.now() - this.elapsed_time;
  57.             this._paused = false;
  58.             return this;
  59.         }
  60.        
  61.         /** Resets the timer without pausing */
  62.         reset() {
  63.             this._paused_at = this._start_time = Date.now();
  64.             return this;
  65.         }
  66.        
  67.         /** Pauses the timer without resetting it */
  68.         pause() {
  69.             this._paused = true;
  70.             this._paused_at = Date.now();
  71.             return this;
  72.         }
  73.    
  74.         /** Stops and resets the timer */
  75.         stop() {
  76.             this._paused = true;
  77.             return this;
  78.         }
  79.     }
  80.     /** @type {HTMLCanvasElement} */
  81.     var canvas = document.createElement("canvas");
  82.     canvas.style.position = "fixed";
  83.     canvas.style.left = 0;
  84.     canvas.style.top = 0;
  85.     canvas.style.position = "fixed";
  86.     canvas.style.width = "100vw";
  87.     canvas.style.height = "100vh";
  88.     canvas.style.zIndex = "100000";
  89.     canvas.style.pointerEvents = "none";
  90.     document.body.insertBefore(canvas, document.body.children[0]);
  91.  
  92.         ctx = canvas.getContext("2d");
  93.     let screen_width = canvas.width = window.innerWidth,
  94.         screen_height = canvas.height = window.innerHeight;
  95.    
  96.     let dtTimer = new Timer(0, true);
  97.     let running = false;
  98.     let scramble;
  99.  
  100.     (function() {
  101.         var snowflakes = [];
  102.  
  103.         const num_flakes = 200,
  104.             wind_change_speed = 0.0005,
  105.             fall_speed_coefficient = 50,
  106.             wind_speed = 0.2;
  107.             scale_coefficient = 1,
  108.             screen_max_overlap = 20,
  109.             min_fall_speed = 65;
  110.  
  111.         let wind_timer = new Timer(0, true);
  112.         running = true;
  113.         for (var i = 0; i < num_flakes; ++i) {
  114.             const flake = new Flake();
  115.             flake.y = Math.random() * (screen_height + 50);
  116.             flake.x = Math.random() * screen_width;
  117.             flake.t = Math.random() * (Math.PI * 2);
  118.             flake.sz = (Math.random() * 3 + 0.8) * scale_coefficient;
  119.             flake.dy = (Math.pow(flake.sz, 2.5) * .1) * fall_speed_coefficient * (Math.random() * 2 + 1);
  120.             flake.dy = flake.dy < min_fall_speed ? min_fall_speed : flake.dy;
  121.  
  122.             flake.wind_offset = Math.random() * Math.PI / 1.3;
  123.  
  124.             flake.dx = 0;
  125.             flake.speed = 0;
  126.            
  127.             snowflakes.push(flake);
  128.         }
  129.         go();
  130.         function go() {
  131.             ctx.clearRect(0, 0, screen_width, screen_height);
  132.             ctx.fill();
  133.             if(!running) {
  134.                 snowflakes = [];
  135.                 return;
  136.             }
  137.             window.requestAnimationFrame(go);
  138.             const dt = dtTimer.elapsed_time * (1 / 1000);
  139.             dtTimer.reset();
  140.             for (var i = 0; i < snowflakes.length; ++i) {
  141.                 const flake = snowflakes[i];
  142.                 flake.dx = Math.sin(wind_timer.elapsed_time * wind_change_speed + flake.wind_offset) * (flake.sz * wind_speed) * 80;
  143.                 flake.speed = Math.sqrt(flake.dx * flake.dx + flake.dy * flake.dy);
  144.                 flake.y += flake.dy * dt;
  145.                 flake.x += flake.dx * dt;
  146.                 if (flake.y > screen_height + 50) flake.y = -10 - Math.random() * screen_max_overlap;
  147.                 if (flake.x > screen_width + screen_max_overlap) flake.x = - screen_max_overlap;
  148.                 if (flake.x < - screen_max_overlap) flake.x = screen_width + screen_max_overlap;
  149.                 flake.draw();
  150.             }
  151.         }
  152.         function Flake() {
  153.             this.draw = function () {
  154.                 ctx.save();
  155.                 ctx.translate(this.x, this.y);
  156.                
  157.                 const angle = Math.atan(this.dx / this.dy);
  158.                 ctx.rotate(-angle);
  159.  
  160.                 ctx.scale(1, Math.max(1, Math.pow(this.speed, 0.7) / 15))
  161.  
  162.                 this.g = ctx.createRadialGradient(0, 0, 0, 0, 0, this.sz);
  163.                 this.g.addColorStop(0, 'hsla(255,255%,255%,1)');
  164.                 this.g.addColorStop(1, 'hsla(255,255%,255%,0)');
  165.                 ctx.moveTo(0, 0);
  166.                 ctx.fillStyle = this.g;
  167.                 ctx.beginPath();
  168.                 ctx.arc(0, 0, this.sz, 0, Math.PI * 2, true);
  169.                 ctx.closePath();
  170.                 ctx.fill();
  171.                 ctx.restore();
  172.             }
  173.         }
  174.  
  175.         scramble = () => {
  176.             for (var i = 0; i < num_flakes; ++i) {
  177.                 snowflakes[i].y = Math.random() * (screen_height + 50);
  178.                 snowflakes[i].x = Math.random() * screen_width;
  179.             }
  180.         }
  181.  
  182.         scramble();
  183.     })();
  184.     function onResizeOrVisibilityChange() {
  185.         canvas.width = screen_width = window.innerWidth;
  186.         canvas.height = screen_height = window.innerHeight;
  187.  
  188.         if(running) scramble();
  189.     }
  190.     document.addEventListener("visibilitychange", () => setTimeout(onResizeOrVisibilityChange, 100), false);
  191.     window.addEventListener('resize', onResizeOrVisibilityChange, false);
  192. })();
Advertisement
Add Comment
Please, Sign In to add comment