strokoff

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


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

Чистый холст

Поскольку canvas изначально поддерживается большим количеством браузеров, у нас нет необходимости в каких-то дополнительных приготовлениях, мы просто создадим новый холст. [cce lang=»html»] Ваш браузер не поддерживает canvas. [/cce] Кроме того, canavas можно добавить на страницу с помощью javascript

[cce lang=»javascript»]

var canvas = document.createElement(«canvas»);
var context = canvas.getContext(«2d»);
canvas.width = 200;
canvas.height = 200;
document.body.appendChild(canvas);

[/cce] Пока мы ничего не видим, но это не беда. Давайте продолжим писать наш код и начнем рисовать на canvas’е, мы уже создали context и будем использовать его далее. [cce lang=»javascript»] context.fillRect(0, 0, canvas.width, canvas.height); [/cce] Мы просто рисуем прямоугольник с координатами начала canvas’а и во всю ширину холста.

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

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

[cce lang=»javascript»]

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

[/cce]

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

[cce lang=»javascript»]

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

[/cce]

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

Перемещение объектов на canvas’е происходит не совсем так, как обычных html элементов таких как div. Иллюзия перемещения создается с помощью покадровой перерисовки холста и предварительным очищением холста перед рисованием нового кадра. Для этого чаще всего используется функция requestAnimationFrame() или функции setTimeout или setInterval. Давайте продолжим расширять наш код и я приведу у дальнейший пример, для начала мы должны установить позицию частицы как переменные, чтобы в дальнейшем мы могли ее передвигать. [cce lang=»javascript»] var posX = 20, posY = 100; [/cce] Далее дополним наш код и добавим setInterval перерисовки холста

[cce lang=»javascript»]

// Рисуем частицу на холсте с интервалом в 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);

[/cce]

 

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

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

[cce lang=»javascript»]

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

[/cce]

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

posX + vx;
poxY + vY;
posY + gravity;

[/cce]

Отскок

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

[cce lang=»javascript»]

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

[/cce]

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

Хаотичность

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

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

Теперь нам необходимо расширить наш код и оптимизировать его для создания множества частиц. Для этого мы создадим функцию с именем Particle, которая будет создавать частицу и служить в роли генератора частиц, а также манипулировать ими. Также нам необходимо реализовать логику хаотичного перемещения для каждой частицы в отдельности. Первым делом вынесем все настройки будущих частиц в один объект. [cce lang=»javascript»] var particles = {}, particleIndex = 0, settings = { density: 20, particleSize: 10, startingX: canvas.width / 2, startingY: canvas.height / 4, gravity: 0.5, maxLife: 100 }; [/cce] Мы определили пустой объект Particles в котором мы будем хранить частицы, создали переменную для индекса и объект с настройками размера, стартовой позиции, гравитации и жизни. В место того, чтобы хранить частицы в массиве, мы будем использовать объект т.к. далее будет проще работать с ключами, а не с индексами. Вот функция, которая будет генерировать частицу.

[cce lang=»javascript»]

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;

}

[/cce]

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

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

[cce lang=»javascript»]

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();

}

[/cce]

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


Последняя редакция 11 октября, 2014 в 12:10