Глава V из серии руководств о том, как создать игру с нуля с помощью TypeScript и собственных API-интерфейсов браузера.

Добро пожаловать в последний выпуск этой главы! В прошлой статье мы представили OnclickComponent, абстрактный класс, который служит мостом между уведомителем (GameInputComponent) и реальными получателями. Сегодня мы собираемся добавить один такой приемник в нашу счастливую семью и, конечно же, накроем GameInputComponent юнит-тестами.

В главе V «Система ввода» мы собираемся создать простую систему, которая даст игроку возможность общаться с игрой. Вы можете найти другие главы этой серии здесь:

Смело переходите в input-2 ветку репозитория. Он содержит рабочий результат предыдущих постов и является отличной отправной точкой для этого.

Оглавление

  1. Вступление
  2. Представляем компонент Grid Onclick
  3. Сетка тестирования
  4. Тестирование компонента Onclick Grid
  5. Тестирование компонента ввода игры
  6. Внедрение зависимостей в игру
  7. Заключение

Вступление

Наша цель в этой главе - убедиться, что наша система ввода работает. Мы согласились с тем, что мы делаем это, временно отмечая Node как активный, когда игрок щелкает по нему. Теперь, когда у нас есть надежная система уведомлений, мы можем ввести что-то вроде NodeOnclickComponent, которое расширит OnclickComponent и фактически установит флаг IsActive. Но мы также можем сделать то же самое на один уровень выше, введя GridOnclickComponent.

Есть 2 причины, по которым я хочу пойти по этому пути. Во-первых, Grid имеет доступ ко всем Nodes одновременно, что дает мне возможность «деактивировать» другие Nodes, кроме того, по которому в данный момент щелкнули. Во-вторых, наш GameInputComponent уведомляет только прямых дочерних элементов Game, которыми в настоящий момент являются только Grid и два Fleets. Конечно, мы могли бы проксировать событие на Node и Ship, если захотим, но на данный момент это не обязательно. Давайте будем простыми. К счастью, расширение этой функциональности должно быть тривиальной задачей.

Представляем компонент Grid Onclick

Имея это в виду, мы начнем с добавления самого первого компонента для объекта Grid:

Мы расширяем OnclickComponent, который просит нас реализовать Awake и Update (согласно требованиям IComponent), но также ClickOn (согласно требованию OnclickComponent). Прежде чем идти дальше, давайте удостоверимся, что у нас есть все бочки:

Если вы помните, в самой первой статье этой главы мы добавили метод Occupies к сущности Node. Этот метод проверяет, действительно ли указанная точка находится в границах этого Node. Мы можем снова использовать эту проверку и установить флаг IsActive для Node:

А затем прикрепите компонент к Grid, чтобы он заработал:

Вот и все! Если вы начинаете игру с npm start и открываете браузер, вы сможете включать и выключать Nodes, щелкая по ним:

Это было просто. Но мы еще не закончили, нам нужно написать несколько тестов, чтобы закрепить нашу победу.

Сетка тестирования

Это просто и должно быть вам знакомо. К настоящему времени мы провели подобное тестирование уже десяток раз. Я начну с создания макета:

И обновите соответствующий файл ствола:

Теперь мы можем обновить все тесты, которые использовались для непосредственного создания экземпляров Grid. Сначала Fleet макет фабрики:

А затем сама спецификация:

Отлично! И мы приземлились в идеальном месте. Давайте улучшим охват тестированием для Grid, проверив, что все его компоненты пробуждаются и обновляются:

Все это должно показаться знакомым. На этом этапе наш код должен успешно скомпилироваться с npm start, а все тесты должны пройти с npm t:

Тестирование компонента Onclick Grid

Потрясающие! Наша следующая остановка - тест на GridOnclickComponent. Первое, что нам нужно сделать, это подготовить спецификацию:

Здесь нет ничего сложного: мы создаем экземпляр компонента и поддерживаем его сущностью. Мы также проследим, чтобы Grid проснулся и сделал все необходимые приготовления.

Теперь, имея все фиктивные данные, мы можем просто ожидать, что самый первый Node станет активным, когда мы щелкнем в его границах:

Опять же, мы сможем успешно скомпилировать с npm start и пройти все тесты с npm t:

Тестирование компонента ввода игры

