Программируем скринсейвер для Илона
medium

Программируем скринсейвер для Илона

Анимация движения звёзд на JavaScript.

Попробуем новую для нас библиотеку в JavaScript — p5. Её используют, чтобы расширить стандартные возможности рисования в JavaScript и писать для этого более крутые скрипты. 

Сегодняшний проект — полёт в космосе к звёздам, как будто мы летим на ракете:

Попробуем новую для нас библиотеку в JavaScript — p5

Логика работы

Чтобы всё это нарисовать, нам нужно:

  1. Подготовить страницу так, чтобы содержимое занимало весь размер окна браузера.
  2. Запрограммировать общее поведение для звёзд — разлетаться к краю экрана, постепенно увеличиваясь в размере.
  3. Предусмотреть такое: если звезда улетела за границы окна — создать новую звезду с таким же поведением.
  4. Создать много звёзд с разными координатами.
  5. Запустить анимацию.

Большинство функций реализуем с помощью библиотеки p5 — в ней много готовых команд, которые упрощают разработку и отрисовку любых объектов.

Что за P5 и зачем она нужна

Библиотека P5.js — это продвинутая библиотека для рисования чего угодно в браузере. Она основана на фреймворке Processing — а он, в свою очередь, создавался, чтобы помочь художникам использовать для своих художественных дел инструменты программирования.

Короче: P5.js — это удобная рисовалка. Сейчас увидите. 

Подготовка

Используем для проекта стандартный HTML-шаблон. Единственное, что мы добавим нового в шаблон — пропишем название проекта.

<!DOCTYPE html>
<html lang="ru" >
<head>
  <meta charset="UTF-8">
  <title>Полёт в космос</title>
 
  <style type="text/css">

  </style>

</head>
<body>

	<!-- основной скрипт -->
	<script type="text/javascript">
	
	</script>

</body>
</html>

Подготавливаем стили

Чтобы во всех браузерах наши звёзды выглядели одинаково, подключим нормализатор стилей:

  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">

Задача нормализатора — привести все стили по умолчанию во всех браузерах к одному общему виду.

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

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

<style type="text/css">
  	*{
  		/* сделаем так, чтобы мы могли задавать размеры всех элементов в разных единицах одновременно, например, высоту в пикселях, а ширину в процентах */
		box-sizing: border-box;
	}
	html, body{
		/* убираем границы и отступы */
		margin: 0;
		padding: 0;
		/* разворачиваем космос на всю ширину окна браузера */
		width: 100%;
		height: 100vh;
		/* не отображаем звёзды, которые вылетели за пределы окна*/
		overflow: hidden;
	}
  </style>

Подключаем библиотеку p5 и создаём основной скрипт

Для подключения библиотеки просто добавляем её вызов в тело страницы:

<!— подключаем p5 — библиотеку для рисования в JavaScrpt —>

<script src='https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.min.js'></script>

После этого создаём основной скрипт, который будет отвечать за всё, что происходит на экране. Всё остальное будем писать внутри него.

<!— основной скрипт —>

<script type="text/javascript">

</script>

Программируем звёзды

Чтобы не описывать каждую звезду отдельно, а задать для них общее поведение, будем использовать классы и методы. Если вы не знаете, что это такое, — почитайте наш мини-цикл про объектно-ориентированное программирование

Вот что мы сделаем с помощью класса:

  1. Пропишем общую логику создания звезды — где именно она появится и как близко к виртуальной передней границе экрана. За это в классах отвечает конструктор — в нём пишутся команды, что именно нужно сделать при создании новой звезды.
  2. Запрограммируем, как будут меняться координаты звезды во время движения. Чтобы изменения произошли, нужно создать новый метод и вызвать его в нужный момент.
  3. Добавим возможность отрисовки звезды по текущим координатам. За это тоже будет отвечать свой метод.

Этими свойствами и возможностями будут обладать все звёзды на основе этого класса — в этом и смысл ООП. Даже если мы создадим миллион звёзд, нам не придётся прописывать логику каждой звезды — за нас это сделает класс.

