Как мы делали зомби игру

в 7:10, , рубрики: App Store, cocos 2d, cocos2d, game development, Gamedev, зомби, игростроение, игрострой, игры, первые шаги, Песочница, метки: , , , , , , , , ,

image

В начале лета мы решили сделать игру для iPad-a. Идея пришла после того как вся компания дружно отбила себе пальцы в Tap Battlefield. Механика была простейшая – все, что нужно было делать, это стучать наперегонки по своей половине экрана. Выигрывал тот, кто успевал набить большее количество касаний.

В какой-то момент мы решили сделать свой Tap Battelfield, с графикой и бонусами.

Tap Deathmatch: Zombies!

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

Чтобы разнообразить геймплей и отойти от чистого фингер-рестлинга, добавили два бонуса. Один достаточно банальный (но тем не менее эффектный): позвоялет в течении нескольких секунд давить зомбаков прямо пальцем. Второй – посложнее: нужно набрать некоторый минимум зомбаков и успеть зажать кнопку до того как кончится отведенное для этого время, чтобы выпустить их целой стаей!

В качестве саунд-дизайнера дебютировал диджей и музыкант Paul B. Графику делали частично сами, частично привлекая 1 фрилансера: иллюстратора и аниматора. В игре около 40 ачивок, 3 режима (на время с бонусами, с бонусами, но без ограничения по времени и просто на время без бонусов), 4 уровня сложности.

А теперь перейдем к интересным вопросам, которые мы повстречали на своем пути.

Кодинг

Для начала я хочу уточнить, что это мой первый опыт написания игры на cocos2d, и на iOS вцелом. Так что если мои решения не до конца правильные буду только рад уточнениям и замечаниям в комментариях или в личных сообщениях. До этого я занимался написанием приложения под iPhone на cocoa.
Cocos довольно легкий framework, особенно для тех кто уже писал на objective c что-нибудь. Я не буду останавливаться на базовых вещах, о них можно прочитать в документации на основном сайте. Статья предполагает, что вы уже знакомы с основными классами данного framework'а.

Проблема №1

Первая и самая большая проблема, с котрой пришлось столкнуться, была рендер большого количества спрайтов на экране (в нашем случае это около полутора тысяч спрайтов). Если создавать спрайты стандартным методом:

CCSprite *sprite = [CCSprite spriteWithFile:@"filename.png"]; 
[layer addChild: sprite]; //  поместили спрайт на слой

в котором мы передаем текстуру спрайта, в качестве параметра, при инициализации. Используя этот способ возникает сразу несколько проблем:

  • Минимальный размер текстуры, хранящейся в памяти 256*256 px, и, если ваша текстура спрайта меньге, то вы просто будете впустую тратить место в памяти
  • Слой будет рендерить отдельный спрайт каждый раз, тем самом в случае 1000 спрайтов на поле, у вас будет происходить 1000 циклов рендеринга, что весьма затратная штука

Для решения таких проблем умные люди придумали класс контейнер CCSpriteBatchNode, который инициализируется следующем образом:

[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"sprites.plist"]; // 1
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:@"sprites.png"]; // 2
[layer addChild:spriteSheet];

Теперь чуть более подробно. Для всего этого понадобится программа texturePacker или zwoptex, c помощью которых вы сможете создавать такие plist'ы и текстуры с набором спрайтов. В интернете есть много туториалов, как работать с ними, так что, подробно останавливаться на этом не будем. Так вот, 1-ой строчкой мы загружаем наши спрайты в кэш, а второй строчкой создаем CCSpriteBatchNode из тексуры с нашими спрайтами. Стоит уточнить, что максимальный размер текстуры с набором спрайтов (2048*2048 для iPad2 и 4096*4096 для iPad3). Теперь все спрайты с текстурами из файла sprites.png, мы будем добавлять не на слой, а на spriteSheet, который будет рендериться за один проход. В итоге мы избавились от проблемы пустого места, так как spriteSheet обычно делают как можно большего размера, а вторых от проблемы большого количества циклов рендеринга, заменив его одним.

Проблема №2

Вторая проблема с которой пришлось столкнуться — это textAlignment в классе CCLabelBMFont. Для начала непосредственно про этот класс. В качестве параметра при инициализации ему передается файл с расширением .fnt (которые можно создать с помощью программы Glyph designer) в котором описано расположение символов вашего алфавита и ссылка на png файл с алфавитом. Тем самым, если ваш label предполагает очень частое обновление то, чтобы не рендерить .ttf файлы для отображения текста, вы сразу передаете ему текстуры симоволов и, тем самым, намного упрощаете работу для opengl.
Так вот, нужно было выставить выравнивание текста по правому краю, и, вроде бы, все должно быть просто с учетом свойства alignment у этого класса, но на его изменения label вообще никак не хотел реагировать. После долгих мучений, я нашел в имплементации этого класса такие строчки:

