Анімація через requestAnimationFrame
Тепер, коли ми знаємо, як намалювати багато цікавих штук, давайте оживимо їх. Перше, що потрібно знати про анімацію — це просто малювання одного і того ж знову і знову. Коли ви викликаєте функцію малювання, вона відразу ж додає щось на екран. Якщо ви хочете анімувати це, просто зачекайте кілька мілісекунд та намалюйте це заново. Звичайно, ви не хочете сидіти в очікуванні, поки цикл не перерветься браузером. Натомість ви повинні намалювати щось, потім попросити браузер викликати це знову через кілька мілісекунд. Найпростіший спосіб зробити це за допомогою функції JavaScript setInterval(). Вона буде викликати вашу функцію малювання кожні N мс.
Однак насправді ми ніколи не повинні використовувати setInterval. setInterval завжди буде малювати з однією швидкістю, незалежно від того, який у користувача комп'ютер, що робить користувач і чи активна поточна сторінка. Коротше кажучи, це працює, але не ефективно. Натомість ми повинні використовувати новий API requestAnimationFrame.
requestAnimationFrame був створений, щоб зробити анімацію плавною та ефективною у плані витрат. Ви викликаєте її з вказівником на функцію малювання. Якийсь момент у майбутньому браузер викличе вашу функцію малювання, коли браузер виявиться готовим. Це дає браузеру повний контроль над малюванням, тому він може знизити частоту кадрів при необхідності. Браузер також може зробити анімацію плавнішою, зафіксувавши частоту оновлення екрана на 60 кадрах в сек. Щоб зациклити анімацію, просто викличте requestAnimationFrame рекурсивно на початку.
requestAnimationFrame стає стандартом, але більшість браузерів підтримує тільки свої власні версії із префіксом. Наприклад, Chrome використовує webkitRequestAnimationFrame, а Mozilla підтримує mozRequestAnimationFrame. Щоб виправити це, ми скористаємося скриптом Пола Іріша. Він просто поєднує різні варіанти в новій функції: requestAnimFrame.
<code data-language="javascript">//setTimeout як запасний варіант window.requestAnimFrame=(function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function( callback){ })();
Спробуємо простий приклад, в якому ми анімуємо прямокутник на екрані.
Базова анімація прямокутник за допомогою requestAnimFrame (клацніть для запуску)
Очищення фону
Тепер ви помітили проблему. Наша прямокутник рухається по екрану, оновлюючись на п'ять пікселів через кожні 100 мілісекунд (або 10 кадрів в сек.), але старий прямокутник залишається. І виглядає так, що прямокутник стає лише довшим та довшим. Пам'ятайте, що це полотно просто набір пікселів. Якщо ви встановите кілька пікселів, то вони залишатимуться там доти, доки не зміняться. Отже, давайте очистимо полотно у кожному кадрі, перш ніж ми намалюємо прямокутник.
<code data-language="javascript">var x=0; function drawIt() { window.requestAnimFrame(drawIt); var canvas=document.getElementById('canvas'); var c=canvas.getContext('2d'); c.clearRect(0,0,canvas.width,canvas.height); c.fillStyle="red"; c.fillRect(x,100,200,100); x+=5; } window.requestAnimFrame(drawIt);
Малювання прямокутника через очищення фону (клацніть для запуску)
Симулятор частинок
Це все, що насправді потрібне для анімації. Малювати щось знову і знову. Спробуємо щось більш складне: симулятор частинок. Ми хочемо, щоб деякі частинки падали вниз по екрану подібно до снігу. Для цього ми реалізуємо класичний алгоритм симулятора частинок:
Симулятор частинок містить список зациклених частинок. У кожному кадрі положення всіх частинок оновлюється ґрунтуючись на деякому рівнянні, при необхідності частинки знищуються/створюються на основі певної умови. Потім частки малюються. Ось простий приклад снігу.
<code data-language="javascript">var canvas=document.getElementById('canvas'); var particles=[]; function loop() { window.requestAnimFrame(loop); createParticles(); updateParticles(); killParticles(); drawParticles(); } window.requestAnimFrame(loop);
Спочатку ми створюємо основу симулятора частинок. Це функція циклу, яка викликається кожні 30 мс. Для структури даних нам потрібен порожній масив частинок та лічильник тактів. На кожній ітерації циклу виконується чотири частини. .push({ x: Math.random()*canvas.width, //між 0 і шириною полотна y: 0, speed: 2+Math.random()*3, //між 2 та 5 radius: 5+Math .random()*5, //між 5 і 10 color: "white", }); } }
Функція createParticles перевіряє, скільки у нас часток. Якщо їх менше 100, створює нову частинку. Зверніть увагу, що перевірка виконується лише кожні 10 такт. Це дозволяє почати з порожнього екрану, а потім поступово нарощувати число частинок, а не створювати всі 100 з самого початку. Ви можете настроїти параметри залежно від бажаного ефекту. Я використовую Math.random() та іншу арифметику, щоб переконатися, що сніжинки розташовуються в різних місцях і не виглядають однаковими. Так сніг стає більш натуральним. part.y +=part.speed; } }
Функція updateParticles досить проста. Вона оновлює координату кожної частки, додаючи їй швидкість. Це змушує сніжинку рухатися вниз по екрану. if(part.y > canvas.height) { part.y=0; } } }
Ось killParticles. Вона перевіряє, що частка знаходиться нижче нижнього краю полотна. У деяких симуляторах ви знищуєте частинку та видаляєте її зі списку. Оскільки ця програма показує безперервний сніг, то ми повторно задіємо частинку, встановивши її назад в 0.
'); c.fillStyle="black"; c.fillRect(0,0,canvas.width,canvas.height); for(var i in particles) { var part=particles[i]; c.beginPath(); c.arc(part.x,part.y, part.radius, 0, Math.PI*2); c.closePath(); c.fillStyle=part.color; c.fill(); } }
Нарешті малюємо частинки. Знову ж таки це дуже просто: очистіть фон, намалюйте коло з поточними координатами, радіусом і кольором частинки. Тепер це виглядає так.
Симулятор частинок для снігу (клацніть для запуску)
Ось за що я люблю симулятори частинок, так це за те, що ви можете створити дуже складну і органічну, природно виглядаючу анімацію з досить простою математикою , у поєднанні з невеликою керованою випадковістю.
Анімація спрайтів
Що таке спрайт?
Заключним основним видом анімації є анімація спрайту. Що таке спрайт?
Спрайт — це маленьке зображення, яке ви можете швидко малювати на екрані. Зазвичай спрайт на ділі вирізують із великого зображення, яке називається спрайт-лист або майстер-зображення. Такий лист може містити кілька різних спрайтів, на кшталт різних персонажів гри. Спрайт-лист також може містити один символ у різних положеннях. У результаті це дає різні кадри анімації. Це класичний стиль анімації: просто прогортати різні малюнки знову і знову. Навіщо і коли використовувати спрайти? Спрайти хороші для кількох речей.
-перше, спрайт це зображення, яке, ймовірно, малюється швидше, ніж вектори, особливо складні. По-друге, спрайти надзвичайно зручні, коли вам потрібно малювати одну штуку знову і знову. Наприклад, у грі Space Invaders у вас є купа куль на екрані, які виглядають однаково. Набагато швидше завантажити спрайт кулі один раз і малювати його знову і знову.
Малювання спрайтів
Спрайти легко намалювати, використовуючи функцію drawImage. Ця функція може малювати та розтягувати частину зображення шляхом вказівки різних вихідних та кінцевих координат. Припустимо, що у нас є наступний спрайт-лист і ми просто хочемо намалювати п'ятий спрайт зліва.
Ми можемо намалювати лише цей спрайт, вказавши координати вихідного коду:
<code data-language="javascript">context.drawImage( img, //зображення спрайт-листа 65,0,13,13, //вихідні координати (x, y, w, h) 0,0,13,13, //кінцеві координати (x, y, w, h));
Анімація спрайту
Як ви можете бачити на повному спрайт-листі, насправді це різні кадри анімації одного об'єкта, так що тепер прогортаємо різні спрайти, щоб створити анімацію. Ми зробимо це, відстежуючи поточний кадр за допомогою лічильника тактів.
<code data-language="javascript">var frame=tick % 10; var x=frame * 13; context.drawImage( img, //зображення спрайт-листа x,0,13,13, //вихідні координати (x, y, w, h) 0,0,13,13, //кінцеві координати (x, y, w,h)); tick++;
Кожен раз при оновленні екран ми обчислюємо поточний кадр анімації дивлячись на лічильник тактів. Операція поділу за модулем (%) на 10 означає зациклити кадр від 0 до 9 знову і знову. Потім обчислюється координата x в залежності від кількості кадрів. Після чого малюється зображення та оновлюється лічильник тактів. Звичайно, це може відбуватися занадто швидко, так що ви можете ділити такти за модулем на 2 або 3, щоб анімація бігла повільніше.
Анімація кожні 10 кадрів для деталізації (клацніть для запуску)
У наступному розділі ми створимо просту гру, в якій демонструється, як використовувати базову анімацію, анімацію спрайтів, події клавіатури та простий симулятор частинок вибухів.