// сколько звёзд может быть одновременно на экране
var starsCount = 800;
// на старте массив со звёздами будет пустой
var stars = [];
// класс, на основе которого будут сделаны все звёзды
class Star{
	// конструктор, который вызывается при создании каждого объекта на основе этого класса
	constructor(){
		// у новой звезды будут случайные координаты
		this.x = random(-width, width);
		this.y = random(-height, height);
		// глубина — насколько виртуально близко к экрану появится звезда
		this.z = random(width);
	}
	// метод, который обновляет координаты звезды
	update(){
		// скорость полёта
		var speed = 12;
		// приближаем звезду к краю экрана, уменьшая глубину на значение скорости
		this.z -= speed;
		// если звезда вылетела за край экрана — делаем из неё новую звезду, для этого меняем координаты
		if(this.z < 1){
			this.x = random(-width, width);
			this.y = random(-height, height);
			// для новой звезды вместо старой глубину появления теперь выбираем не случайным образом, а задаём прямо
			this.z = width;
		}
	}

	// метод, который отрисовывает звезду на экране
	drawStar(){
		// каждая звезда — белого цвета
		fill(255);
		// и без контура
		noStroke();

		// с помощью функции map() из библиотеки p5.js получаем новые координаты для отрисовки звезды 
		var sx = map(this.x / this.z, 0, 1, 0, width);
		var sy = map(this.y / this.z, 0, 1, 0, height);

		// чем ближе к краю экрана (чем меньше глубина z) — тем больше радиус 
		var r = map(this.z, 0, width, 10, 0);
		// рисуем звезду в новых координатах и новым размером
		ellipse(sx, sy, r, r);
	}
}

Готовимся к запуску

В библиотеке p5 есть специальная функция setup() — код, который в ней написан, выполнится сразу после загрузки страницы со скриптом. Сделаем такую функцию в нашем скрипте, чтобы в ней запрограммировать создание холста и всех звёзд.

// подготавливаем всё к запуску — то, что написано здесь выполнится автоматически сразу после загрузки
function setup(){
	// создаём холст, на котором будем рисовать
	createCanvas(innerWidth, innerHeight);
	// размещаем сразу все звёзды на холсте
	for (var i = 0; i < starsCount; i++) {
		// каждая новая звезда — объект класса Star и умеет то же самое, что и все остальные звёзды
		stars[i] = new Star();
	}
}

Рисуем и запускаем анимацию

Ещё одна специальная функция из той же библиотеки — draw(). Она отвечает за рисование и анимацию. Всё, что написано внутри этой функции, будет выполняться раз за разом, по кругу, пока мы не закроем страницу. Используем это, чтобы сделать анимацию для звёзд. 

👉 При каждом проходе draw() не очищает холст, нам нужно сделать это самостоятельно. Для этого будем просто закрашивать всё чёрным и рисовать звёзды заново.

/ пока мы не закроем страницу, постоянно будет выполняться функция drw() 
function draw(){
	// ставим чёрный фон и указываем скорость обновления фона — чем меньше второе число, тем больший шлейф будут оставлять звёзды
	background(0, 180);
	// формируем центр экрана, куда «полетим» сквозь звёзды
	translate(width/2, height/2);

	// отрисовываем каждый раз все звёзды и меняем их положение
	for (var i = 0; i < starsCount; i++) {
		stars[i].drawStar();
		stars[i].update();
	}
}

Следим за размерами экрана

Чтобы у нас полёт рисовался пропорционально экрану даже при изменении размера окна, добавим обработчик этого события. Он сработает при каждом изменении размеров окна и сразу изменит размер холста.

// если поменяется размер окна браузера — сразу меняем размер холста
addEventListener('resize', () => {
resizeCanvas(innerWidth, innerHeight);
})

Результат

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

<!DOCTYPE html>
<html lang="ru" >
<head>
  <meta charset="UTF-8">
  <title>Полёт в космос</title>
  <!-- сделаем так, чтобы в каждых браузерах результат выглядел одинаково — подключим нормализатор стилей -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
  <style type="text/css">
  	*{
  		/* сделаем так, чтобы мы в блоке управляли размерами не контента, а самого блока — это понадобится для звёзд */
		box-sizing: border-box;;
	}
	html, body{
		/* убираем границы и отступы */
		margin: 0;
		padding: 0;
		/* разворачиваем космос на всю ширину окна браузера */
		width: 100%;
		height: 100vh;
		/* не отображаем звёзды, которые вылетели за пределы окна*/
		overflow: hidden;
	}
  </style>

