Эмуляция физики в JavaScript (Часть 1)

от автора

Признание: На самом деле я не очень хорошо знаю физику. Сказать, что я обладаю базовыми знаниями – это сильно преувеличить. Последний раз я знала что-то достаточно сложное по физике 11 лет назад. Мне было 17, и я знала ровно столько, чтобы получить твердую четверку на выпускных экзаменах в школе, после которых я немедленно выкинула всю эту информацию из своей головы, чтобы освободить место для более важных вещей, таких как тексты песен из альбома «Nellyville» Nelly.

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

Банальная физика

Мне нравится называть это банальной физикой, так как мы используем очень базовое понимание векторов и пишем JavaScript, который в какой-то мере воспроизводит эти векторы, но никоим образом не представляет собой реальную физическую среду. Преимущество банальной физики заключается в том, что вам на самом деле даже не нужно понимать теорию физики за ее пределами. Вам нужно понимать только то, как ее использовать для анимации.

Векторы

Вектор – это математический объект, характеризующийся величиной и направлением. Скорость и ускорение – это векторы. Если вы скажете, что собираетесь ехать в северо-восточном направлении со скоростью 35 миль в час, вы опишете вектор.

Создаем скорость с помощью JavaScript

Наверняка, вы уже знаете, что такое скорость, но я все равно вам расскажу. Вектор скорости – это вектор, который состоит из скорости и направления. Когда мы воспроизводим скорость в JavaScript, мы делим ее на два вектора – скорость в направлении x и скорость в направлении y. Здесь мы имеем дело с пикселями и анимацией JavaScript, поэтому мы можем описать нашу скорость с точки зрения количества пикселей в кадр. Квадрату в примере присвоена скорость в направлении х в размере 2 пикселей на каждый кадр, и скорость в направлении y в размере 2 пикселей на каждый кадр. В результате мы получаем линейное диагональное движение.

var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var width = canvas.width = window.innerWidth; var height = canvas.height = window.innerHeight;  // position var x = 0; var y = 0; // velocity var vx = 2; var vy = 2;  // animation loop function animate() {   // clear canvas   ctx.clearRect(0, 0, width, height);   // draw square   ctx.fillRect(x,y,20,20);      // update position with velocity   x += vx;   y += vy;   requestAnimationFrame(animate);      // if square is out of view reset position to the start   if (y > height || x > width) {     x = 0;     y = 0;   } }  animate(); 

Создаем ускорение с JavaScript

Ускорение – это коэффициент изменения скорости объекта. И как же мы воспроизводим это в JavaScript? У нас есть скорость vx и vy, и мы можем добавить ускорение в направлении x или y в каждом кадре. То есть, если ускорение равно 0,5 пикселей, мы добавим 0,5 пикселя к скорости x и скорости y в каждом кадре. Это заставит наш квадратик ускориться.

Невероятно простой и забавный пример – давайте сделаем фонтан из частиц!

Фонтан из частиц – это первый эффект банальной физики, который я анимировала. В частности, я сделала его с помощью Flash и ActionScript, но сейчас мы можем сделать это с JavaScript и канвой. По сути, я планирую использовать объект «частица» для создания фонтана.

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

function Particle(x, y, vx, vy, size, color, opacity) {    this.update = function() {     x += vx;     y += vy;   }    this.draw = function() {     ctx.globalAlpha = opacity;     ctx.fillStyle = color;     ctx.fillRect(x, y, size, size);   }  }  function createParticle(i) {   // initial position in middle of canvas   var x = width*0.5;   var y = height*0.5;   // randomize the vx and vy a little - but we still want them flying 'up' and 'out'   var vx = -2+Math.random()*4;   var vy = Math.random()*-3;   // randomize size and opacity a little & pick a color from our color palette   var size = 5+Math.random()*5;   var color = colors[i%colors.length];   var opacity =  0.5 + Math.random()*0.5;   var p = new Particle(x, y, vx, vy, size, color, opacity);   particles.push(p); } 

В результате должно получиться что-то вроде этого (возможно, вам придется нажать «rerun», чтобы их увидеть).

Частицы просто распыляются вверх и никогда не падают вниз. Нам нужно добавить немного «силы притяжения», чтобы заставить частицы падать. Мы уже знаем, как это сделать, потому что силу притяжения, по сути, можно воспроизвести с помощью ускорения в направлении y (вниз). Давайте установим значение силы притяжения (ускорения) равное 0,04 пикселя. Также мы немного уменьшим прозрачность каждого кадра, чтобы каждая частица в результате растворялась. После этого мы сделаем нулевую прозрачность в точке, в которой мы будем «возвращать» нашу частицу в центр фонтана.

Листинг результата

var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var width = canvas.width = window.innerWidth; var height = canvas.height = window.innerHeight; var particles = []; var colors = ['#029DAF', '#E5D599', '#FFC219', '#F07C19', '#E32551']; var gravity = 0.04;  function initParticles() {   for (var i = 0; i < 200; i++) {     setTimeout(createParticle, 20*i, i);   } }  function createParticle(i) {   // initial position in middle of canvas   var x = width*0.5;   var y = height*0.5;   // randomize the vx and vy a little - but we still want them flying 'up' and 'out'   var vx = -2+Math.random()*4;   var vy = Math.random()*-3;   // randomize size and opacity a little & pick a color from our color palette   var size = 5+Math.random()*5;   var color = colors[i%colors.length];   var opacity =  0.5 + Math.random()*0.5;   var p = new Particle(x, y, vx, vy, size, color, opacity);   particles.push(p); }  function Particle(x, y, vx, vy, size, color, opacity) {      function reset() {     x = width*0.5;     y = height*0.5;     opacity = 0.5 + Math.random()*0.5;     vx = -2+Math.random()*4;     vy = Math.random()*-3;   }      this.update = function() {     // if a particle has faded to nothing we can reset it to the starting position     if (opacity - 0.005 > 0) opacity -= 0.005 ;     else reset();          // add gravity to vy     vy += gravity;     x += vx;     y += vy;   }      this.draw = function() {     ctx.globalAlpha = opacity;     ctx.fillStyle = color;     ctx.fillRect(x, y, size, size);   }  }  function render() {   ctx.clearRect(0, 0, width, height);   for (var i = 0; i < particles.length; i++) {     particles[i].update();     particles[i].draw();   }   requestAnimationFrame(render); }   // resize window.addEventListener('resize', resize); function resize() {   width = canvas.width = window.innerWidth;   height = canvas.height = window.innerHeight; }   // init initParticles(); render(); 

Таким образом, у нас получится бесконечный фонтан частиц!

ссылка на оригинал статьи http://habrahabr.ru/post/262099/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *