Почему мои частицы ускоряются, когда я нажимаю кнопку в JavaScript? - PullRequest
2 голосов
/ 30 сентября 2019

Я делаю пусковую установку для конфетти, которая создает квадраты и размещает их в верхней части экрана, каждый из которых имеет определенную силу тяжести и направление в сторону. У меня есть кнопка, которая делает 100 из них одновременно. Однако каждый раз, когда я нажимаю кнопку, она создает новые, но также ускоряет движение существующих квадратов.

var width1 = window.innerWidth || document.documentElement.clientWidth ||
  document.body.clientWidth;
var height1 = window.innerHeight || document.documentElement.clientHeight ||
  document.body.clientHeight;
let canvas = document.getElementById('confetti');
let ctx = canvas.getContext('2d');
canvas.width = width1;
canvas.height = height1;
let pieces = [];
let numberOfPieces = 100;
let lastUpdateTime = Date.now();
var a = 0;
var intervalID;

function randomColor() {
  let colors = ['#999999ff', '#b7b7b7ff', '	#D3D3D3', '#ffff00 ', '#d9d9d9ff'];
  return colors[Math.floor(Math.random() * colors.length)];
}

function update() {
  let now = Date.now(),
    dt = now - lastUpdateTime;

  for (let i = pieces.length - 1; i >= 0; i--) {
    let p = pieces[i];

    if (p.y > canvas.height) {
      pieces.splice(i, 1);
      continue;
    }

    p.y += p.gravity * dt;
    p.rotation += p.rotationSpeed * dt;
    p.x += p.direction;
  }


  if (pieces.length < numberOfPieces) {
    for (var b = pieces.length; b < numberOfPieces; b++) {
      pieces.push(new Piece(Math.random() * canvas.width, -20));
      b--;
      numberOfPieces--;
    }
  }
  lastUpdateTime = now;
  a++;
  if (a >= 1) {
    numberOfPieces = 0;
    //console.log("number of pieces: " + numberOfPieces + " pieces.length: " + pieces.length);
  }
}

function draw() {

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  pieces.forEach(function(p) {
    ctx.save();

    ctx.fillStyle = p.color;

    ctx.translate(p.x + p.size / 2, p.y + p.size / 2);
    ctx.rotate(p.rotation);

    ctx.fillRect(-p.size / 2, -p.size / 2, p.size, p.size);

    ctx.restore();
  });

  requestAnimationFrame(draw);
}

function Piece(x, y) {
  this.x = x;
  this.y = y;
  this.size = (Math.random() * 0.5 + 0.75) * 15;
  this.gravity = (Math.random() * 0.5 + 0.75) * 0.15;
  var c = Math.random()
  if (c > 0.5) {
    this.direction = -(Math.random() * 0.6);
  } else {
    this.direction = (Math.random() * 0.6);
  }
  this.rotation = (Math.PI * 2) * Math.random();
  this.rotationSpeed = (Math.PI * 2) * (Math.random() - 0.5) * 0.0005;
  this.color = randomColor();
}

while (pieces.length < numberOfPieces) {
  pieces.push(new Piece(Math.random() * canvas.width, Math.random() * canvas.height));
}
var bye = 0;

function myfunction() {
  var hello = Date.now();

  var difference = hello - bye;
  if (difference > 1000) {
    a = 0;
    numberOfPieces = pieces.length + 100;

    intervalID = setInterval(update, 30);
    draw();
    bye = Date.now();
  }

}
<canvas id="confetti"></canvas>
<button style="float: right; border: 1px blue solid; width: 100px; height: 100px;" onclick="myfunction()">Click me</button>

1 Ответ

2 голосов
/ 30 сентября 2019

Исправления в порядке важности:

  • Запустите ваш двигатель только один раз! (не при каждом нажатии. PS: вы не очищали свой интервал)
  • Удалить setInterval, вы уже используете requestAnimationFrame() в качестве двигателя
  • Производительность мудро, создать pieces = {} Объект (вместо Массива) и при создании магазина внутри ваших фигур на this.id (просто случайное число)
  • Удалите метод draw(). Вместо создайте this.draw() метод для каждого confetto .
  • Поместите вашу логику удаления в метод this.draw(). Чтобы удалить часть из нашего pieces объекта - просто используйте delete pieces[this.id]
  • Добавьте логику, чтобы также удалить часть из pieces объекта - если он выходит из левого / правого холстаребра
  • Внутри вашего движка просто зациклите pieces и вызовите метод .draw() каждого элемента.
  • Нет необходимости передавать аргументы конструктору Piece. Сохраняйте это простым и просто используйте new Piece();
  • Создайте многократно используемую функцию rnd(min, max), чтобы вернуть значение с плавающей запятой от min до max (исключено)
  • Удалите ненужные переменные (например, a или lastUpdateTime)
  • Удалите ненужные while неработающие циклы инициализации.
  • Переименуйте myfunction() во что-то значимое, то есть: createConfetti()
  • Поместите colors Array в "root" scope. Это ваши статические значения.
  • Используйте Element.addEventListener() вместо встроенного JavaScript, например onclick.
  • Знайте разницу между const и let и используйте соответственно. Вам не нужно var больше.

Вот пример:

const width1 = window.innerWidth || document.documentElement.clientWidth ||
  document.body.clientWidth;
const height1 = window.innerHeight || document.documentElement.clientHeight ||
  document.body.clientHeight;
const canvas = document.getElementById('confetti');
const ctx = canvas.getContext('2d');
const pieces = {}; // For better delete performance
const numberOfPieces = 100;
const colors = ['#999999', '#b7b7b7', '#D3D3D3', '#f48024', '#d9d9d9'];
const rnd = (min, max) => Math.random() * (max - min) + min;

let bye = 0;

canvas.width = width1;
canvas.height = height1;

function Piece() {
  this.id = rnd(0, 1e3);
  this.g = rnd(0.7, 2);
  this.w = rnd(5, 25);
  this.x = rnd(0, canvas.width);
  this.y = -this.w;
  this.dir = rnd(0, 1) > 0.5 ? rnd(0, 0.5) : -rnd(0, 0.5);
  this.r = rnd(1, 8);
  this.rSpeed = rnd(1, 5) * 0.01;
  this.color = colors[~~rnd(0, colors.length)];
  this.draw = () => {
    if (this.y > canvas.height || this.x < -this.w || this.x > canvas.width + this.w) {
      delete pieces[this.id];
      return;
    }
    this.y += this.g;
    this.r += this.rSpeed;
    this.x += this.dir;
    ctx.save();
    ctx.fillStyle = this.color;
    ctx.translate(this.x + this.w / 2, this.y + this.w / 2);
    ctx.rotate(this.r);
    ctx.fillRect(-this.w / 2, -this.w / 2, this.w, this.w);
    ctx.restore();
  }
  // populate into object
  pieces[this.id] = this;
}

function createConfetti() {
  const hi = Date.now();
  if (hi - bye <= 1000) return;
  bye = hi;
  // Populate pieces array
  let i = numberOfPieces;
  while (i) {
    new Piece();
    i--;
  }
}

function engine() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  const piecesIDs = Object.keys(pieces);
  if (piecesIDs.length) {
    piecesIDs.forEach(id => pieces[id].draw());
  }
  requestAnimationFrame(engine);
}

engine(); // Start engine once! Not on every click
document.querySelector('#createConfetti').addEventListener('click', createConfetti);
* { margin:0; }
button { z-index:1; position:absolute; }
#confetti { display:block; }
<button id="createConfetti">Click me</button>
<canvas id="confetti"></canvas>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...