Попробуем новую для нас библиотеку в JavaScript — p5. Её используют, чтобы расширить стандартные возможности рисования в JavaScript и писать для этого более крутые скрипты.
Сегодняшний проект — полёт в космосе к звёздам, как будто мы летим на ракете:
Логика работы
Чтобы всё это нарисовать, нам нужно:
- Подготовить страницу так, чтобы содержимое занимало весь размер окна браузера.
- Запрограммировать общее поведение для звёзд — разлетаться к краю экрана, постепенно увеличиваясь в размере.
- Предусмотреть такое: если звезда улетела за границы окна — создать новую звезду с таким же поведением.
- Создать много звёзд с разными координатами.
- Запустить анимацию.
Большинство функций реализуем с помощью библиотеки 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>
Программируем звёзды
Чтобы не описывать каждую звезду отдельно, а задать для них общее поведение, будем использовать классы и методы. Если вы не знаете, что это такое, — почитайте наш мини-цикл про объектно-ориентированное программирование.
Вот что мы сделаем с помощью класса:
- Пропишем общую логику создания звезды — где именно она появится и как близко к виртуальной передней границе экрана. За это в классах отвечает конструктор — в нём пишутся команды, что именно нужно сделать при создании новой звезды.
- Запрограммируем, как будут меняться координаты звезды во время движения. Чтобы изменения произошли, нужно создать новый метод и вызвать его в нужный момент.
- Добавим возможность отрисовки звезды по текущим координатам. За это тоже будет отвечать свой метод.
Этими свойствами и возможностями будут обладать все звёзды на основе этого класса — в этом и смысл ООП. Даже если мы создадим миллион звёзд, нам не придётся прописывать логику каждой звезды — за нас это сделает класс.
// сколько звёзд может быть одновременно на экране
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. Заодно попрактикуемся в ООП — создадим объекты на основе объектов из другого класса.