Pull to refresh

Рецепт вращения планет в космосе на HTML5 + JavaScript

Reading time 3 min
Views 38K
imageВ рамках создания нашей браузерной космической игры, перед нами стояла задача разработать простую и наименее ресурсозатратную анимацию вращения планет в звездной системе.

Вычеркиваем


После непродолжительного подбора различных способов реализации, сразу были исключены варианты:
  • с gif-анимацией (из-за низкого качества изображения);
  • с Flash (по договоренности, Flash-технологии решили в проекте не использовать);
  • с анимацией с помощью JQuery посредством функции $().animate (по причине ее прожорливости).


CANVAS в помощь!


Итак, остановились мы на использовании Canvas и JavaScript, посчитав этот вариант оптимальным для реализации нашей задачи.

Пофантазируем...

Любым доступным способом находим, рисуем или генерируем карту нашей будущей планеты. Предположим, у нас это будет экзопланета, где есть вода и растительность. Выглядеть карта нашей планеты будет примерно так:

image

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

image

image

Создаем планету

В качестве космического пространства у нас выступит блок div с любым подходящим для этого бэкграундом, а внутри разместим элемент с id=«planet»:

<div style="background-image:url(space.jpg); width:1000px; height: 1000px;">
     <canvas id="planet" width="300" height="300" style="position: absolute; left:200px; top: 200px;">
     </canvas>
</div>

Далее заставляем нашу карту двигаться внутри созданного элемента canvas, который скоро превратится в планету:

 $(function(){

        var pl_id = 'planet';

	var image = new Image();
	image.src = 'images/planets/1/1/map.jpg';

        // определяем длину и высоту элемента canvas
	var width = $('#'+pl_id).width();
	var height = $('#'+pl_id).height();

	var canvas = document.getElementById(pl_id);
	var id = canvas.getContext("2d");

	var newMoveWidth = 0;
	var newMoveHeight = 0;

	var drawPl = function(){

	     id.clearRect(0, 0, width, height);
             // рисуем карту с новыми координатами внутри элемента
	     id.drawImage(image, newMoveWidth, newMoveHeight, width, height, 0, 0, width, height); 

	     if (newMoveWidth >= 899.5) newMoveWidth = 0; // если смещение достигло предела, начинаем сначала
	     else newMoveWidth = newMoveWidth+0.5; // иначе двигаем карту дальше

	}

        setInterval(drawPl, 50); // запускаем анимацию со скоростью 50 мс.

 });

В результате произведенных действий, получаем примерно такую картину:

image

Закругляем...


Квадратных планет еще не открыли, поэтому придадим нашему небесному телу более привычный вид, прописав в style нашего элемента canvas border-radius на 50 процентов. Получаем:

image

Уже лучше, однако по-прежнему нет ощущения, что перед нами сферический объект.

Теперь подготовим в графическом редакторе круг с тенью по краям и бликами. Он должен быть обязательно полупрозрачным, т.к. мы будем накладывать его на нашу планетарную карту. В оригинале он будет выглядеть так:

image

Сейчас добавляем в нашу анимацию эффект вращения, а также, накладываем подготовленную картинку с тенями поверх карты планеты.

Финальный код нашей анимированной планеты получается таким:

<div style="background-image:url(space.jpg); width:1000px; height: 1000px;">
     <canvas id="planet" width="300" height="300" style="position: absolute; left:200px; top: 200px; border-radius:50%">   
     </canvas>
</div>

И код самой анимации:

$(function(){

        var pl_id = 'planet';

	var image = new Image();
	image.src = 'map2.jpg';

        // загружаем изображение тени и бликов планеты
	var fxShadow = new Image();
	fxShadow.src = 'planet_shadow.png';

        // определяем длину и высоту элемента canvas
	var width = $('#'+pl_id).width();
	var height = $('#'+pl_id).height();

	// рассчитываем угол вращения планеты
	var beta = 360/900;
	var beta = (beta*Math.PI)/360;
	var l = (Math.sqrt(width*width+width*width))/2;
	var gam = Math.PI - ((Math.PI - (beta * Math.PI)/360)/2) - (Math.PI/4);
	var b = 2*l*Math.sin(beta/2);
	var x = b*Math.sin(gam);
	var y = b*Math.cos(gam);
	var p1 = Math.cos(beta);
	var p2 = Math.sin(beta);

	var canvas = document.getElementById(pl_id);
	var id = canvas.getContext("2d");

	var newMoveWidth = 0;
	var newMoveHeight = 0;

	var drawPl = function(){

	        id.clearRect(0, 0, width, height);
		// применяем к нашей планете вращение
		id.transform(p1, p2, -p2, p1, x, -y);
                // рисуем карту с новыми координатами внутри элемента
		id.drawImage(image, newMoveWidth, newMoveHeight, width, height, 0, 0, width, height); 
                //добавляем тень и блики
                id.drawImage(fxShadow, 0, 0, width, height);
                // если смещение достигло предела, начинаем сначала
		if (newMoveWidth >= 899.5) newMoveWidth = 0; 
		else newMoveWidth = newMoveWidth+0.5; // иначе двигаем карту дальше

	}

        setInterval(drawPl, 50); // запускаем анимацию со скоростью 50 мс.

 });

Финальный результат анимации планеты в игре:

image

image

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

Спасибо за внимание!
Tags:
Hubs:
+23
Comments 14
Comments Comments 14

Articles