-(void) createFontChars{
    CGSize tmpSize = CGSizeZero;
    tmpSize.width = longestLine;
    tmpSize.height = totalHeight;
    [self setContentSize:CC_SIZE_PIXELS_TO_POINTS(tmpSize)];
}

Тоесть, размер лейбла, выставлялся просто константой, которую разработчики либо забыли закомментировать, либо я не знаю. Но, после удаления этих строчек, свойство alignment стало реагировать на изменения и все заработало, как надо.

Плюсы использования CCLabelBMFont:

  • Гораздо менее затратный рендеринг очень полезен для часто обновляемых лейблов.
  • Позволяет легко использовать тексты со сложными эффектами, недоступными обычным способом.

Минусы:

  • Размер можно менять только используя свойство scale, и в некоторых случаях шрифт получается очень нечетким, так что приходится иметь несколько .fnt файлов для одинаковых шрифтов, но с разным размером.

Другие советы

Для повышения производительности советую использовать замену стандартному NSArray — CCArray, сравнение время выполения методов у них можно найти в этой статье. Все спрайты лучше помещать в CCSriteFrameCache — если вы создаете анимированные объекты. Всю анимацию лучше тоже помещать в CCAnimationCache, так как создание каждой довольно затратная процедура.
Еще очень помогли во время разработки две книги: Strougo R., Wenderlich R. — Learning Cocos2D A Hands-On Guide, Learn cocos2d Game Development

Общение с инвесторами/паблишерами

Как и любому независимому разработчику, нам особо не на кого было рассчитывать. Более того, сама игра не представляет собой “вирутальный мир”, куда игрок погружается с головой, а разработчик потихоньку высасывает из него денежки. Наша история проста как хлеб с маслом и шансы тут 50/50 – либо пойдет, либо нет.

В связи с этим, при переговорах с паблишерами/инвесторами особой поддержки мы не получили. Все ориентируются либо на свой опыт либо на опыт разработчика. А у нас мало того, что первая игра, так еще и геймплей особенно ни на что не похож. Мы обращались в Chillingo и, надо признать общение с ними нас очень порадовало. Отвечали на вопросы и письма быстро и очень уважительно, они были первыми кто установил наш бета билд с тестфлайта. Для себя сделали вывод, что обязательно обратимся к ним еще раз на более «серьезном» проекте.

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

Ну и напоследок пару слов о маркетинге.

Маркетинг.

С точки зрения маркетинга (demodisc) мы, помимо общеизвестных стандартных инструментов, решили реализовать следующие:

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

Статистика

Единственная статистика, которая дается сегодня в играх, это лидерборды (взглянув на которые, иногда пропадает желание играть дальше). Мы решили расширить ее, сделать более интересной и вовлекающей. В TDM:Z мы отображаем вклад каждого айпада в общий процент убитых зомби. Мы также можем давать результат по стране, региону или всему миру (и на этом в будущем хотим достроить некоторые ачивки/статистику).

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

Скидка на шер

Поначалу мы придумали хитрый инструмент – скидка 50% за владение кодом (которые даются каждому платному пользователю для шеринга друзьям). Этот вариант подразумевал наличие поля для ввода этого кода на видном месте, и именно на этом нас запорол Apple. Конечно мы и не думали продавать коды сами за меньшие деньги, а вот использовать их для большей виральности – безусловно да.

В результате решили сделать скидку за шер. Выглядит это так: инэпп для активации полной версии можно купить либо за 3 доллара, либо сделать шер в двух соц сетях и купить за 1 доллар. Причем есть промежуточный вариант, расшарить только в одной соц-сети и цена будет 2 доллара. Очень интересно будет посмотреть статистику.

Пасхалки

Эта идея была особенно актуальна при наличии того самого поля для ввода. Но и за неимением оного пасхалки не исчезнут и мы их обязательно планируем реализовать в 1.1.

Некоторые из них будут менять внешний вид игры, другие будут открывать новые игровые бонусы. Какие-то предоставят доступ к секретному контенту. Часть пасхалок будут открываться при получении самого высокого уровня ачивок, некоторые будут спрятаны на определенных сайтах или форумах.

Вот собственно и все.
Сегодня мы стартовали и будем рады если Вы скачаете приложение и оставите свои комментарии здесь. Мы очень старались, но понимаем, что это только начало пути.

Автор: Antonlipetsk48

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js