Как оптимизировать систему частиц canvas с объектами частиц

#javascript #jquery #canvas

#javascript #jquery #холст

Вопрос:

итак, я создал простую систему частиц с canvas и javascript (немного jQuery), но, похоже, я не могу заставить ее работать со скоростью более 8 кадров в секунду на моем старом компьютере, это код:

 var starList = [];

function Star(){
    this.x = getRandomInt(0, canvas.width);
    this.y = getRandomInt(0, canvas.height);
    this.vx = getRandomInt(2,5);
    this.size = this.vx/5;
    this.opacity = getRandomInt(0, 5000) / 10000;
    this.color = getRandomFromArray(["239, 207, 174", "162, 184, 229", "255, 255, 255"]);
    this.draw = function(){
        ctx.fillStyle = "rgba(" this.color "," this.opacity ")";
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, true);
        ctx.closePath();
        ctx.fill();
    },
    this.move = function(){
        this.x = this.x - this.vx;

        if(this.x < 0) {
            this.x = canvas.width;
            this.opacity = getRandomInt(0, 5000) / 10000;
            this.color = getRandomFromArray(["239, 207, 174", "162, 184, 229", "255, 255, 255"]);
            this.y = getRandomInt(0, canvas.height);
            this.size = this.vx/5;
            this.vx = getRandomInt(2,5);
        }
    }
}

var canvas, ctx;

function setCanvas(){
    canvas = $('canvas')[0];
    ctx = canvas.getContext("2d");

    canvas.width = $(window).width()/5;
    canvas.height = $(window).height()/5;
}

setCanvas();

function generateStars(){
    for(var i = 0; i < 5000; i  ){
        var star = new Star();
        starList.push(star);
    }

    for(var i = 0; i < starList.length; i  ) {
        star = starList[i];
        star.draw();
    }
}

generateStars();

function loop() {
    window.requestAnimationFrame(loop);

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

    //draw and move stars
    for(var i = 0; i < starList.length; i  ) {
        star = starList[i];
        star.draw();
        star.move();
    }
}
  

Я предполагаю, что использование объектов для частиц (звезд) и перебор массива объектов с индексом 5000, и выполнение этих двух функций сложно для процессора / графического процессора, но как я могу оптимизировать этот код?

Я видел, что другие избегают использования функций в конструкторе, перемещают и рисуют частицы, когда они перебирают массив. Это ускорит работу?

РЕДАКТИРОВАТЬ: игнорируйте getRandomInt и подобные функции, это простые функции, которые я использую для генерации случайного материала.

Комментарии:

1. Помимо того, что это неполный список, и идеи не могут быть проверены, а просто переданы вам, очевидным моментом для поиска, по-видимому, является функция рисования. Кажется, что для рисования 5000 дуг потребуется некоторое время. Вместо этого я бы попробовал нарисовать 5000 прямоугольников. Если это намного быстрее, возможно, все же стоит нарисовать круглый прозрачный png с композицией, чтобы раскрасить его. Вычисление контура дуги будет медленным, и я бы предположил, что аппаратное ускорение не ускоряется. С другой стороны, может быть смешивание / масштабирование / раскраска изображений. Вот кое-что для синхронизации: developer.mozilla.org/en-US/docs/Web/API/Performance/now

Ответ №1:

Самая медленная часть вашего кода — это команды рисования пути:

 ctx.fillStyle = "rgba(" this.color "," this.opacity ")";
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
  

Canvas рисуется очень быстро, но 5000 рисунков займут некоторое время.

Вместо этого…

Создайте таблицу спрайтов, содержащую все вариации звезд, которые вы хотите отобразить.

Копирование пикселей из таблицы спрайтов в холст отображения выполняется намного быстрее, чем выполнение команд рисования. Это особенно верно для рисования дуг, где по окружности должно быть вычислено много точек.

Важно!

Ограничьте вариации звезд — зрители не заметят, что ваши звезды не являются бесконечно случайными.

Затем используйте обрезную версию drawimage , чтобы быстро нарисовать каждый желаемый звездный спрайт из таблицы спрайтов:

 // set the global alpha
ctx.globalAlpha = getRandomInt(0, 5000) / 10000;

// cut the desired star-sprite from the spritesheet
// and draw it on the visible canvas
ctx.drawImage( spritesheet,                             // take from the spritesheet
    this.sheetX, this.sheetY, this.width, this.height,  // at this sprite's x,y
    this.x, this.y, this.width, this.height)            // and draw sprite to canvas
  

Таблица спрайтов

Вы можете использовать второй холст в памяти в качестве таблицы спрайтов и создавать свои звездные спрайты на стороне клиента при первом запуске вашего приложения. drawImage Команда примет ваш второй холст в памяти в качестве источника изображения (!).

 var spritesheet=document.createElement('canvas');
var spriteContext=spriteSheet.getContext('2d');
...
// draw every variation of your stars on the spritesheet canvas
...