Добавление функций в нашу демонстрацию отбойных шаров
=====================================================

* Назад
* Обзор: Objects

В этом упражнении мы будем использовать проект прыгающих шаров из предыдущей статьи и добавим в него новые интересные возможности.

| Требования: | Перед тем как приступить к этому упражнению нужно выполнить задания из всех статей текущего модуля. |
| --- | --- |
| Цель: | Проверить насколько хорошо вы понимаете объекты и связанные с ними конструкции в языке Javascript. |

Начало
------

Для начала скопируйте файлы index-finished.html, style.css и main-finished.js из предыдущей статьи в новую директорию на вашем компьютере.

Для выполнения упражнения вы можете использовать сайт JSBin или Thimble. Вы можете вставлять HTML, CSS и JavaScript-код в один из этих онлайн-редакторов. Если ваш онлайн-редактор не поддерживает раздельные панели для редактирования JavaScript/CSS кода, то вы можете встроить код в HTML с помощью тегов `<script>`/`<style>`.

**Примечание:** . Если у вас что-то не получается — попросите о помощи. Более подробная информация находится в секции Assessment or further help в конце этой страницы.

Краткое описание проекта
------------------------

Наша весёлая демонстрация шаров - это весело, но теперь мы хотим сделать её немного более интерактивной, добавив контролируемый пользователем злой круг, который будет есть шары, если он их поймает. Мы также хотим проверить ваши навыки создания объектов, создав общий объект `Shape()`, который могут наследовать наши шары и злой круг. Наконец, мы хотим добавить счётчик очков, чтобы отслеживать количество оставшихся шаров для захвата.

Следующий скриншот даёт вам представление о том, как должна выглядеть готовая программа:

![](/ru/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features/bouncing-evil-circle.png)

Чтобы дать вам больше идеи, посмотрите на законченный пример (не заглядывая в исходный код!)

Шаги по завершению
------------------

В следующих разделах описывается, что вам нужно делать.

### Создание наших новых объектов

Прежде всего, измените существующий конструктор `Ball()` так, чтобы он стал конструктором `Shape()` и добавил новый конструктор `Ball()`:

1. Конструктор `Shape()` должен определять свойства `x`, `y`, `velX` и `velY`, так же, как и конструктор `Ball()`, но не свойства `color` и `size`.
2. Он также должен определить новое свойство `exists`, которое используется для отслеживания наличия шаров в программе (не было съедено злым кругом). Это должно быть логическое (`true` / `false`).
3. Конструктор `Ball()` должен наследовать свойства `x`, `y`, `velX`, `velY` и `exists` из конструктора `Shape()`.
4. Он также должен определить свойство `color` и `size`, как это сделал оригинальный конструктор `Ball()`.
5. Не забудьте установить `prototype` и `constructor` конструктора `Ball()` соответствующим образом.

Определения меток шара `draw()`, `update()` и `collisionDetect()` должны быть такими же, как и раньше.

Вам также нужно добавить новый параметр в новый вызов конструктора `new Ball() ( ... )` - параметр `exists` должен быть 5-м параметром и ему должно быть присвоено значение `true`.

На этом этапе попробуйте перезагрузить код - он должен работать так же, как и раньше, с нашими перепроектированными объектами.

### Определение EvilCircle()

Теперь пришло время встретить плохого парня - `EvilCircle()`! Наша игра будет включать только один злой круг, но мы все ещё будем определять его с помощью конструктора, который наследует от `Shape()`, чтобы дать вам некоторую практику. Возможно, вам захочется добавить ещё один круг в приложение, которое может контролироваться другим игроком или иметь несколько злобных окружений, управляемых компьютером. Вы, вероятно, не собираетесь захватить мир одним злым кругом, но он будет делать для этой оценки.

Конструктор `EvilCircle()` должен наследовать `x`, `y`, `velX`, `velY` и `exists` из `Shape()`, но `velX` и `velY` должны всегда равняться 20.

Вы должны сделать что-то вроде `Shape.call(this, x, y, 20, 20, exists);`

Он также должен определить свои собственные свойства следующим образом:

* `color` — `'white'`
* `size` — `10`

Опять же, не забудьте определить свои унаследованные свойства как параметры в конструкторе и правильно установить свойства `prototype` и `constructor`.

### Defining EvilCircle()'s methods

`EvilCircle()` должен иметь четыре метода, как описано ниже.

#### `draw()`

Этот метод имеет ту же цель, что и метод `draw()` метода `Ball()`: он рисует экземпляр объекта на холсте. Он будет работать очень схожим образом, поэтому вы можете начать с копирования определения `Ball.prototype.draw`. Затем вы должны внести следующие изменения:

* Мы хотим, чтобы злой круг не был заполнен, а скорее имел внешнюю линию (удар). Вы можете добиться этого, обновив `fillStyle` и `fill()` до `strokeStyle` и s `stroke()`.
* Мы также хотим сделать ход немного толще, так что вы можете увидеть злой круг немного легче. Этого можно добиться, установив значение для `lineWidth` где-нибудь после вызова `beginPath()` (3 будем делать).

#### `checkBounds()`

Этот метод будет делать то же самое, что и первая часть функции `Ball()`'s `update()`, чтобы посмотреть, не исчезнет ли злой круг от края экрана и не прекратит это делать. Опять же, вы можете просто скопировать определение `Ball.prototype.update`, но есть несколько изменений, которые вы должны сделать:

* Избавьтесь от последних двух строк - мы не хотим автоматически обновлять позицию злого круга на каждом кадре, потому что мы будем перемещать его каким-то другим способом, как вы увидите ниже.
* Внутри операторов `if()`, если тесты возвращают true, мы не хотим обновлять `velX` / `velY`; мы хотим вместо этого изменить значение `x` / `y`, так что злой круг возвращается на экран немного. Добавление или вычитание (по мере необходимости) свойства `size` злого круга имеет смысл.

#### `setControls()`

Этот метод добавит обработчик событий `onkeydown` к объекту `window`, чтобы при нажатии определённых клавиш клавиатуры мы могли перемещать злой круг вокруг. Следующий код должен быть помещён внутри определения метода:


```js
var _this = this;
window.onkeydown = function (e) {
  if (e.keyCode === 65) {
    _this.x -= _this.velX;
  } else if (e.keyCode === 68) {
    _this.x += _this.velX;
  } else if (e.keyCode === 87) {
    _this.y -= _this.velY;
  } else if (e.keyCode === 83) {
    _this.y += _this.velY;
  }
};
```


Поэтому, когда нажата клавиша, проконсультируется о свойствах keyCode (en-US) объекта события, чтобы увидеть, какая клавиша нажата. Если это один из четырёх, представленных указанными ключевыми кодами, тогда злой круг будет перемещаться влево / вправо / вверх / вниз.

* Для бонусного пункта сообщите нам, к каким ключам относятся указанные коды ключей.
* В другой бонусной точке вы можете сказать нам, почему нам пришлось установить `var _this = this`; в позиции, в которой он находится? Это как-то связано с функциональной областью.

#### `collisionDetect()`

Этот метод будет действовать очень похоже на метод `collisionDetect()` в `Ball()`, поэтому вы можете использовать его в качестве основы для этого нового метода. Но есть несколько отличий:

* В внешнем выражении `if` вам больше не нужно проверять, совпадает ли текущий мяч на итерации с шаром, который выполняет проверку, потому что он больше не является мячиком, это злой круг! Вместо этого вам нужно выполнить проверку, чтобы проверить, существует ли проверенный шар (с каким свойством вы могли бы это сделать?). Если этого не существует, он уже был съеден злым кругом, поэтому нет необходимости проверять его снова.
* Во внутреннем `if`-выражении вы больше не хотите, чтобы объекты меняли цвет при обнаружении столкновения - вместо этого вы хотите установить любые шары, которые сталкиваются с злым кругом, чтобы больше не существовать (опять же, как вы думаете, d сделать это?).
### Приведение злого круга в программу

Теперь мы определили злой круг, нам нужно на самом деле заставить его появиться на нашей сцене. Для этого вам нужно внести некоторые изменения в функцию `loop()`.

* Прежде всего, создайте новый экземпляр объекта злого круга (указав необходимые параметры), затем вызовите его метод `setControls()`. Вам нужно только сделать эти две вещи один раз, а не на каждой итерации цикла.
* В точке, где вы прокручиваете каждый шар и вызываете функции `draw()`, `update()` и `collisionDetect()` для каждого из них, делайте так, чтобы эти функции вызывались только в том случае, если текущий шар существует.
* На каждой итерации цикла вызовите методы draw `draw()`, `checkBounds()` и `collisionDetect()` для злого шарика.
### Реализация счётчика баллов

Чтобы выполнить счётчик счётчиков, выполните следующие действия:

1. В своём HTML-файле добавьте элемент `<p>` непосредственно под элементом `<h1>` (en-US), содержащим текст «Ball count:».
2. В вашем файле CSS добавьте следующее правило внизу:

```css
p {
  position: absolute;
  margin: 0;
  top: 35px;
  right: 5px;
  color: #aaa;
}
```

3. В своём JavaScript сделайте следующие обновления:
    * Создайте переменную, которая хранит ссылку на абзац.
    * Держите подсчёт количества шаров на экране в некотором роде.
    * Увеличьте количество и покажите обновлённое количество шаров каждый раз, когда шар добавляется в сцену.
    * Уменьшите счёт и покажите обновлённое количество мячей каждый раз, когда злой круг ест шарик (его не существует).
Советы и подсказки
------------------

* Эта оценка довольно сложная. Делайте каждый шаг медленно и осторожно.
* Может быть, идея сохранить отдельную копию демонстрации после того, как вы получите каждый этап работы, так что вы можете вернуться к ней, если позже окажетесь в беде.
Assessment
----------

Если вы проводите эту оценку в рамках организованного курса, вы должны уметь отдать свою работу своему учителю / наставнику для маркировки. Если вы самообучаетесь, то вы можете получить руководство по маркировке довольно легко, задав тему обсуждения для этого упражнения или в IRC-канале #mdn в Mozilla IRC. Сначала попробуйте упражнение - ничего не выиграть от обмана!

* Назад
* Обзор: Objects
In this module
--------------

* Object basics
* Object-oriented JavaScript for beginners (en-US)
* Object prototypes
* Inheritance in JavaScript
* Working with JSON data
* Object building practice
* Adding features to our bouncing balls demo