Уроки, алгоритмы, программы, примеры

Вход на сайт

Материалы по разделам

Построения
на плоскости (2D)
Графика
в пространстве (3D)
Вычислительная
геометрия
Физическое
моделирование
Фрактальная
графика

Новые комментарии

Спасибо за статью. Я не Ваш студент. Но мне она помогла написать функцию для Канторова множества на Python для черепашки: import turtle def kanter(x, y, d):     if d > 1:         turtle...
Как реализовать в данном примере границы расчёта?

Счетчики и рейтинг

Рейтинг@Mail.ru Яндекс.Метрика
Среда программирования: 
HTML 5 + JavaScript

Для реализации анимации в canvas для начала необходимо добавить canvas:D
Делается это след. образом:

<!DOCTYPE HTML>
<html>	
	<head>
		<meta charset = "utf-8">
		<title>Чисто Canvas</title>
	</head>
	<body>
		<div align = "center">
			<canvas width = "800px" height = "600px" style = "border: 1px solid black"></canvas>
		</div>
		<script>
			let ctx = document.querySelector("canvas").getContext("2d"); //Получаем контекст
		</script>
	</body>
</html>

Что мы получили:

Теперь мы можем с ним работать. Взаимодействовать с ним будем только через JavaScript.
При создании каких-либо анимаций желательно разделять логику и рендер. Для этого создадим четыре функции: play, render, update и requestAnimFrame. В update мы будем просчитывать координаты анимируемых объектов, проверять их на столкновения и пр., а через render мы будем отображать все необходимые объекты на холсте. Функция play поочередно вызовет render, update и requestAnimFrame, после чего завершит свою работу. Когда браузер в очередной раз будет готов обновить кадр, функция requestAnimFrame снова вызовет функцию play. Последовательность этих действий будет повторяться, пока мы их сами каким-либо образом не прервем. Реализация функции requestAnimFrame будет разобрана в конце урока.
let ctx = document.querySelector("canvas").getContext("2d"); //Получаем контекст
function play(){
	update();
	render();
        //После того, как функция Play завершит свою работу, нам необходимо, чтоб через некоторое время(один кадр) она снова вызвалась. Для этого мы и прописываем следующую строчку
        requestAnimFrame(play);
}
function update(){
}
function render(){
}
var requestAnimFrame = (function() {
	return window.requestAnimationFrame ||
	window.webkitRequestAnimationFrame ||
	window.mozRequestAnimationFrame ||
	window.oRequestAnimationFrame ||
	window.msRequestAnimationFrame ||
	function(callback) {
		window.setTimeout(callback, 50);
	};
})();
play(); 

Теперь, создадим глобальный объект, который будет содержать в себе информацию о фигуре, которую мы будем анимировать, добавив его в самое начало JavaScript кода. Пусть это будет квадрат.
var sqr = {
	x: 0,
	y: 0,
	sizeX: 50,
	sizeY: 50
}

Отобразим же его с:
Для этого достаточно в render закинуть метод fillRect с необходимыми аргументами. ctx.fillRect(x1, y1, a, b) отобразит прямоугольную область на холсте в координатах x1, y1, размером a*b. Нам же необходимо отобразить квадрат размером sqr.sizeX* sqr.sizeY в координатах sqr.x, sqr.y.
function render(){
	ctx.fillRect(sqr.x, sqr.y, sqr.sizeX, sqr.sizeY);
}

Результат:

Попробуем его анимировать. Для этого в update необходимо менять его координаты каждый кадр, а в render очищать холст перед каждой прорисовкой, стирая квадрат со своих старых позиций.
function update(){
	sqr.x++;
}
function render(){
	ctx.clearRect(0, 0, 800, 600);
	ctx.fillRect(sqr.x, sqr.y, sqr.sizeX, sqr.sizeY);
}

Теперь наш квадрат медленно ползет вправо со скоростью 1px/кадр. Для более гибкого и удобного управления анимациями скорость желательно так же задавать внутри объектов описывающих какие-либо элементы.
Как будет выглядеть наш скрипт целиком:
var sqr = {
	x: 0,
	y: 0,
	dx: 1, //Скорость по x
	dy: 0, //Скорость по y
	sizeX: 50,
	sizeY: 50
}
function play(){
	update();
	render();
	requestAnimFrame(play);
}
function update(dt){
	sqr.x += sqr.dx;
	sqr.y += sqr.dy;
}
function render(){
	ctx.clearRect(0, 0, 800, 600);
	ctx.fillRect(sqr.x, sqr.y, sqr.sizeX, sqr.sizeY);
}
var requestAnimFrame = (function() {
	return window.requestAnimationFrame ||
	window.webkitRequestAnimationFrame ||
	window.mozRequestAnimationFrame ||
	window.oRequestAnimationFrame ||
	window.msRequestAnimationFrame ||
	function(callback) {
		window.setTimeout(callback, 50);
	};
})();
play();

Осталась одна проблема, которую желательно устранить. Анимация на разных устройствах воспроизводиться с разной скоростью, в зависимости от частоты кадров. Нам нужно эту зависимость устранить, но оставить обновление экрана покадровым.
Для этого введем несколько переменных (lost, new, dt), для вычисления времени (в секундах) , которое прошло с момента последнего вызова update (будет храниться в переменной dt). Саму же dt мы будем передавать в update для дальнейшей работы с ним. Так же, перед вызовом play нам нужно будет задать базовое значение переменной lost.
let last;
function play(){
	let now = Date.now();
	let dt = (now - last)/1000;
	update(dt);
	render();
	requestAnimFrame(play);
	last = now;
}

last = Date.now();
play();

После этого мы можем задать зависимость положения объекта от его скорости и времени в update.
sqr.x += sqr.dx*dt;
sqr.y += sqr.dy*dt;

Теперь наш объект двигается со скоростью 1px/сек.

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

function(){
//код
}

Эту функцию оборачиваем в круглые скобки, чтобы тут же ее вызывать, а то, что она вернет -- положить в переменную requestAnimFrame.
requestAnimFrame = (function(){
//код
})();

В реализации нашей анимации анонимная функция возвращает ссылку на метод и мы ее кладем в переменную requestAnimFrame, после чего мы можем вызывать метод, на которую была возвращена ссылка через эту переменную.
Остается вопрос, какой метод возвращается анонимной функцией?
Тот, что определен. Нам нужен любой метод из след. списка:
window.requestAnimationFrame()
window.webkitRequestAnimationFrame()
window.mozRequestAnimationFrame()
window.oRequestAnimationFrame()
window.msRequestAnimationFrame()
И на случай, если ни один из этих методов не поддерживается браузером -- возвращаем ссылку на анонимную функцию, которая дает схожий эффект:
function(callback) {
window.setTimeout(callback, 50);
};
И чтобы вернуть первый попавшийся метод, который определен, достаточно написать строку вида:
return метод1 || метод2 || метод3 || ... || методN
Посмотрим еще раз на готовую реализацию.
var requestAnimFrame = (function() {
	return window.requestAnimationFrame ||
	window.webkitRequestAnimationFrame ||
	window.mozRequestAnimationFrame ||
	window.oRequestAnimationFrame ||
	window.msRequestAnimationFrame ||
	function(callback) {
		window.setTimeout(callback, 50);
	};
})();

На этом все. Надеюсь, этот урок оказался полезным для Вас.