</head>
<body>
	<!-- подключаем p5 — библиотеку для рисования в JavaScrpt -->
	<script src='https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.min.js'></script>
	<!-- основной скрипт -->
	<script type="text/javascript">
	// сколько звёзд может быть одновременно на экране
	var starsCount = 800;
	// на старте массив со звёздами будет пустой
	var stars = [];
	// класс, на основе которого будут сделаны все звёзды
	class Star{
		// конструктор, который вызывается при создании каждого объекта на основе этого класса
		constructor(){
			// у новой звезды будут случайные координаты
			this.x = random(-width, width);
			this.y = random(-height, height);
			// глубина — насколько виртуально близко к экрану появится звезда
			this.z = random(width);
		}
		// метод, который обновляет координаты звезды
		update(){
			// скорость полёта
			var speed = 12;
			// приближаем звезду к краю экрана, уменьшая глубину на значение скорости
			this.z -= speed;
			// если звезда вылетела за край экрана — делаем из неё новую звезду, для этого меняем координаты
			if(this.z < 1){
				this.x = random(-width, width);
				this.y = random(-height, height);
				// для новой звезды вместо старой глубину появления теперь выбираем не случайным образом, а задаём прямо
				this.z = width;
			}
		}

		// метод, который отрисовывает звезду на экране
		drawStar(){
			// каждая звезда — белого цвета
			fill(255);
			// и без контура
			noStroke();

			// с помощью функции map() из библиотеки p5.js получаем новые координаты для отрисовки звезды 
			var sx = map(this.x / this.z, 0, 1, 0, width);
			var sy = map(this.y / this.z, 0, 1, 0, height);

			// чем ближе к краю экрана (чем меньше глубина z) — тем больше радиус 
			var r = map(this.z, 0, width, 10, 0);
			// рисуем звезду в новых координатах и новым размером
			ellipse(sx, sy, r, r);
		}
	}

	// подготавливаем всё к запуску — то, что написано здесь выполнится автоматически сразу после загрузки
	function setup(){
		// создаём холст, на котором будем рисовать
		createCanvas(innerWidth, innerHeight);
		// размещаем сразу все звёзды на холсте
		for (var i = 0; i < starsCount; i++) {
			// каждая новая звезда — объект класса Star и умеет то же самое, что и все остальные звёзды
			stars[i] = new Star();
		}
	}

// пока мы не закроем страницу, постоянно будет выполняться функция drw() 
function draw(){
	// ставим чёрный фон и указываем скорость обновления фона — чем меньше второе число, тем больший шлейф будут оставлять звёзды
	background(0, 180);
	// формируем центр экрана, куда «полетим» сквозь звёзды
	translate(width/2, height/2);

	// отрисовываем каждый раз все звёзды и меняем их положение
	for (var i = 0; i < starsCount; i++) {
		stars[i].drawStar();
		stars[i].update();
	}
}

	// если поменяется размер окна браузера — сразу меняем размер холста
	addEventListener('resize', () => {
		resizeCanvas(innerWidth, innerHeight);
	})	
	</script>

</body>
</html>

Что дальше

Дальше сделаем ещё несколько проектов с библиотекой p5. Заодно попрактикуемся в ООП — создадим объекты на основе объектов из другого класса.


Код

Sikriti Dakua



Художник

Даня Берковский


Корректор

Ирина Михеева


Вёрстка

Мария Дронова


Соцсети

Олег Вешкурцев

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Еще по теме
Улучшаем автоматизацию новостей
Улучшаем автоматизацию новостей

И получаем готовый рабочий продукт.

easy
Подключаем нейросеть к веб-камере
Подключаем нейросеть к веб-камере

Готовьтесь — искусственный интеллект уберёт вас из кадра.

medium
Делаем свой блокировщик любой рекламы за 3 минуты
Делаем свой блокировщик любой рекламы за 3 минуты

Хакерский метод победить рекламодателей.

easy
Задача с собеседования: как найти палиндром
Задача с собеседования: как найти палиндром

Элитная задача с сайта Leetcode

easy
Что означает ошибка TypeError: something() takes 0 positional arguments but 1 was given
Что означает ошибка TypeError: something() takes 0 positional arguments but 1 was given

Это когда аргументы появляются там, где их быть не должно

easy
Что означает ошибка TypeError: Cannot assign to read only property
Что означает ошибка TypeError: Cannot assign to read only property

Ошибка, которая хотя бы раз, но встречалась у каждого

easy
Делаем свою доску задач с тегами и анимацией
Делаем свою доску задач с тегами и анимацией

Так делает большинство таск-трекеров

medium
Что означает ошибка OverflowError: math range error
Что означает ошибка OverflowError: math range error

Это ошибка переполнения из-за математических операций

easy
Что означает ошибка TypeError: string indices must be integers
Что означает ошибка TypeError: string indices must be integers

Ошибка на внимательность из мира строк в Python

easy
medium