Это удобное для новичков руководство научит вас рисовать закат на p5.js, используя градиенты, циклы, массивы и объекты!

Создание заката, луны и звезд

  1. Откройте новое окно в Google Chrome и перейдите в редактор p5.js. Вы должны увидеть такой код:
function setup() { 
 createCanvas(400, 400);
}
function draw() { 
 background(220);
}

2. Настройка холста. Мы хотим, чтобы наша сцена заката занимала все окно. В функции setup() замените строку на createCanvas, чтобы читать:

createCanvas(windowWidth, windowHeight);

3. Добавление функции градиента. Теперь мы хотим заполнить фон градиентом, имитирующим закат. Мы собираемся позаимствовать функцию создания градиента с официального сайта p5.js. Вставьте это определение функции в конец вашего кода:

function setGradient(x, y, w, h, c1, c2, axis) {
  noFill();
  if (axis == "Y") {  // Top to bottom gradient
    for (let i = y; i <= y+h; i++) {
      var inter = map(i, y, y+h, 0, 1);
      var c = lerpColor(c1, c2, inter);
      stroke(c);
      line(x, i, x+w, i);
    }
  }  
  else if (axis == "X") {  // Left to right gradient
    for (let j = x; j <= x+w; j++) {
      var inter2 = map(j, x, x+w, 0, 1);
      var d = lerpColor(c1, c2, inter2);
      stroke(d);
      line(j, y, j, y+h);
    }
  }
}

По сути, эта функция принимает начальные (x, y) координаты градиента, ширину, высоту, два цвета и ось (X или Y), по которой цвет должен измениться, и рисует градиент.

Градиент на оси Y заставляет цвет изменяться сверху вниз; градиент на оси x заставляет изменять цвет слева направо. Функция lerpColor постепенно смешивает два цвета вместе.

4. Подбираем цвета. Нам нужно выбрать два цвета для градиента. Чтобы имитировать закат, я выбрал темно-синий и оранжевый цвет из Палитры цветов HTML и поместил их в свою функцию draw():

var color1 = color(0, 0, 153);
var color2 = color(204, 51, 0);

Не стесняйтесь выбирать свое - три значения, которые вам понадобятся, будут значениями rgb (красный, зеленый, синий), указанными в скобках прямо под большим цветовым блоком.

5. Создадим градиент! Чтобы вызвать функцию setGradient, которую мы определили на предыдущем шаге, нам нужно написать этот код внизу функции draw():

setGradient(0, 0, windowWidth, windowHeight, color1, color2, "Y");

6. Проверьте это! Нажмите кнопку «запустить» и посмотрите, появляется ли градиент на вашем экране.

7. Добавление петли. Давайте поработаем! Звезды начинают выходить на закате, верно? Для звезд мы хотим нарисовать много маленьких желтых кружков в случайных местах. Чтобы нарисовать кучу чего угодно, нам нужно использовать цикл, который будет рисовать круги снова и снова. Вот цикл, который будет выполняться 50 раз - добавьте его в свою draw() функцию:

for (var i = 0; i < 50; i++) {
   // Code goes here
}

8. Случайное расположение наших звезд. Я хочу, чтобы все мои звезды имели случайные координаты (x, y). Внутри цикла я случайным образом сгенерирую две переменные, x и y:

var x = random(windowWidth);
var y = random(windowHeight-200);

Я сделал y windowHeight-200, потому что не хотел, чтобы звезды подходили слишком близко к горизонту (внизу экрана).

9. Рисуем звезды. А теперь давайте нарисуем звезды! Добавьте этот код после переменных x и y:

noStroke();
fill(255, 255, 0);
ellipse(x, y, 2, 2);

Что тут происходит? Во-первых, noStroke() сообщает компьютеру, что я не хочу, чтобы вокруг моих звезд был контур. fill(255, 255, 0) делает мои звезды желтыми (не стесняйтесь выбирать свои собственные цвета и значения RGB из Палитры цветов HTML). И, наконец, последняя линия рисует эллипс размером 2x2 пикселя в случайно выбранном месте (x, y).

10. Видеть звезды. Давайте проверим! Когда вы нажимаете кнопку «запустить», вы видите звезды?

11. Регулировка частоты кадров. Ваши звезды движутся СУПЕР БЫСТРО? Мы можем это изменить. В вашей функции setup() добавьте код:

frameRate(1);

Посмотрите, что произойдет, когда вы снова нажмете «запустить». Вы можете попробовать разные числа и посмотреть, что вам больше нравится.

12. Задача: добавить луну. Вы видели, что функция fill(r, g, b) устанавливает цвет, а функция ellipse(x, y, w, h) рисует эллипс. Можете ли вы использовать эти два инструмента, чтобы нарисовать луну где-нибудь на экране?

Расширение: создание мерцающих звезд.

Каждый раз, когда наша рамка меняется, все звезды перерисовываются в разных положениях. Но что, если мы хотим, чтобы наши звезды постоянно мерцали?

  1. Мы собираемся создавать звездочки! Внизу кода (под функцией setGradient) добавьте этот код:
function Star() {
   // We'll add code here
}
Star.prototype.draw = function() {
   // We'll add code here
}

2. Придание каждой звезде постоянного положения. В функции Star определите ее конкретные координаты (x, y):

function Star() {
   this.x = random(windowWidth);
   this.y = random(windowHeight-200);
}

3. Заставляем каждую звезду мерцать. Теперь мы хотим нарисовать каждую звезду, указав цвета noStroke() и fill, как и раньше. Добавьте следующие строки в вашу Star.prototype.draw функцию:

noStroke();
fill(255, 255, 0);
ellipse(this.x, this.y, 2, 2);

Но мы собираемся постоянно обновлять положение каждой звезды (x, y), чтобы она казалась мигающей. Добавьте эти две строки в функцию Star.prototype.draw:

this.x += (random(10) - 5);
this.y += (random(10) - 5);

4. Создание новых звезд! Поскольку наши звезды будут помнить свое положение (x, y), нам нужно создать набор, скажем, из 50 звезд, которые мы будем держать на ночном небе. В самом верху вашего кода (даже до функций!) Добавьте эту строку:

var stars = [];

Это создает структуру данных, называемую массивом, который будет содержать все наши звезды.

А теперь давайте добавим к нему звездочки! Внутри функции setup() добавьте следующие строки:

for (var i = 0; i < 50; i++) {
    stars.push(new Star());
}

Опять же, мы использовали наш цикл, который выполнится 50 раз и добавит (или вытолкнет) 50 новых звезд в массив звезд.

5. Давайте заставим звезды мигать! Наконец, нам нужно добавить звезды где-нибудь в нашей функции draw(). Удалите последний цикл for из функции draw() и замените его этим циклом:

for (var i = 0; i < 50; i++) {
    stars[i].draw();
}

6. Проверьте это! Нажмите кнопку «Выполнить». Ваши звезды мерцают?

7. Лишнее мерцание. Наши звезды в настоящее время перемещаются, создавая иллюзию мерцания, когда на самом деле они просто меняют свое положение. Давайте поиграемся с тем, чтобы заставить их сиять.

Мы собираемся присвоить каждой звезде собственную ширину и высоту. Добавьте эти строки кода в свою Star() функцию:

this.w = 2;
this.h = 2;

Измените строку в draw(), которая начинается с ellipse, чтобы включить эти новые переменные:

ellipse(this.x, this.y, this.w, this.h);

Теперь вам нужно сделать так, чтобы ширина и высота колебались от 2x2 пикселей до 3x3 пикселей. Добавьте эти строки в свою Star.prototype.draw функцию:

if (this.w == 2) {
    this.w = 3;
    this.h = 3;
} else {
    this.w = 2;
    this.h = 2;
}

8. Проверьте это! Вы видите сияющие звезды?

Расширение: создание падающей звезды

  1. Определение падающей звезды. Так же, как мы создали объект-звезду, мы собираемся создать объект-падающую звезду! Вставьте это определение в самый конец вашего кода:
function ShootingStar() {
  this.x = random(windowWidth-200);
  this.y = random(windowHeight-400);
  this.w = 6;
  this.h = 4;
}

В этом определении я случайным образом генерирую координаты (x, y) в верхнем левом квадранте экрана и делаю падающую звезду немного больше, чем наша обычная звезда 2x2.

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

ShootingStar.prototype.draw = function() {
  noStroke();
  fill(255, 255, 0);
  ellipse(this.x, this.y, this.w, this.h);
  if (this.h > 0) {
    this.h -= 0.5;
  }
  this.w += 7;
  this.x += 5;
}

Каждый раз, когда звезда рисуется, ее высота уменьшается, ширина увеличивается и она перемещается по оси x экрана.

3. Реализация звезды. Теперь, когда мы определили поведение падающей звезды, давайте добавим переменную для ее сохранения. Вверху кода добавьте:

var shootingStar;

Затем в функции setup() мы поместим в переменную падающую звезду. Добавьте этот код в конец вашего setup() кода:

shootingStar = new ShootingStar();

Наконец, нам нужно будет перерисовывать падающую звезду в каждом кадре. Добавьте этот код в свой draw() код:

shootingStar.draw();

4. Проверьте это! Вы видите звезду, летящую по экрану? Вы можете поэкспериментировать с frameRate в setup и посмотреть, хотите ли вы, чтобы звезда двигалась быстрее или медленнее.

Дополнительные расширения

  1. Добавьте больше падающих звезд с помощью массива и for петель! (Подсказка: посмотрите, как были созданы 50 звезд.)
  2. Сможете ли вы заставить падающие звезды лететь по дуге?
  3. Используйте свои знания градиентов и эллипсов, чтобы нарисовать другие сцены, например, конфетти, падающие с потолка. (Подсказка: вам нужно постоянно изменять значение y, чтобы конфетти падало.)
  4. Можете ли вы заставить звезды (или конфетти) скользить по экрану и отскакивать от края? (Подсказка: вам нужно постепенно увеличивать / уменьшать координаты x и y и постоянно проверять, эквивалентны ли эти переменные windowWidth или windowHeight.)