как настроить цикл для воспроизведения один раз на холсте частиц

avatar
user3103726
8 апреля 2018 в 09:26
283
0
2

Я впервые создал холст частиц, я хочу знать, как остановить этот цикл и воспроизвести его только один раз.
Я попытался поставить setTimeout(), но он продолжает играть и все еще зацикливается. Возможно, я поставил setTimeout() не в ту строку.

Кто-нибудь знает, как остановить цикл? Код кажется сложным, чтобы остановить цикл. Если есть способ остановить, пожалуйста, помогите!

angular.module("particles", [])
.directive("explosion", ["$interval",
function($interval) {
  return {
    restrict: "C",
    template: "<canvas></canvas",
    replace: true,
    transclude: true,
    scope: {
      particle: "@",
      count: "=",
      speed: "=",
      size: "=",
      colors: "=",
      spawn: "="
    },
    link: function(scope, element, attrs) {
      console.log("Starting canvas ", scope.particle);
      var ctx = element[0].getContext('2d');
      var particles = [];
      var width, height;
      var maxCount = scope.count || 100;
      var maxSpeed = scope.speed || 150;
      var maxSize = scope.size || 10;
      var colors = scope.colors || ['#f00'];
      var spawnTime = scope.spawn ? 1000 / scope.spawn : 10;
      var resize = function() {
        element.attr({
          width: $('body').width(),
          height: $('body').height()
        });

        width = element.attr('width');
        height = element.attr('height');

        console.log("Size ", width, "x", height);
      };
      var spawn = function() {
        particles.push({
          x: width / 2,
          y: height / 2,
          sx: width / 2,
          sy: height / 2,
          v: {
            x: (maxSpeed << 1) * Math.random() - maxSpeed,
            y: (maxSpeed << 1) * Math.random() - maxSpeed
          },
          s: Math.random() * maxSize,
          rm: Math.floor( Math.random() * (80 + 1 - 10) ) + 10,
          a: 1,
          c: colors[Math.floor(Math.random() * colors.length)]
        });
      };
      var draw = function() {
        ctx.clearRect(0, 0, width, height);
        for (var i = 0; i < particles.length; i++) {
          var p = particles[i];
          ctx.beginPath();
          ctx.globalAlpha = p.a;
          ctx.fillStyle = p.c;
          ctx.arc(p.x, p.y, p.s, 0, 2 * Math.PI);
          ctx.fill();
          
          ctx.beginPath();
          drawStar(ctx, p.sx, p.sy, 8, p.rm, Math.ceil(p.rm*.1));
          ctx.fill();
          
        }
        function drawStar(context, xCenter, yCenter, nPoints, outerRadius, innerRadius) {
          ctx.beginPath();
          for (var ixVertex = 0; ixVertex <= 2 * nPoints; ++ixVertex) {
            var angle = ixVertex * Math.PI / nPoints - Math.PI / 2;
            var radius = ixVertex % 2 == 0 ? outerRadius : innerRadius;
            context.lineTo(xCenter + radius * Math.cos(angle), yCenter + radius * Math.sin(angle));
          }
        }
      };
      var lastSpawned = 0;
      var update = function(delta) {

        lastSpawned += delta;
        while (lastSpawned > spawnTime) {
          lastSpawned -= spawnTime;
          spawn();
        }
        var particleOverflow = particles.length - maxCount;
        if (particleOverflow > 0) {
          particles.splice(0, particleOverflow);
        }

        for (var i = 0; i < particles.length; i++) {
          var p = particles[i];
          p.x += p.v.x * delta / 1000;
          p.y += p.v.y * delta / 1000;
          p.a *= 0.99;
          p.sx += p.v.x * delta / 600;
          p.sy += p.v.y * delta / 600;
        }
      };
      var finished = false;
      var time;
      var animate = function(elapsed) {
        if (!time)
        time = elapsed;

        var delta = elapsed - time;
        time = elapsed;
        update(delta);
        draw();
        setTimeout(draw, 100);


        if (!finished) window.requestAnimationFrame(animate);
      };

      resize();
      $(window).on('resize', resize);
      window.requestAnimationFrame(animate);
      scope.$on("$destroy", function() {
        finished = true;
      });
    }
  };
}
]);
html {
  height: 100%;
}
body {
  background:#000;
  overflow:hidden;
  height:100%;
}
.canvas {
  width:100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="particles">
    <div class="canvas explosion" particle="circle"
    count="100" speed="200" size="40" spawn="10"
    colors="['rgba(255,255,255,.6)', 'rgba(255,255,255,.4)', 'rgba(255,255,255,.2)', 'rgba(255,255,255,.3)']" ></div>
  </div>
Источник
Kaiido
8 апреля 2018 в 10:53
0

Не смешивайте settimeout с обратным вызовом requestAnimationFrame, и чтобы остановить этот цикл, у вас уже есть флаг finished, поэтому устанавливайте его в true в любое время, но вне цикла rAF.

user3103726
8 апреля 2018 в 11:11
0

если флаг завершения установлен в значение true, анимация вообще не воспроизводится. извините, может быть, я пишу неправильный текст, я хочу воспроизвести анимацию холста только один раз, без зацикливания. извините, это меня усложняет.

Kaiido
8 апреля 2018 в 11:12
0

Только один раз? Затем просто удалите window.requestAnimationFrame(animate) в функции animate. И если вам нужно сделать цикл x раз, вы можете сделать setTimeout(function(){finished=true;}, x_time), но вне цикла rAF (он же animate в вашем коде)

Kaiido
8 апреля 2018 в 11:19
0

Но обратите внимание, что первый кадр почти пуст.

Ответы (0)