HTML5画布粒子爆炸

Kai*_*all 5 javascript html5 canvas

我正试图让粒子爆炸起作用.它工作,但看起来有些帧不会被渲染.如果我多次点击几次爆炸就会开始呃......"滞后/断断续续".有什么我忘记做的事吗?当我点击多次时,浏览器可能会挂起.在彼此内部有2个循环是不是太多了?

附上我的代码,你可以看到.只需尝试多次点击,您就会看到问题.

// Request animation frame
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
// Canvas
var c = document.getElementById('canvas');
var ctx = c.getContext('2d');
// Set full-screen
c.width = window.innerWidth;
c.height = window.innerHeight;
// Options
var background = '#333'; // Background color
var particlesPerExplosion = 20;
var particlesMinSpeed = 3;
var particlesMaxSpeed = 6;
var particlesMinSize = 1;
var particlesMaxSize = 3;
var explosions = [];
var fps = 60;
var now, delta;
var then = Date.now();
var interval = 1000 / fps;
// Optimization for mobile devices
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
    fps = 29;
}
// Draw
function draw() {
    // Loop
    requestAnimationFrame(draw);
    // Set NOW and DELTA
    now = Date.now();
    delta = now - then;
    // New frame
    if (delta > interval) {
        // Update THEN
        then = now - (delta % interval);
        // Our animation
        drawBackground();
        drawExplosion();
    }
}
// Draw explosion(s)
function drawExplosion() {
    if (explosions.length == 0) {
        return;
    }
    for (var i = 0; i < explosions.length; i++) {
        var explosion = explosions[i];
        var particles = explosion.particles;
        if (particles.length == 0) {
            explosions.splice(i, 1);
            return;
        }
        for (var ii = 0; ii < particles.length; ii++) {
            var particle = particles[ii];
            // Check particle size
            // If 0, remove
            if (particle.size < 0) {
                particles.splice(ii, 1);
                return;
            }
            ctx.beginPath();
            ctx.arc(particle.x, particle.y, particle.size, Math.PI * 2, 0, false);
            ctx.closePath();
            ctx.fillStyle = 'rgb(' + particle.r + ',' + particle.g + ',' + particle.b + ')';
            ctx.fill();
            // Update
            particle.x += particle.xv;
            particle.y += particle.yv;
            particle.size -= .1;
        }
    }
}
// Draw the background
function drawBackground() {
    ctx.fillStyle = background;
    ctx.fillRect(0, 0, c.width, c.height);
}
// Clicked
function clicked(e) {
    var xPos, yPos;
    if (e.offsetX) {
        xPos = e.offsetX;
        yPos = e.offsetY;
    } else if (e.layerX) {
        xPos = e.layerX;
        yPos = e.layerY;
    }
    explosions.push(new explosion(xPos, yPos));
}
// Explosion
function explosion(x, y) {
    this.particles = [];
    for (var i = 0; i < particlesPerExplosion; i++) {
        this.particles.push(new particle(x, y));
    }
}
// Particle
function particle(x, y) {
    this.x = x;
    this.y = y;
    this.xv = randInt(particlesMinSpeed, particlesMaxSpeed, false);
    this.yv = randInt(particlesMinSpeed, particlesMaxSpeed, false);
    this.size = randInt(particlesMinSize, particlesMaxSize, true);
    this.r = randInt(113, 222);
    this.g = '00';
    this.b = randInt(105, 255);
}
// Returns an random integer, positive or negative
// between the given value
function randInt(min, max, positive) {
    if (positive == false) {
        var num = Math.floor(Math.random() * max) - min;
        num *= Math.floor(Math.random() * 2) == 1 ? 1 : -1;
    } else {
        var num = Math.floor(Math.random() * max) + min;
    }
    return num;
}
// On-click
$('canvas').on('click', function(e) {
    clicked(e);
});
draw();
Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html>

