Работа с частицами в Canvas

29 Июня 2014 4645 , ,


В продолжении темы разработки Арканоида, захотелось сделать какой-нибудь эффект разрыва блока при его уничтожении, для этого необходимо освоиться с работой частиц в canvas. Как работать с Canvas частицами сегодня и пойдет речь.

Чистый холст

Поскольку canvas изначально поддерживается большим количеством браузеров, у нас нет необходимости в каких-то дополнительных приготовлениях, мы просто создадим новый холст.

1
 <canvas id="example" width="200" height="200"> Ваш браузер не поддерживает canvas. </canvas>

Кроме того, canavas можно добавить на страницу с помощью javascript

1
2
3
4
5
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
canvas.width = 200;
canvas.height = 200;
document.body.appendChild(canvas);

Пока мы ничего не видим, но это не беда. Давайте продолжим писать наш код и начнем рисовать на canvas’е, мы уже создали context и будем использовать его далее.

1
 context.fillRect(0, 0, canvas.width, canvas.height);

Мы просто рисуем прямоугольник с координатами начала canvas’а и во всю ширину холста.

Представление частицы

Теперь давайте добавим частицу на наш холст и начнем проводить манипуляции уже с ней.

1
2
3
// Рисуем частицу
context.fillStyle = "white";
context.fillRect(300, 200, 10, 10);

Теперь мы будем рисовать частицу с помощью метода fillRect, вы можете указать частицу в форме круга или вовсе нужного вам рисунка. В предыдущем коде мы рисовали на канвасе во весь холст прямоугольник, но не указывали fillStyle, когда данный параметр не указан, стиль заливки по умолчанию будет черным. Пример отрисовки круглой частицы

1
2
3
4
5
6
//Рисуем круглую частицу на холсте
context.beginPath();
context.fillStyle = "white";
context.arc(500, 200, 10, 0, Math.PI*2, true);
context.closePath();
context.fill();

Движение частицы

Перемещение объектов на canvas’е происходит не совсем так, как обычных html элементов таких как div. Иллюзия перемещения создается с помощью покадровой перерисовки холста и предварительным очищением холста перед рисованием нового кадра. Для этого чаще всего используется функция requestAnimationFrame() или функции setTimeout или setInterval. Давайте продолжим расширять наш код и я приведу у дальнейший пример, для начала мы должны установить позицию частицы как переменные, чтобы в дальнейшем мы могли ее передвигать.

1
 var posX = 20, posY = 100;

Далее дополним наш код и добавим setInterval перерисовки холста

1
2
3
4
5
6
7
8
9
10
11
12
// Рисуем частицу на холсте с интервалом в 30ms
setInterval(function() {
//Очищаем canvas context.fillStyle = "black";
context.fillRect(0,0,canvas.width, canvas.height);
posX += 1;
//На каждой итерации меняем позиции X и Y
posY += 0.25;
// Рисуем частицу
context.beginPath();
context.fillStyle = "white";
context.arc(posX, posY, 10, 0, Math.PI*2, true);
context.closePath(); context.fill(); }, 30);

 

Физика и случайности

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

1
2
3
var vx = 10,
vy = -10,
gravity = 1;

Теперь векторная скорость говорит нам о том, что каждую итерацию (30мс) частица будет перемещаться на 10 пикселей вправо и 10 пикселей в низ. Теперь давайте заменим часть кода в нашем примере и добавим движение с прибавлением векторной скорости и прибавлением гравитации в векторной скорости по вертикали

1
2
3
posX + vx;
poxY + vY;
posY + gravity;

Отскок

Для того, чтобы частицы не падали и имели некий отскок, мы можем дополнить логику и «переворачивать» (флиповать) векторную скорость по оси Y и домножать на произвольный коофицент отскока.

1
2
3
4
if (posY > canvas.height * 0.75) {
vy *= -0.6; vx *= 0.75;
posY = canvas.height * 0.75;
}

Если положение частицы ниже чем две трети (*0.75) холста, то мы домножаем отскок на 60% (т.е. каждый следующий отскок будет ниже на 40%) в тоже время мы замедляем на 25% скорость по горизонтали при каждом отскоке.

Хаотичность

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

Создание частиц

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

1
 var particles = {}, particleIndex = 0, settings = { density: 20, particleSize: 10, startingX: canvas.width / 2, startingY: canvas.height / 4, gravity: 0.5, maxLife: 100 };

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Particle() {

// Устанавливаем позицию согласно настройкам

this.x = settings.startingX;
this.y = settings.startingY;

// Случайные X и Y скорости

this.vx = Math.random() * 20 - 10;
this.vy = Math.random() * 20 - 5;

//Увеличиваем индекс и добавляем частицу с новым индексом.

particleIndex ++; particles[particleIndex] = this;
this.id = particleIndex; this.life = 0;

}

Рисование множества частиц

Теперь для рисования мы должны расширить наш объект Particle и добавим в prototype метод draw

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Particle.prototype.draw = function() {

this.x += this.vx;
this.y += this.vy;

// Добавляем гравитацию

this.vy += settings.gravity;

// Отсчитываем жизнь

this.life++;

// Если жизнь частицы больше максимальной - удаляем

if (this.life >= settings.maxLife) { delete particles[this.id]; }

// Рисуем частицу

context.clearRect(settings.leftWall, settings.groundLevel, canvas.width, canvas.height);
context.beginPath();
context.fillStyle="#ffffff";
context.arc(this.x, this.y, settings.particleSize, 0, Math.PI*2, true); context.closePath(); context.fill();

}

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

Подписывайтесь на обновления

Читайте RSS ленту

Комментарии

Добавить комментарий