在Canvas中平稳地停止动画雨

时间:2017-05-23 00:24:18

标签: javascript canvas

Rain Picture Here所以我的问题不是停止下雨,而是停止下雨,所以已经下雨的雨完成了屏幕上的动画。

我在JS中尝试了setInterval和setTimeout,但它只是冻结了。

使用JQuery删除canvas标签会立即取消所有掉落。

任何想法或方向都会很棒!

    var canvas = document.getElementById("rainCanvas");
    var ctx = canvas.getContext("2d");

    var canvasW = window.innerWidth;
    var canvasH = window.innerHeight;
    canvas.height = canvasH;
    canvas.width = canvasW;


var mf = 70;
var drops = [];



for(var i = 0; i < mf; i++){
    drops.push({
        x: Math.random()*canvasW,
        y: Math.random()*canvasH,
        r: Math.random()*5+2,
        d: Math.random() + 1
    })

}

function fill() {
    ctx.fill();
    }



function drawRain(){
    ctx.clearRect(0, 0, canvasW, canvasH);
    ctx.fillStyle = "rgba(255, 255, 255, .5)";
    ctx.beginPath();
    for(var i = 0; i < mf; i++){
        var f = drops[i];
        ctx.moveTo(f.x-5, f.y);
        ctx.lineTo(f.x, f.y-15);
        ctx.lineTo(f.x+5, f.y);
        ctx.arc(f.x, f.y + f.r*.7,5, 0, Math.PI, false);
    }
    fill();

    moveRain();

}

function moveRain(){
    for(var i = 0; i < mf; i++){
        var f = drops[i];
        f.y += Math.pow(f.d, 2) + 1;

        if(f.y > canvasH){
            drops[i] = {x: Math.random()*canvasW, y: 0, r: f.r, d: f.d};
        }
    }
}


var i = setInterval(drawRain, 20);


setTimeout(function( ) { clearInterval(); }, 2000);
canvas{ background-color: black }
<canvas id="rainCanvas"></canvas>

3 个答案:

答案 0 :(得分:0)

你想要做的是设置一个标志,以阻止雨水回到你的功能中的顶部以停止下雨:

var stopRain = false;

...

setTimeout(function( ) { stopRain = true; }, 2000);

现在在moveRain内,当该变量为true而不是将其移回顶部时,将其从数组中删除。一旦我们删除了所有的滴,我们就可以清除不再需要的间隔:

function moveRain(){
    for(var i = 0; i < mf; i++){
        var f = drops[i];
        f.y += Math.pow(f.d, 2) + 1;

        if(f.y > canvasH){
            if(stopRain) {              // When we stop raining 
            drops.splice(i, 1);        // Remove drop from array
            mf--;                      // Make sure to update the "length"
            if(mf<1) clearInterval(i); // If there are not more drops clear the interval
          } else drops[i] = {x: Math.random()*canvasW, y: 0, r: f.r, d: f.d};
        }
    }
}

Fiddle Example

您也可以使用drops.length而不是mf,这样您就不需要mf--

答案 1 :(得分:0)

在这里,我修复了一些代码并添加了一个rainDensity变量来控制新雨滴的数量。原始代码设计为具有固定数量的雨滴,必须进行更改才能达到预期的效果。

&#13;
&#13;
window.onload = function(){

  var canvas = document.getElementById("rainCanvas");
  var ctx = canvas.getContext("2d");

  var canvasW = window.innerWidth;
  var canvasH = window.innerHeight;
  canvas.height = canvasH;
  canvas.width = canvasW;

  var drops = [];
  
  function makeDrop() {
    drops.push({
      x: Math.random()*canvasW,
      y: -10,
      r: Math.random()*4+1,
      d: Math.pow(Math.random() + 1, 2) + 1
    })
  }


  function drawRain(){
    ctx.clearRect(0, 0, canvasW, canvasH);
    ctx.fillStyle = "rgba(128, 128, 255, .5)";
    for(var f of drops){
      ctx.beginPath();
      ctx.moveTo(f.x-5, f.y);
      ctx.lineTo(f.x, f.y-15);
      ctx.lineTo(f.x+5, f.y);
      ctx.arc(f.x, f.y + f.r*.7,5, 0, Math.PI, false);
      ctx.fill();
    }
  }
  
  function handleFrame() {
    drawRain();
    updateRain();
  }
  
  function updateRain() {
    moveRain();
    makeNewDrops();
  }

  var dropPerFrameCounter = 0;
  var startTime = Date.now();
  function makeNewDrops() {
    var elapsedTime = (Date.now() - startTime) / 1000;  
    // rainDensity: set it to 0 to stop rain
    var rainDensity = Math.max(0, Math.sin(elapsedTime / 3) + 0.5);
    dropPerFrameCounter += rainDensity;
    while (dropPerFrameCounter >= 1) {
      dropPerFrameCounter--;
      makeDrop();
    }
  }
  function moveRain() {
    for(var f of drops){
      f.y += f.d;
    }
    drops = drops.filter(d => d.y < canvasH);
  }

  var intervalRender = setInterval(handleFrame, 20);
}
&#13;
<canvas id="rainCanvas"></canvas>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

必须添加一个答案,因为该示例全部使用setInterval来制作看起来很糟糕的动画。使用requestAnimationFrame制作动画。还解决了代码中的一些其他问题。

我添加了一个暂停,当您单击画布时暂停动画。再次单击将继续。

&#13;
&#13;
var canvas = document.getElementById("rainCanvas");
var ctx = canvas.getContext("2d");

var canvasW = window.innerWidth;
var canvasH = window.innerHeight;
canvas.height = canvasH;
canvas.width = canvasW;
var mf = 70;
var drops = [];
var paused = false;



for(var i = 0; i < mf; i++){
    drops.push({
        x: Math.random()*canvasW,
        y: Math.random()*canvasH,
        r: Math.random()*5+2,
        d: Math.random() + 1
    })

}




function drawRain(){
    if(!paused){
        ctx.clearRect(0, 0, canvasW, canvasH);
        ctx.fillStyle = "rgba(255, 255, 255, .5)";
        ctx.beginPath();
        for(var i = 0; i < mf; i++){
            var f = drops[i];
            ctx.moveTo(f.x - 2.5 * f.d, f.y);
            ctx.lineTo(f.x, f.y - 7.5 * f.d);
            ctx.lineTo(f.x + 2.5 * f.d, f.y);
            ctx.arc(f.x, f.y + f.r * 0.7, 2.5 * f.d, 0, Math.PI, false);
        }
        ctx.fill();

       for(var i = 0; i < mf; i++){
            var f = drops[i];
            f.y += Math.pow(f.d, 2) + 1;

            if(f.y > canvasH + 15){ // make sure completely off the bottom
               // dont create a new drop reuse it will stop GC from 
               // having to interrupt the code.
                f.x =  Math.random()*canvasW;
                f.y = -6; // move off top
                
            }
        }
    }
    requestAnimationFrame(drawRain);
}


requestAnimationFrame(drawRain);
canvas.addEventListener("click",()=>{paused = ! paused});
&#13;
canvas{
   background-color: black;
   position : absolute;
   top : 0px;
   left : 0px;
}
&#13;
<canvas id="rainCanvas"></canvas>
&#13;
&#13;
&#13;