<head>
    <style>
        * {
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>
    <canvas id="canvas"></canvas>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

</html>
Run Code Online (Sandbox Code Playgroud)

the*_*ude 5

如果粒子太小,您将从迭代中返回。这导致该爆炸的其他粒子仅在下一帧渲染。

我有一个工作版本:

// Request animation frame
const requestAnimationFrame = window.requestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  window.webkitRequestAnimationFrame ||
  window.msRequestAnimationFrame;

// Canvas
const c   = document.getElementById('canvas');
const ctx = c.getContext('2d');

// Set full-screen
c.width  = window.innerWidth;
c.height = window.innerHeight;

// Options
const background            = '#333';                    // Background color
const particlesPerExplosion = 20;
const particlesMinSpeed     = 3;
const particlesMaxSpeed     = 6;
const particlesMinSize      = 1;
const particlesMaxSize      = 3;
const explosions            = [];

let fps        = 60;
const interval = 1000 / fps;

let now, delta;
let then = Date.now();

// Optimization for mobile devices
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
  fps = 29;
}

// Draw
function draw() {
  // Loop
  requestAnimationFrame(draw);

  // Set NOW and DELTA
  now   = Date.now();
  delta = now - then;

  // New frame
  if (delta > interval) {

    // Update THEN
    then = now - (delta % interval);

    // Our animation
    drawBackground();
    drawExplosion();

  }

}

// Draw explosion(s)
function drawExplosion() {

  if (explosions.length === 0) {
    return;
  }

  for (let i = 0; i < explosions.length; i++) {

    const explosion = explosions[i];
    const particles = explosion.particles;

    if (particles.length === 0) {
      explosions.splice(i, 1);
      return;
    }

    const particlesAfterRemoval = particles.slice();
    for (let ii = 0; ii < particles.length; ii++) {

      const particle = particles[ii];

      // Check particle size
      // If 0, remove
      if (particle.size <= 0) {
        particlesAfterRemoval.splice(ii, 1);
        continue;
      }

      ctx.beginPath();
      ctx.arc(particle.x, particle.y, particle.size, Math.PI * 2, 0, false);
      ctx.closePath();
      ctx.fillStyle = 'rgb(' + particle.r + ',' + particle.g + ',' + particle.b + ')';
      ctx.fill();

      // Update
      particle.x += particle.xv;
      particle.y += particle.yv;
      particle.size -= .1;
    }

    explosion.particles = particlesAfterRemoval;

  }

}

// Draw the background
function drawBackground() {
  ctx.fillStyle = background;
  ctx.fillRect(0, 0, c.width, c.height);
}

// Clicked
function clicked(e) {

  let xPos, yPos;

  if (e.offsetX) {
    xPos = e.offsetX;
    yPos = e.offsetY;
  } else if (e.layerX) {
    xPos = e.layerX;
    yPos = e.layerY;
  }

  explosions.push(
    new explosion(xPos, yPos)
  );

}

// Explosion
function explosion(x, y) {

  this.particles = [];

  for (let i = 0; i < particlesPerExplosion; i++) {
    this.particles.push(
      new particle(x, y)
    );
  }

}

// Particle
function particle(x, y) {
  this.x    = x;
  this.y    = y;
  this.xv   = randInt(particlesMinSpeed, particlesMaxSpeed, false);
  this.yv   = randInt(particlesMinSpeed, particlesMaxSpeed, false);
  this.size = randInt(particlesMinSize, particlesMaxSize, true);
  this.r    = randInt(113, 222);
  this.g    = '00';
  this.b    = randInt(105, 255);
}

// Returns an random integer, positive or negative
// between the given value
function randInt(min, max, positive) {

  let num;
  if (positive === false) {
    num = Math.floor(Math.random() * max) - min;
    num *= Math.floor(Math.random() * 2) === 1 ? 1 : -1;
  } else {
    num = Math.floor(Math.random() * max) + min;
  }

  return num;

}

// On-click
$('canvas').on('click', function (e) {
  clicked(e);
});

draw();
Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>

<html>

	<head>
		<style>* {margin:0;padding:0;overflow:hidden;}</style>
	</head>

    <body>
        <canvas id="canvas"></canvas>
    </body>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    </html>
Run Code Online (Sandbox Code Playgroud)