Если вы еще не пересекались с P5.js, вы должны знать, что это самый простой способ рисования в Интернете и в то же время один из самых мощных. P5.js вдохновлен библиотекой Java под названием Processing. Но в то время как Processing многословен и сложен для поиска хороших примеров, в P5 есть много отличных примеров и практически нет шаблонов.
В этом примере мы собираемся построить простой и маленький Pong. Pong — это игра atari, в которой 2 игрока пытаются забить гол на другой стороне времени.
Это будет просто, потому что это будет первый подход к P5, и он будет маленьким, потому что чем меньше, тем симпатичнее.
Самый простой способ начать играть с P5 — использовать онлайн-редактор P5 https://editor.p5js.org/. Вы также можете использовать его, загрузив в заголовок HTML-файла. Код, который мы собираемся использовать, можно найти здесь https://editor.p5js.org/davidalencia/sketches/hmX4-A8lw.
настроить и нарисовать
P5 загружает множество служебных функций, упрощающих работу с анимацией. Две основные функции — setup, которая будет запускаться один раз при старте, и draw, которая будет вызываться каждый кадр.
Мы собираемся начать с создания панели Pong.
setup(){ createCanvas(80, 80); } draw(){ background(0); rect(10, 40, 4, 14); }
При настройке главное, что мы должны сделать, это создать холст, на котором мы будем рисовать. Вызвав createCanvas, мы можем определить размер, в данном случае 80 на 80 пикселей.
В Draw мы определяем цвет фона как черный и создаем прямоугольник в точках (10, 40) шириной 4 и высотой 14. Важно отметить, что если мы вызовем background в конце, он закрасит все, что было. до.
Использование классов более удобно для анимации, поэтому мы собираемся использовать их.
Бары
У нас уже есть бар, так что давайте начнем с того, что сделаем его классом. Наш класс должен принимать координату x, чтобы мы могли использовать ее для левой и правой панели и отслеживать точки. Он также должен иметь метод рисования, чтобы мы могли обрабатывать анимацию.
class Bar { constructor(x){ this.x = x; this.y = 30; this.height = 14; this.width = 4; this.points = 0; } draw(){ rect(this.x, this.y, this.width, this.height); } }
Теперь мы можем создать две полоски, необходимые для игры. Здесь мы переписываем функцию рисования.
let left = new Bar(2); let right = new Bar(76); draw(){ background(0); left.draw() right.draw() }
Вы должны увидеть что-то вроде этого. Но вряд ли это бары Понга, они должны как минимум двигаться вверх-вниз. Мы изменим класс Bar, чтобы он имел метод up и down. Оба метода должны проверять ребра и не перемещаться, если они находятся рядом с одним.
Если вы уже что-то анимировали или немного поиграли с кодом, вы можете заметить, что ось «y» идет сверху вниз, а не снизу вверх, как можно подумать. Итак, чтобы сдвинуть планку вниз, мы должны увеличить «y», а чтобы сдвинуть ее вверх, мы должны уменьшить ее.
class Bar { . . . up(){ this.y = (this.y < 80-this.height)? this.y-1: this.y } down(){ this.y = (this.y > 0)? this.y+1: this.y } }
Это не двигает планку само по себе. К счастью, в P5 есть функция, которая будет вызываться каждый раз, когда происходит событие клавиатуры, и переменная, принимающая значение последней нажатой клавиши.
Теперь мы будем перемещать левую полосу вверх с помощью w и вниз с помощью s, коды которых равны 87 и 83 соответственно. А для правой панели мы будем использовать стрелки вверх и вниз, в P5 есть константы для этих клавиш. Если вам интересно, вы можете просмотреть их все здесь https://p5js.org/es/reference/#/p5/keyPressed.
У нас уже есть экземпляры панели, поэтому нам просто нужно прослушивать нажатия клавиш и перемещать их.
function keyPressed(){ if(p.keyCode==87) left.up() else if(p.keyCode==83) left.down() else if(p.keyCode==p.UP_ARROW) right.up() else if(p.keyCode==p.DOWN_ARROW) right.down() }
Мяч
Теперь, когда у нас есть стержни, пришло время запрограммировать мяч. Мяч должен отскакивать от верхнего и нижнего краев и появляться в середине.Кроме того, мы зададим ему случайную скорость и направление, чтобы игрок не знал, откуда прилетел мяч.
class Ball{ constructor(){ this.x = 40 this.y = 40 this.xs =(Math.random()-0.5) this.ys = (Math.random()-0.5) } }
Как и в нашем классе Bar, у класса ball также должен быть метод draw. Но мяч движется сам по себе, поэтому мы должны обновлять позицию каждый раз, когда рисуем мяч. И если мяч движется сам по себе, мы должны проверить края. В понге, когда мяч касается верхнего или нижнего края, он отскакивает, а это означает, что ускорение по оси «у» умножается на -1.
Ни с того ни с сего я решил сделать шар квадратом 2 на 2. Преимущество в том, что мы уже знаем, как рисовать прямоугольник, а квадрат — это разновидность прямоугольника.
draw(){ //drawing the square rect(this.x, this.y, 2, 2) //updating the position this.y *=this.ys this.x +=this.xs // looking for edges if(this.y<=0 || this.y>=80-2){ this.ys = this.ys *(-1) this.y += this.ys } }
Хороший. У нас есть класс мяча, теперь нам нужен экземпляр и его нужно нарисовать.
let ball = new Ball() function draw(){ . . . ball.draw() }
У вас должно получиться что-то вроде этого ниже.
Взаимодействие мяча и брусьев
Итак, теперь у нас есть движущийся мяч и два играбельных бара. Но мяч проходит через решетку. Если мяч находится перед перекладиной, то мы должны оттолкнуть мяч от оси «х». И если мяч проходит за перекладиной, не касаясь ее, то другая перекладина получает очко, и мы создаем новый мяч.
Легче узнать, не попал ли мяч в перекладину, нам просто нужно убедиться, что мяч находится за перекладиной. Когда это происходит, мы увеличиваем точки другого бара и создаем новый шар.
Итак, давайте проверим эти условия в розыгрыше. Если координата x мяча меньше, чем у левой полосы, или больше, чем сумма координаты x и ширины правой полосы, мы увеличиваем соответствующий счет и создаем новый мяч.
function draw(){ . . . if(ball.x<left.x){ right.points++; ball = new Ball() } else if(ball.x>right.x+right.width){ left.points++; ball = new Ball(); }
После этого нам нужно проверить два условия. Мы должны убедиться, что мяч находится в пределах бара. По этой причине координата у шара должна быть больше, чем у бруска, но меньше суммы координаты у бруска и длины его высоты. Кроме того, расстояние между мячом и перекладиной не должно быть больше ширины мяча.
function draw(){ const inScope = (ball, bar)=>ball.y>bar.y && ball.y<bar.y+bar.height; . . . else if(inScope(ball, left) && ball.x < left.x+left.width){ ball.x = left.x+left.width ball.xs *= -1 } else if(inScope(ball, right) && ball.x > right.x-2){ ball.x = this.right.x-2 ball.xs *= -1 } }
Последние штрихи
Осталось только табло. P5, будучи одним из самых простых доступных фреймворков, позволяет нам сделать это одной строкой, передав сначала сообщение, а затем нужные нам координаты.
function draw(){ . . . text(`${left.points} : ${right.points}`, 40, 10) }
Но это оказывается немного не к месту, и цвет не совсем правильный. По этой причине нам нужно вызвать еще две команды. Первый будет центрировать текст, а второй определяет цвет. Это должно выглядеть так.
function draw(){ . . . textAlign(p.CENTER); fill(255, 255, 255); text(`${left.points} : ${right.points}`, 40, 10) }
У вас должно получиться что-то похожее на изображение, показанное ниже.
Поздравляем, у вас наконец-то есть хорошая игра Pong, закодированная в P5!
Помните, что весь код находится по следующей ссылке: https://editor.p5js.org/davidalencia/sketches/hmX4-A8lw