Практика 14

Карточная игра

Что предстоит сделать?

Сегодня вы потренируетесь использовать классы  и вспомните как работать с модулями в js.

Задача состоит в том, чтобы добавлять в карточную игру новые типы карт с новым функционалом.

Возьмите код игры из репозитория: https://bitbucket.org/frontschoolnsk/lesson14/src

Задание на практику

1. Установите зависимости проекта и запустите http сервер - npm run start. Игра доступна по адресу http://localhost:8080.

Понаблюдайте, как игра играет сама в себя.

В файле index.js создаются колоды карты и запускается игра. В заданиях следует править только этот файл, если явно не сказано менять другие файлы. Также можете создавать свои файлы под классы.

Загляните в файлы Game.js и Card.js, посмотрите на стадии хода, какие действия происходят с картой, какие возможности по расширению заложены.

2. Сейчас все скрипты подключены в index.html по одному. Воспользуйтесь тем, что Chrome уже поддерживает использование модулей ECMAScript из коробки и сделайте так, чтобы все скрипты подключались с помощью конструкций import и export:

- Уберите из index.html все скрипты кроме index.js: <script type="module" src="index.js"></script>
- В других файлах со скриптами допишите в конце export default с той сущностью, которую нужно экспортировать по-умолчанию.

- Используйте ошибки в консоле Developer Tools, чтобы понять, в каком модуле чего не хватает и импортируйте недостающее конструкцией import.
- В результате игра снова должна работать без ошибок.

3. Во всем коде типы определены по-старому, через прототипы. Изоляция кода при этом обеспечивает за счет техники IIFE. Благодаря использованию модулей ECMAScript каждый файл изолирован и IIFE больше не нужны.

Новый синтаксис с классами совместим с прототипами. Чтобы убедиться в этом перепишите TaskQueue с использованием class и без IIFE:
- Уберите самовызывающуюся функцию.
- Перенесите вверх функцию runNextTask, потому что это не метод TaskQueue.
- Перепишите TaskQueue на синтаксис с классами.
- export default поставьте сразу перед инструкцией class.

4. Создайте новые карты:

- Duck с именем «Мирная утка» и силой 2
- Dog с именем «Пес-бандит» и силой 3

После добавления новых типов замените карты в колоде шерифа на уток, а в колоде бандита - на собак.

Функция isDuck должна возвращать true для утки, а функция isDog — для собаки.

Если все сделано правильно, то внизу карты утки должен быть текст Duck➔ Card, а у собаки Dog➔ Card.

 

5. Метод getDescriptions в Card создан для того, чтобы на картах появлялась дополнительная информация. Его функционал хочется расширить. Причем так, чтобы это работало и для уток, и для собак, и для всех остальных существ, которые будут добавляться.

- Создай новый тип Creature и унаследуй его от Card.
- Duck и Dog должны наследоваться от Creature.
- Переопредели в классе Creature реализацию getDescriptions на новую. Теперь в ней должны возвращаться две строки описания в виде массива: одна из getDescriptions в Card, вторая из функции getCreatureDescription, из  index.js.

Используя те же колоды убедись, что у уток появилась надпись «Утка» над строкой с цепочкой наследования, а у собак надпись «Собака» над цепочкой наследования.

6. Добавьте новую карту "Браток" (Lad). Сила карты 2, наследуется от Dog. Замените в колоде бандита собак на двух братков. Добавьте в описание карты «Чем их больше, тем они сильнее».

Чем больше братков находится в игре, тем больше урона без потерь поглощается и больше урона по картам наносится каждым из них:

Защита от урона      =  количество * (количество + 1) / 2
Дополнительный урон  =  количество * (количество + 1) / 2

Чтобы следить за количеством братков, удобно использовать статические методы класса Lad. Добавьте классу методы:

static getInGameCount() { return this.inGameCount || 0; }
static setInGameCount(value) { this.inGameCount = value; }

Хоть inGameCount явно не объявляется, при первом вызове setInGameCount, оно будет создано со значением value.

- чтобы обновлять количество братков в игре переопределите методы doAfterComingIntoPlay, doBeforeRemoving
- чтобы рассчитывать бонус к урону и защите стоит завести статический метод getBonus в классе Lad.

Чтобы в getBonus обращаться к другим статическим методам можно использовать this, а не имя класса Lad.

- переопределите методы modifyDealedDamageToCreature и modifyTakenDamage, чтобы они использовали бонус.

 

7. Добавьте новую карту Изгой (Rogue). Сила 2, наследуется от Creature. Её особенность в том, что перед атакой на карту забирает у нее все способности к увеличению наносимого урона или уменьшению получаемого урона. Одновременно эти способности забираются у всех карт того же типа, но не у других типов карт. Изгой получает эти способности, но не передает их другим Изгоям. Для проверки:
const seriffStartDeck = [
    new Duck(),
    new Duck(),
    new Duck(),
    new Rogue(),
];
const banditStartDeck = [
    new Lad(),
    new Lad(),
    new Lad(),
];

- Изгой похищает эти способности: modifyDealedDamageToCreature, modifyDealedDamageToPlayer, modifyTakenDamage
- Чтобы похитить способности у всех карт некоторого типа, надо взять их из прототипа
- Получить доступ к прототипу некоторой карты можно так: Object.getPrototypeOf(card)
- Чтобы не похищать способности у других типов, нельзя задевать прототип прототипа
- Object.getOwnPropertyNames и obj.hasOwnProperty позволяют получать только собственные свойства объекта
- Удалить свойство из объекта можно с помощью оператора delete так: delete obj[propName]

Это не то же самое, что obj[propName] = undefined
- После похищения стоит обновить вид всех объектов игры. updateView из gameContext поможет это сделать.

Практика 14

By khalfina

Практика 14

  • 63