Это вишенка поверх нашего торта на сегодня. Мы некоторое время откладывали тестирование GameInputComponent, но больше не будем! Я начну с представления спецификации, как обычно:

Как и в случае с GridOnclickComponent, я создал экземпляр объекта, самого компонента и прикрепил их друг к другу. Компонент не несет особой ответственности, он просто «обрабатывает щелчок»:

Но как именно это проверить? HandleClick - это частный метод, и мы не можем просто вызвать его. И это законно, потому что то, как именно компонент выполняет свои обязанности, - это его детали реализации, которые нас не волнуют. Что нас интересует, так это то, что каждая дочерняя сущность Game, к которой прикреплено какое-либо OnclickComponent, получает уведомление, когда мы щелкаем внутри холста.

Мы можем легко подделать щелчок мышью. Мы также можем с легкостью высмеять Canvas, чтобы вернуть нам фальшивый балл:

Но как мы можем проверить, действительно ли был вызван OnclickComponent ребенка? Что ж, мы знаем, что к Grid прикреплен этот компонент. Мы также знаем, что он добавлен как первый дочерний элемент к Game. Мы можем рискнуть и запросить самый первый элемент из Game.Entities списка:

И это сработает! Как только вы запустите npm t, вы увидите, что тесты пройдены:

Но есть загвоздка. Мы зависим от порядка детей в Game. Этот тест вообще не касается этого. Более того, если по какой-то причине мы изменим порядок элементов, наш тест не пройдёт. И это проблема, поскольку мы не меняли никакой логики, относящейся к этому тесту. Другими словами, теперь мы получаем ложные негативы.

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

Д.И. - старый друг тестирования. Это один из самых простых и эффективных способов улучшить тестируемость вашего кода. Я не буду тратить время на подробное объяснение того, как это работает. К счастью, на эту тему есть множество статей, книг, подкастов и видео. Я продолжу при условии, что вы, уважаемый читатель, знаете и понимаете, как работает DI.

Внедрение зависимостей в игру

Зависимости, которые нас интересуют в этом случае, являются дочерними по отношению к Game: Grid и Fleet. Чтобы сделать их «инъекционными», я перемещаю их из Awake и вместо этого помечаю constructor как обязательные параметры:

Для этого потребуется обновить main файл:

А также game.mock:

Теперь, вернувшись в спецификацию, мы можем напрямую указать ссылку на Grid mock и следить за ним:

И это работает! Ваш код должен компилироваться с npm start, и все тесты должны пройти с npm t. Но есть еще одна загвоздка ...

Наши тесты проходят, пока Grid имеет GridOnclickComponent. Это предположение снова выходит из-под контроля данного конкретного теста. В любой момент мы можем удалить это из Grid и получить еще один ложноотрицательный результат.

Чтобы решить эту проблему, мы должны убедиться, что у mocked Grid есть несколько OnclickComponent. Мы не можем полагаться на GridOnclickComponent, поэтому мы должны определить поддельный:

Отлично сделано! Теперь наш тест охватывает только то, что должно. На этом этапе наш код должен успешно скомпилироваться с npm start, а все тесты должны пройти с npm t:

Вы можете найти полный исходный код этого поста в input-3 ветке репозитория.

Заключение

На этом завершается эта короткая глава. Мы узнали, как мы можем заполнить события щелчка от DOM body до конкретного Node и сделать их активными. Мы ввели абстрактную OnclickComponent, которая дает нам возможность делегировать событие без необходимости хранить информацию о конкретных респондентах. И, конечно же, мы тщательно протестировали все новые функции.

Следующая глава посвящена движению. Мы собираемся глубоко задуматься над механикой нашей игры. Главный вопрос для нас: «Как игроки могут перемещать свои Ships?» Планирую опубликовать его в феврале-марте 2021 года, с нетерпением жду встречи с вами!

Мне бы очень хотелось услышать ваши мысли! Если у вас есть комментарии, предложения, вопросы или любой другой отзыв, не стесняйтесь присылать мне в личном сообщении или оставьте комментарий ниже! Если вам нравится эта серия, поделитесь ею с другими. Это действительно помогает мне продолжать работать над этим. Спасибо, что прочитали, до встречи в следующий раз!

Это глава N из серии руководств «Создание игры с помощью TypeScript». Другие главы доступны здесь: