--- title: Практика построения объектов slug: Learn/JavaScript/Objects/Object_building_practice tags: - Guide - JavaScript translation_of: Learn/JavaScript/Objects/Object_building_practice original_slug: Learn/JavaScript/Объекты/Object_building_practice ---
В предыдущих статьях мы рассмотрели всю существенную теорию объектов JavaScript и детали синтаксиса, давая вам прочную основу для начала. В этой статье мы погружаемся в практическое упражнение, давая вам больше практики в создании пользовательских объектов JavaScript, с веселым и красочным результатом.
Необходимые знания: | Базовая компьютерная грамотность, базовые знания HTML и CSS, знакомство с основами JavaScript (see First steps and Building blocks) и основами OOJS (см. Introduction to objects). |
---|---|
Цель: | Получение некоторой практики в использовании объектов и объектно-ориентированных методов в реальном мире. |
В этой статье мы напишем классическую демонстрацию «прыгающих шаров», чтобы показать вам, насколько полезными могут быть объекты в JavaScript. Наши маленькие шары будут подпрыгивать на экране и менять цвет, когда они касаются друг друга. Готовый пример будет выглядеть примерно так:
В этом примере будет использоваться Canvas API для рисования шаров на экране и API requestAnimationFrame для анимации всего экрана - вам не нужно иметь никаких предыдущих знаний об этих API, и мы надеемся, что к тому моменту, когда вы закончите эту статью, вам будет интересно изучить их больше. По пути мы воспользуемся некоторыми изящными объектами и покажем вам пару хороших приемов, таких как отскоки шаров от стен и проверка того, попали ли они друг в друга (иначе известный как обнаружение столкновения).
Для начала создайте локальные копии наших файловindex.html
, style.css
и main.js
. Они содержат следующее:
<h1>
, и избавляются от любых полос прокрутки или отступы по краю страницы (так что это выглядит красиво и аккуратно).<canvas>
и предоставляют общую функцию, которую мы собираемся использовать.Первая часть скрипта выглядит так:
var canvas = document.querySelector('canvas'); var ctx = canvas.getContext('2d'); var width = canvas.width = window.innerWidth; var height = canvas.height = window.innerHeight;
Этот скрипт получает ссылку на элемент <canvas>
, а затем вызывает метод getContext()
, чтобы дать нам контекст, по которому мы можем начать рисовать. Результирующая переменная (ctx) - это объект, который непосредственно представляет область рисования холста и позволяет рисовать на ней 2D-фигуры.
Затем мы устанавливаем переменные, называемые width
и height
, а также ширину и высоту элемента canvas (представленные свойствами canvas.width
и canvas.height
), чтобы равняться ширине и высоте окна просмотра браузера (область, на которой отображается веб-страница - это можно получить из свойств {{domxref("Window.innerWidth")}} и {{domxref("Window.innerHeight")}}).
Вы увидите здесь, что мы объединяем несколько назначений вместе, чтобы все переменные были установлены быстрее - это совершенно нормально.
Последний бит исходного скрипта выглядит следующим образом:
function random(min, max) { var num = Math.floor(Math.random() * (max - min + 1)) + min; return num; }
Эта функция принимает два числа в качестве аргументов и возвращает случайное число в диапазоне между ними.
В нашей программе будет много шаров, подпрыгивающих вокруг экрана. Поскольку эти шары будут вести себя одинаково, имеет смысл представлять их в виде объекта. Начнем с добавления следующего конструктора в конец нашего кода.
function Ball(x, y, velX, velY, color, size) { this.x = x; this.y = y; this.velX = velX; this.velY = velY; this.color = color; this.size = size; }
Здесь мы включаем некоторые параметры, которые определяют свойства, которым должен соответствовать каждый шар в нашей программе:
x
и y
координаты - горизонтальные и вертикальные координаты, где мяч будет запускаться на экране. Координаты могут находиться в диапазоне от 0 (верхний левый угол) до ширины и высоты окна просмотра браузера (нижний правый угол).velX
и velY
) - каждому шару задана горизонтальная и вертикальная скорость; в реальном выражении эти значения будут регулярно добавляться к значениям координат x
/y
, когда мы начнем анимировать шары, чтобы их перемещать на каждом кадре.color
- каждый мяч получает цвет.size
- каждый мяч получает размер - это будет его радиус в пикселях.Этим мы сортируем свойства, но что насчет методов? Мы хотим заставить эти шары на самом деле сделать что-то в нашей программе.
Сначала добавьте следующий метод draw()
к Ball()
's prototype
:
Ball.prototype.draw = function() { ctx.beginPath(); ctx.fillStyle = this.color; ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI); ctx.fill(); }
Используя эту функцию, мы можем сказать нашему шару нарисовать себя на экране, вызвав ряд членов контекста двумерного холста, который мы определили ранее (ctx
). Контекст похож на бумагу, и теперь мы хотим, чтобы наше перо рисовало что-то на нем:
beginPath()
, чтобы указать, что мы хотим нарисовать фигуру на бумаге.fillStyle
для определения того, какой цвет нам нужен, - мы устанавливаем его в свойство цвета нашего шара.arc()
для отслеживания формы дуги на бумаге. Его параметры:
x
и y
центра дуги - мы указываем свойства x
и y
нашего шара.size
шарика.2 * PI
, что эквивалентно 360 градусам в радианах (досадно, вы должны указать это в радианах). Это дает нам полный круг. Если вы указали только 1 * PI
, вы получите полукруг (180 градусов).fill()
, который в основном утверждает: «Закончите рисование пути, начатого с beginPath()
, и заполните область, которую он занимает с цветом, указанным ранее в fillStyle
».Теперь вы можете начать тестирование своего объекта..
var testBall = new Ball(50, 100, 4, 4, 'blue', 10);
testBall.x testBall.size testBall.color testBall.draw()
Мы можем нарисовать мяч в нужном положении, но чтобы начать движение мяча, нам нужна функция обновления. Добавьте следующий код внизу вашего файла JavaScript, чтобы добавить метод update()
к Ball()
's prototype
:
Ball.prototype.update = function() { if ((this.x + this.size) >= width) { this.velX = -(this.velX); } if ((this.x - this.size) <= 0) { this.velX = -(this.velX); } if ((this.y + this.size) >= height) { this.velY = -(this.velY); } if ((this.y - this.size) <= 0) { this.velY = -(this.velY); } this.x += this.velX; this.y += this.velY; }
Первые четыре части функции проверяют, достиг ли шар края холста. Если это так, мы изменяем полярность соответствующей скорости, чтобы заставить шар двигаться в противоположном направлении. Так, например, если мяч двигался вверх (положительный velY
), то вертикальная скорость изменяется так, что он начинает двигаться вниз (отрицательная величина velY
).
В этих четырех случаях мы:
x
, чем ширина холста (мяч уходит с правого края).x
меньше 0 (мяч уходит с левого края).y
больше высоты холста (мяч уходит с нижнего края).y
меньше 0 (мяч уходит с верхнего края).В каждом случае мы включаем size
шарика в расчет, потому что координаты x
/y
находятся в центре шара, но мы хотим, чтобы край шара отскакивал от периметра - мы не хотим, чтобы мяч на половину заходил за границу экрана прежде чем он начнет возвращаться назад.
Последние две строки добавляют значение velX
к координате x
, а значение velY
- координате y
- шар фактически перемещается при каждом вызове этого метода.
На сейчас этого достаточно, давайте продолжим анимацию!
Теперь давайте приступать к веселью! Сейчас мы начнем добавлять шары к холсту и анимировать их.
var balls = [];
Все программы, которые оживляют вещи, обычно включают цикл анимации, который служит для обновления информации в программе, а затем визуализации результирующего представления для каждого кадра анимации; это основа для большинства игр и других подобных программ.
function loop() { ctx.fillStyle = 'rgba(0, 0, 0, 0.25)'; ctx.fillRect(0, 0, width, height); while (balls.length < 25) { var ball = new Ball( random(0,width), random(0,height), random(-7,7), random(-7,7), 'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')', random(10,20) ); balls.push(ball); } for (var i = 0; i < balls.length; i++) { balls[i].draw(); balls[i].update(); } requestAnimationFrame(loop); }
Наша функция loop()
выполняет следующие действия:
fillRect()
(четыре параметра обеспечивают начальную координату, а ширину и высоту для рисованного прямоугольника ). Это позволяет скрыть рисунок предыдущего кадра до того, как будет нарисован следующий. Если вы этого не сделаете, вы увидите, как длинные змеи пробираются вокруг холста, а не шары! Цвет заливки устанавливается на полупрозрачный, rgba(0,0,0,0,25)
, чтобы позволить нескольким кадрам слегка просвечивать, создавая маленькие тропы за шариками по мере их перемещения. Если вы изменили 0.25 на 1, вы больше не увидите их. Попробуйте изменить это число, чтобы увидеть эффект, который он имеет.Ball()
, используя случайные значения, сгенерированные с помощью нашей функции random()
, затем push()
на конец нашего массива шаров, но только в том случае, когда количество шаров в массиве меньше 25. Итак когда у нас есть 25 мячей на экране, больше не появляется шаров. Вы можете попробовать изменить число в balls.length < 25
, чтобы получить больше или меньше шаров на экране. В зависимости от того, сколько вычислительной мощности имеет ваш компьютер / браузер, если указать несколько тысячь шаров, это может довольно существенно повлиять на производительность анимации. balls
и запускает каждую функцию draw()
и update()
для рисования каждого из них на экране, а затем выполняет необходимые обновления по положению и скорости во времени для следующего кадра.requestAnimationFrame()
- когда этот метод постоянно запускается и передается одно и то же имя функции, он будет запускать эту функцию определенное количество раз в секунду для создания плавной анимации. Обычно это делается рекурсивно - это означает, что функция вызывает себя каждый раз, когда она запускается, поэтому она будет работать снова и снова.loop();
Вот и все для основы - попробуйте сохранить и освежить, чтобы проверить свои прыгающие шары!
Теперь немного поиграем, давайте добавим в нашу программу обнаружение конфликтов, поэтому наши мячи узнают, когда они ударят по другому шару.
update()
(т.е. блок Ball.prototype.update
).
Ball.prototype.collisionDetect = function() { for (var j = 0; j < balls.length; j++) { if (!(this === balls[j])) { var dx = this.x - balls[j].x; var dy = this.y - balls[j].y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < this.size + balls[j].size) { balls[j].color = this.color = 'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) +')'; } } } }
Этот метод немного сложный, поэтому не беспокойтесь, если вы не понимаете, как именно это работает. Ниже приводится объяснение:
for
через все шары в массиве balls[]
.if
, чтобы проверить, проходит ли текущий шарик, тот же самый шар, что и тот, который мы сейчас проверяем. Мы не хотим проверять, что мяч столкнулся с самим собой! Для этого мы проверяем, является ли текущий мяч (т.е. мяч, метод которого вызван методом collisionDetect) такой же, как шар петли (т.е. шар, на который ссылается текущая итерация цикла for в collisionDetect метод). Затем мы используем !
чтобы отменить проверку, чтобы код внутри оператора if выполнялся только в том случае, если они не совпадают.if
. В этом случае мы просто устанавливаем свойство color
обоих кругов на новый случайный цвет. Мы могли бы сделать что-то гораздо более сложное, например, заставить шары отскакивать друг от друга реалистично, но это было бы гораздо сложнее реализовать. Для такого моделирования физики разработчики склонны использовать игры или библиотеку физики, такие как PhysicsJS, matter.js, Phaser и т.д.balls[i].update();
balls[i].collisionDetect();
Примечание. Если вам не удается заставить этот пример работать, попробуйте сравнить код JavaScript с нашей готовой версией (также смотрите, как он работает в прямом эфире).
Мы надеемся, что вам понравилось писать собственный пример случайных прыгающих шаров в реальном мире, используя различные объектные и объектно-ориентированные методы из всего модуля! Это должно было дать вам некоторую полезную практику использования объектов и хорошего контекста реального мира.
Вот и все для предметных статей - все, что осталось сейчас, - это проверить свои навыки в оценке объекта.
{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}