Как написать игру в стиле Tower Defense
Если вы не знакомы с жанром, Tower Defence представляет собой стратегическую игру, где игрок покупает и располагает вооруженные башни в стратегических точках, чтобы остановить волны врагов, которые пытаются достичь базы и уничтожить ее. Каждая последующая волна врагов обычно сильнее предыдущей, достигается это за счет увеличения устойчивости к вашему оружию и способности быстрее двигаться. Игра заканчивается в случае, когда вы выстояли все волны врагов(Победа!), либо же в случае когда враги добрались до базы и уничтожили ее(Проигрыш!). Вот скриншот игры, которую мы закончим писать в конце урока:
Как вы можете видеть на картинке, враги появляются из левой верхней части экрана и следуют вдоль зеленого маршрута к базе игрока. Вдоль дороги множество платформ, где игрок может установить башню. Игрок может купить ровно столько башен, сколько позволяют запасы золота. Радиусы атаки башен, показаны белым кругом, если враги находятся внутри этого круга, башня будет стрелять по ним пока не уничтожит, либо враги не выйдут из радиуса атаки.
Подготовка ресурсов- Все классы использованные в игре
- Папка с библиотекой Cocos2D
- Папка ресурсов с необходимыми графикой и звуками
Вначале, добавьте фоновую картинку на сцену. Откройте класс HelloWorldLayer.m и добавьте следующие строчки кода внутрь условия «if» в методе «init»:
Первая строчка в разделе #1 позволяет слою принимать события касания. Остальная часть кода в разделе #2 добавляет фоновый спрайт на нашу сцену. Фоновая картинка помогает увидеть, где игрок может ставить башни. Теперь вам нужно задать несколько точек на экране, касаясь которых игрок сможет строить башни. Чтобы сохранить смысл наших действий, все точки будут находиться в файле ".plist", в котором их можно будет легко изменить. TowerPosition.plist находится в папке Resources и уже содержит несколько позиций для постройки башен внутри. Рассмотрите этот файл, вы найдете массив словарей, которые содержат всего два ключа: «x» и «y». Каждый словарь представляет собой позицию башни по ее координатам на экране. Теперь вам нужно прописать этот файл и установить базы для башен на карте. Откройте HelloWorldLayer.h и добавьте следующую переменную (внутрь фигурных скобок после строчки interface):
Внесите следующие изменения в HelloWorldLayer.m:
Скомпилируйте и запустите приложение, вы увидите квадраты по сторонам дороги, они будут служить базой для установки башен.
Теперь эти базы готовы, давайте построим несколько башен! Вначале, откройте HelloWorldLayer.h и добавьте следующую строчку после закрытия фигурных скобок:
Синтезируйте переменную башен в HelloWorldLayer.m ниже строчки @implementation:
Затем, создайте новый класс, который будет представлять башни. Добавьте новый файл из шаблона iOS\Cocoa Touch\Objective-C. Назовите класс Tower, и сделайте его подклассом CCNode. Замените содержимое Tower.h следующим:
- attackRange: определяет расстояние с которого башни могут атаковать врагов
- damage: определяет сколько урона башня наносит врагам
- fireRate: определяет сколько времени нужно башни на перезарядку
- Может ли игрок позволить такое удовольствие? Метод canBuyTower проверит, имеет ли пользователь достаточно золота, чтобы купить башню. Хотя, на данный момент, у игрока все золото форта Нокс и метод будет возвращать всегда YES.
- Нарушает ли игрок правила постройки? Если tb.UserData задана, тогда на том месте уже стоит башня и вы не можете построить новую.
Но к чему все это вооружение без «плохих парней», давайте позовем их на вечеринку!
Политика игры: Враги, Волны и ВэйпоинтыДобавьте следующий код в HelloWorldLayer.m:
Скомпилируйте и запустите игру:
На карте шесть вэйпоинтов, по этому пути будут следовать враги. Перед тем как вы дадите друзьям проиграть в игре, вам нужно добавить несколько вспомогательных методов. Для начала добавьте описание методов в заголовочный файл, чтобы другие классы могли использовать эти методы без предупреждений от компилятора. Откройте HelloWorldLayer.h и добавьте следующие описания методов перед строчкой " end":
Далее откройте HelloWorldLayer.m и добавьте следующие строки в конец файла (перед end):
Внесите следующие изменения в HelloWorldLayer.m:
- maxHP: определяет сколько ударов может выдержать враг
- walkingSpeed: определяет как быстро двигается враг
- mySprite: хранит визуальной представление врага(спрайт)
- destinationWaypoint: хранит ссылку на следующий выэйпоинт
- Вычисляется вектор, пролегающий от нынешней позиции к целевой, ему присваивается значение 1, для удобства работы(нормализованная переменная).
- Нормализованный вектор умножается на скорость передвижения, для вычисления количества пути для преодоления в данном кадре. Ему присваивается нынешняя позиция для получения следующей.
Переключитесь на HelloWorldLayer.m и опишите метод:
Все выше написанное достойно объяснения. Самая важная часть- метод LoadWave; он считывает данные из Waves.plist. Взгляните на Waves.plist, и вы заметите, что он содержит 3 массива. Каждый из них представляет собой волну, которая является группой врагов, появляющихся вместе. Первый массив содержит шесть словарей. Каждый словарь представляет собой врага. В этом уроке, словарь хранит только время появления врага, но может содержать в себе тип врага, его способности, здоровье и т.д. Метод loadWave проверяет, должна ли появиться следующая волна, создает соответствующих врагов, основываясь на информации о волне, и расписывает их время появления соответственно. Метод enemyGotKilled проверяет количество врагов на экране, если их нет, вызывает следующую волну. Позже этот же метод будет использован для проверки победы игрока. Скомпилируйте и запустите игру сейчас. Враги двигаются к вашей базе!
Атака башенТеперь в Tower.m:
Самая важная часть в коде- метод update в классе Tower. Башня постоянно будет проверять на наличие врага внутри радиуса атаки. Если таковой имеется, башня поворачивается к нему и начинает стрелять. Как только враг помечен, как цель, метод задает расписание стрельбы башни согласно ее скорострельности. Каждый враг содержит список башен, стреляющих по нему, если враг умрет, они все будут оповещены об этом факте и перестанут стрелять. Скомпилируйте и запустите ваше приложение. Расставьте несколько башен на карте. Вы увидите, как башни начнут стрелять во врагов, проходящих внутри их радиуса, как меняются полоски их здоровья до тех пор, пока они не умирают.
Осталось добавить всего несколько деталей, чтобы получить готовую версию tower defense. Неплохо бы добавить звуковые эффекты, научить базу получать урон от врагов и ограничить количество золота игрока.
Финальные штрихиplayerHp показывает сколько жизней у игрока, а CCLabelBMFont это надпись, которая демонстрирует это количество. gameEnded задается, когда игра закончена! Также добавьте следующие описания методов:
Теперь откройте HelloWorldLayer.m и внесите следующие изменения:
Это добавляет метод, который уменьшает количество жизней игрока, обновляет надпись и проверяет, закончились ли жизни у игрока. Если да, игре конец! Метод getHpDamage вызывается, когда враг достигает базы. Вы ранее уже добавили его в update метод в Enemy.m. Скомпилируйте и запустите игру. Позвольте врагам дойти до вашей базы. Вы должны увидеть, как количество ваших жизней уменьшается, пока игра не оканчивается.
Пришло время урезать бюджет! Множество игр внедряют опцию “zero-sum”, предоставляя игроку ограниченное количество ресурсов на постройку в начале игры. Ваша игра будет иметь нечто похожее, но в упрощенном виде. Откройте HelloWorldLayer.h и добавьте следующие переменные:
Также как с жизнями, была добавлена переменная количества золота(playerGold) и надпись для его отображения(ui_gold_lbl). Также добавьте описание нового метода:
Теперь откройте HelloWorldLayer.m и сделайте следующее:
Новый код вверху проверяет, хватает ли золота каждый раз, как игрок строит башню. Если хватает, башня строится, цена башни вычитается из количества золота игрока. Нужно также награждать игрока за убийство врагов. Добавьте следующую строчку в метод getDamaged:(внутри условия “if”) в Enemy.m:
Запустите игру и вы увидите, что вы можете строить ровно столько башен, сколько позволяет запас золота. За убийство врагов золото добавляется. Восхитительная система, неправда ли?