Семь итераций наивности или как я полтора года свою дебютную игру писал
С появлением у меня в первом классе Dendy вопрос кем я стану отпал сам собой буквально через пару недель — программистом конечно же. Я долго и упорно шел к этому, невзирая на отсутствие информатики в школе, работал в техподдержке известного всем регистратора параллельно с учебой в институте, но полноценная жизнь началась лишь в тот момент, когда меня наконец-то взяли хоть куда-то писать код.
Очень скоро я понял, что мало быть программистом, работающим от звонка до звонка и получающим за это деньги на карточку — всё самое интересное начинается, когда решаешь сам без всяких архитекторов, тестировщиков и тимлидов что-нибудь этакое написать и заставить работать. Желательно что-нибудь веселое и захватывающее. Игру, например.
Под катом лежат семеро очевиднейших (как мне сейчас кажется) граблей, неожиданно вставших у меня на пути, а потому способных с отличной от нуля вероятностью встать на пути любого, идущего дорогой разработки игр.
Всю свою жизнь я играл в компьютерные игры. Начал ещё в те времена, когда с десяток их помещалось на одной дискете 1.44 Мб. Никогда не понимал тех, кто говорит, что игры — это уход от реальности и повод для излишнего воображения о себе того, чего нет на самом деле. По-моему игры — это тренировка концентрации, разжигание жажды познания, практика в управлении ресурсами и тренажёр целеустремлённости. Неудивительно, что уже в первом классе я точно знал кем стану — программистом. И я им стал.
За те несколько последних лет, что я успел поработать по специальности, мне встретилось много интересных людей. Почему-то больше всего мне запали в душу два программиста, никак друг с другом не связанные; оба они пламенно мечтали изучить мобильные платформы, чтобы затем писать свои приложения. Как позже каждый из них честно признался, в игры ни один, ни другой никогда не играли, не играют, играть не собираются и вообще находят это занятие бестолковым, для малышей. На мой вполне резонный вопрос (заданный чуть ли не при первом знакомстве) что они собираются писать, когда наконец поймут, что готовы взяться за разработку собственного проекта под мобильные платформы, оба без тени сомнения заявили: «игры, конечно же».
Я тоже всегда мечтал выпустить собственную игру. И если бы кто-нибудь сказал мне 20 лет назад, что в будущем не надо будет иметь целый холдинг, чтобы делать это, я бы, наверное, меньше играл и больше занимался.
С момента появления рынка мобильных приложений прошло уже немало времени. Но пока я жил в подмосковье, у меня вечно находились более приоритетные занятия, нежели изучение этих самых мобильных платформ и выпуск приложения хотя бы для одной из них. Сначала я долго копил на телефон на android'е, параллельно заканчивая учёбу и не забывая поигрывать то в Starcraft II, то в Tropico 3; потом весь был поглощён трудом разработчика в разных не имеющих никакого отношения к мобильному рынку компаниях, а вечера неизменно просиживал за World Of Tanks. И вот однажды с моей семьёй случилось чудо, о котором мы давно мечтали — мы с женой и полугодовалым сыном переехали из подмосковья в карельский посёлок с населением в 3 тыс. человек, а работать стали удаленно. Высвободившиеся 4 часа времени, затрачиваемые ранее на дорогу, было решено на этот раз не тратить впустую.
Концепция
Конечно же я решил начать с чего-нибудь попроще, поэтому выбрал для своей затеи игральные карты — они являют собой чуть ли не идеальный тренажёр ООП. Java я к тому времени знал, а вот от любого C-языка меня почему-то воротило, поэтому приложение было решено выпустить под Android. Тем более, что эмуляторам я не очень-то доверял, а единственным моим физическим устройством был HTC Explorer с андроидом 2.3.3 на борту и 20 Мб свободной памяти.
Засучив рукава, я полез в маркет смотреть и сравнивать приложения конкурентов. Признаюсь, первое впечатление у меня было такое, что все эти игры делают те самые мои товарищи — люди, малозаинтересованные в играх. Ну или небольшие конторки, где директор имеет посторонний доход и чтобы капитал вращался, решил выпускать приложения, поскольку это сейчас в тренде — нанял программистов и, считай, готово. За редким исключением все игры выглядели даже на скриншотах как братья-близнецы — неизменный зелёный фон и заезженные картинки на картах точь-в-точь как на реальных.
Я прочитал несколько десятков статей на хабре о том как кто свои дебютные игры писал и заметил, что чаще всего сценарий начинающего игродела выглядит так: он (а в ближайшей перспективе — я) берёт себе какой-нибудь простенький проектик типа крестики-нолики или морской бой, коих в маркете и так навалом (ага, сказал человек, решивший делать очередную карточную игру), делает всё то же самое, что и у всех, поменяв цвета на оранжевый и салатовый (такого нет ни у кого!), затем постит приложение в маркете и вдруг обнаруживает, что его игра никому не нужна. Игродел недоумевает — он ведь потратил силы, ночей не спал, цвета подбирал и тайком даже позволил себе несколько раз перед сном, зажмурившись, подумать: «а может все-таки взлетит?» Он уже безвозвратно и страстно в свою игру влюблен (а как может быть иначе?), забыл о том, что хотел с самого начала выпустить что попроще, без претензии на мировое господство.
Мне в тот момент абсолютно некуда было торопиться, я спокойно работал на своей работе, а проектом решил заниматься по вечерам и на выходных. Я решил никаких прототипов «попроще» не писать, а сразу сделать игру, за которую будет не стыдно и которая даже если не взлетит, то в будущем, откопанная фанатами моей 10ой/79ой/133ей игры, сразу продемонстрирует тот факт, что я с первой же попытки пытался делать что-то особенное. Несколько недель у меня ушло просто на раздумья о том, что будет выгодно отличать мою карточную игру от других. Решение, когда я его нашёл, оказалось значительно проще, чем можно было себе вообразить — я просто решил сделать игру, в которую сам бы с удовольствием играл (кэп одобряет).
Я скачал себе кучу «Дураков» и хорошенько в них поиграл. Выглядело это так: Начинается новая игра. Кладём карты, берём карты, кладём, берём, кладём, берём, изо всех сил стараемся выиграть. Победил — ура! Проиграл — увы. Повторить до бесконечности.
Кто играл в WoT знает, что очень быстро там сам бой отходит на второй план, уступая место игре в прокачку боевой техники. Радость наступает теперь уже не от победы в очередном бою (хотя и это бывает), а от покупки нового танка. Представим на секунду, что все танки в этой игре с самого начала доступны и выбирать можно любой. Интересно играть? Не думаю.
Так и тут — в того же самого «Дурака» ради самой победы хочется играть только первый десяток матчей, потом — надоедает. Вывод очевиден: за победы надо давать деньги. А вот куда эти деньги тратить — другой вопрос, который, кстати, мучает меня до сих пор и к которому я до сих пор нахожу новые и новые ответы.
Можно позволить человеку на эти деньги покупать новые рубашки для карт и новые фоны для карточных стычек. Интересно будет играть? Ну, не так скучно как на «просто так», но на хит пока ещё не тянет.
А что если я не в «Дурака» люблю играть, а в «Кинга»? Вот оно!
Я придумал сделать сборник карточных игр, в котором за каждую победу ты получаешь монеты и на эти монеты можешь открывать новые карточные игры. Запахло уже чем-то верным. Тем более что топовый сборник карточных игр именно так примерно и выглядит, только там новые игры надо открывать за реальные деньги.
Теперь надо было определить количество и состав игр. По крайней мере на первое время, до запуска приложения.
«Дурак», конечно же. Это самая распространенная, самая, по-моему, любимая в нашей стране игра. Мы в деревне частенько коротаем с друзьями вечерок за этой игрой и чайником зелёного чая.
«Кинг», конечно же. В неё мы тоже играем иногда. К тому же в детстве я упарывался в эту игру под MS-DOS, соперничая с героями «Союзмультфильма» (Вадим Владимирович, моё почтение).
Был ещё один пасьянс, в который я играл-не-мог-наиграться лет десять тому назад на каком-то забугорном флэш-портале. Он назывался «Пирамида», но официальные правила пасьянса с таким названием расходятся с той игрой, в которую играл я. В моей игре класть поверх текущей карты в колоде нужно карту из пирамиды старше или младше по значению на единицу, в результате чего при определённой сноровке и удаче можно снести полпирамиды в один ход. С той игрой десять лет тому назад была, кстати, одна крупная проблема: её логика обрабатывалась на стороне сервера и потому после каждого нажатия страница перезагружалась (сейчас у меня есть подозрение, что не флэш это был — засланец какой-то). Эта игра жутко меня тогда затянула, но так же жутко и раздражала тем, что на одну партию тратилось столько времени. Я пообещал себе в том нежном 17-летнем возрасте когда-нибудь написать себе такую же, но без тормозов. А гештальты, как известно, надо закрывать.
Я начал активно читать в Интернете самые разные материалы, посвященные карточным играм и самим картам. Подобрал тематики мастей для человечков на картах, попытался копнуть в историю самих карт и понять отчего же мне так стыдно кому-либо признаваться в том, что я делаю карточную игру. Я не знаю насколько это только у меня, но по-моему карточные игры считаются какой-то достаточно маргинальной забавой, присущей не самым успешным слоям нашего общества. Впрочем, об этом чуть-чуть и позже.
Почитав в википедии про «Дурака», я был восхищен количеством модификаций к нему (сейчас статью уже отредактировали, модификаций там больше нет, но было штук 50, не меньше). Я решил, что должен во что бы то ни стало сделать хотя бы самые интересные к нему. Я поискал аналоги «Дурака» в маркете, желательно с кучей википедьевских модификаций, но нашёл лишь одного такого «Дурака», и то модификации там были во-первых в большинстве своём платные, а во-вторых можно было активировать не больше одной модификации за раз. А ведь смешивать-то их между собой — самое интересное! Засучив рукава, я решил отобрать наиболее интересные правила (коих получилось больше 20), а также не преминул добавить и своих, чего стесняться-то. Покупать их планировалось, естественно, тоже за выигранные деньги.
Я вообще с самого начала решил, что не буду уподобляться тем, кто установил игры на пьедестал своего способа выживания и потому вынужден брать «за простой дождь — 100 лир, за проливной дождь — 200 лир, за дождь с громом и молнией — 300 лир.» Ведь когда писатель пишет книгу, он в последнюю очередь думает о том как он будет её монетизировать, для него (как и для меня в данном случае, ведь я прямо писатель получаюсь, да-да, творческий человек, вот справка) самое главное — это самовыражение и творческий порыв.
В такой ситуации можно было бы сделать игру и вовсе бесплатной — без рекламы и встроенных покупок, но в этом случае я бы лишил себя удовольствия покопаться в API встроенных покупок и межэкранной рекламы, а также обошёл бы стороной целый аспект разработки мобильных игр под названием «монетизация». Так что я постарался соблюсти баланс — играть должно быть вполне комфортно и без доната, но если вдруг кто-то хочет поддержать разработчика и купить что-то — я только рад. При этом в покупках никакого ограничения на функционал, исключительно экономия времени.
Одна особенность в виде наград за победы, — хорошо, а две — ещё лучше. Я не отказывал себе в удовольствии помечтать о том, что еще можно было бы изменить в карточных играх так, чтобы мне они нравились больше. Я пытался докопаться до самой сути удовольствия от этой интеллектуальной забавы и однажды, отыграв уже сотни партий с друзьями в деревне, я уселся играть за стол с бабушкой моей жены, живущей в Москве. Я был поражён тому насколько игра преобразилась. Вместо тёплой и дружной атмосферы чаепития, происходило какое-то соперничество не на жизнь, а на смерть, и каждая победа или проигрыш воспринимались буквально как триумф или оскорбление соответствено.
В тот момент я понял, что игра в карты это ещё и, как ни странно, общение. Не было бы такого изобилия наших вечерних посиделок, если бы мы не разбавляли поединки беседой и шутками, не ели параллельно фрукты и не слушали какую-нибудь музыку. Я сразу же вспомнил Mario’s Game Gallery и Wild Board Games, где противники комментировали вслух происходящее на доске или столе. Что может быть приятнее возгласов жертвы, загнанной в угол?
Благодаря Марио, кстати, вспомнил я и ещё одну преинтереснейшую игру, в которую играл в его галерее — Go Fish! По-русски эта игра называется «Сундучки» и в нашей стране в неё играют несколько иначе. Суть этой забавы, если кто не знает, сводится к угадыванию наличия на руке у противника карт определенного значения. Угадал — получаешь их себе. Нет — очередь твоего противника. И в то время как за рубежом угадывают просто значение карт, у нас нужно ещё назвать их количество, цвет и масти.
Я решил, что в моей игре противники будут разговаривать, комментируя происходящее за столом. Такого уже не было ни у кого и тянуло на действительно исключительный продукт. Теперь настало время придумать — кто будут эти противники? Я начал раздумывать о том кто они обычно — люди, играющие в карты. Профессиональные картёжники. Пенсионеры. Шпана уличная. Студенты на лекции. Аристократы с сигаретами в мундштуке. Бездомные на лавочке в сквере.
Я хотел бы, чтобы у игры был смрадный и мрачный дух подпольного заведения, околонуарный стиль как в настольной игре «За бортом». А ещё я хотел меткое и броское название для своей игры, почти что торговую марку; название, за которое было бы не стыдно и которое я смог бы с гордостью произносить. И после нескольких дней мучительных раздумий я его нашёл — «Картёжный дом».
Объём этой затеи вызывал скепсис у тех, кому я пытался её в двух словах описать. Ведь если этого нет в маркете, значит это не так-то просто сделать, не так ли? «Да ты будешь годами свою игру писать» — говорили мне. — «Бросишь на полпути». Все эти беспокойства за меня и мою затею можно было понять. Мне же самому оставалось только повторять себе, что торопиться мне некуда, что у меня осадная тактика, что с работы я ради этого не увольняюсь, просто решил заменить ежевечерние покатушки в танчики разработкой.
Первая итерация наивности: никакой графики
Первая итерация наивности была у меня с первой версией игры, на которую ушло около двух-трёх недель. Работал я над проектом в свободное от работы и домашних дел время, а в условиях пока лишь только изучения платформы, работа шла и вовсе еле-еле. Хорошо если за вечер мне удавалось сделать хоть какую-то одну законченную игровую функцию.
Я, кстати, не умею рисовать. Вообще. Вдаваться в подробности, объясняя насколько всё плохо я смысла не вижу, поскольку так смотрю — у многих программистов есть эта черта. Вот я и решил, что напишу чистый функционал, а потом прикручу графику. Карты в руке стали у меня списком кнопок в виде LinearLayout, а всё происходящее — TextView с кратким описанием произведённых ходов.
Я понимаю, это глупость полнейшая и вряд ли у кого-нибудь хоть когда-нибудь хватит ума поступить так же — любой понимает, что надо рисовать хотя бы серыми картинками. С другой стороны, если у меня возникла в голове такая идея, то есть ненулевая вероятность, что то же самое произойдёт и с кем-то ещё. Вот мой совет таким людям, как я полтора года назад: не делайте так. Вам придётся переиначивать весь модуль управления, ловя куда нажал пользователь и определяя что он этим хотел сказать. Вам придётся вводить задержки между обработками ввода и выполнением соответствующего отклика, чтобы дождаться окончания анимации, которой у вас сейчас нет. Учитывая, что всё это придётся делать, разрывая и зашивая уже готовый код, поверьте мне, это будет болезненно.
Мне повезло осознать это достаточно рано и не переделывать куски уже существующего кода, а просто стереть всё и начать заново в тот момент, когда я понял, что в процессе нападения надо дать возможность ходить несколькими картами. Любое решение в этой ситуации в условиях карт в виде кнопок было бы обречено — в итоговый релиз оно бы не вошло, а время отняло бы.
Вторая итерация наивности: я сделаю всё идеально, а спорное — вынесу в настройки
Эта итерация на самом деле объединила в себе сразу две моих наивных точки зрения. Общее же у них то, что обе ошибки описаны в книге Алана Купера «Психбольница в руках пациентов». Поэтому наиболее общим советом было бы — читайте книги на разработческие и околоразработческие темы. Многие и многие ошибки, которые вы допускаете или собираетесь допустить, кем-то давным-давно обнаружены, надо лишь взять в руки книгу и позволить этому кому-то вас предупредить. К тому же — это отличное развлечение — внимать тем, кто понимает твои дрожащие руки и бессоные ночи в попытке создать шедевр.
Впрочем, обо всем по порядку.
Я не стал связываться с android-шаблонами, а решил делать всё на чистом canvas'е, разделив соответственно программу на два потока — поток управления и поток отрисовки. Свой выбор я могу объяснить тем, что мечтал (и так и не добрался до того, чтобы) ввести визуальные искривления в игре, а для подобного подхода стандартная приложеньевская разметка, как мне казалось, ну никак не подходила.
Когда с третьего раза у меня наконец-то начало что-то получаться, я нарисовал пустую карту и стал выводить текстом на ней её масть и значение. Мой успех вскружил мне голову. Я решил во что бы то ни стало сделать всё так, чтобы люди ахнули от удобства и идеальности моей игры. Я никогда к тому времени не держал в руках ни одно устройство от Apple, но слышал от нескольких людей, что там всё потрясающе удобно и органично. Решив сделать всё не хуже (и даже тайком мечтая о том, что люди будут переходить с буржуйского Apple на Android просто ради моей игры (ха-ха, ха)), я решил, что не нужно никаких кнопок «Взять» или «Бито». Достаточно просто потянуть карты на столе на себя или в сторону соответственно.
Я старался сделать игру максимально реалистичной — думал даже заставить проигравшего тасовать колоду руками и раздавать карты, но решил эту штуку отложить на потом. А вот что я действительно сделал, так это то, что карты клались в любое место стола. В результате, конечно же, возникала ситуация, когда более поздние карты ложились поверх уже побитых. Я долго отлаживал механизм запрета этого действия, но поняв, что компьютер рано или поздно всё равно может нечаянно так сделать (в том случае если двое сразу будут подкидывать карты, выбрав одни и те же конечные координаты анимации), добавил возможность нажать на любую карту, отчего та всплывала под каким бы количеством карт уже не находилась.
На такие мало что значащие мелочи у меня ушло достаточно много времени — около двух месяцев. Я пытался довести простейшего «Дурака» до состояния идеальности, прежде чем двигаться дальше, хотя впереди работы было ещё очень и очень много. От этого разрастался и код класса, отвечающего за отрисовку, и код контроллера управления со стороны игрока.
Позже я прочитал об этой особенности программистов у Купера. Он пишет, что если есть даже мизерно малая вероятность, что какое-то событие произойдёт, программисты всегда тратят время на то, чтобы сделать что-то для этой ситуации. Даже если вероятность события один к ста миллионам и оно не более чем мягкое неудобство, а время на то, чтобы разработать код специально для этого случая займёт две недели, разработчики всё равно стремятся покрыть все события, имеющие отличную от нуля вероятность.
Это, конечно, очередная глупость с моей стороны — недальновидная и упрямая упоротость. Учитывая, что мне предстояло навернуть ещё целую кучу модификаций на рисовалку и управлялку «Дурака», следовало сосредоточиться прежде всего на этих режимах, а уж потом на каких-то частных и редких случаях управления и отрисовки. Мой же подход противоречил в том числе и закону Парето, призывающему (в моей вольной трактовке) сосредотачиваться первым делом на наиболее важных аспектах. Как сказал Макконнелл в «Совершенном Коде»: «Скульптор всегда сначала создает грубую форму будущей скульптуры, а уж потом принимается за детали. Принимаясь же в первую очередь за детали, вы рискуете либо в ходе дальнейшей разработки выкинуть код, над которым трудились дольше, чем нужно было, либо — что еще хуже — оставить плохой код в проекте, пожалев его, ведь вы столько над ним работали».
Могли бы мои пользователи играть в «Дурака», если бы у них иногда нижние карты закрывались верхними? Могли бы. А могли бы они играть в задуманную мною игру, если бы в ней не было модификаций «Дурака»? Нет, не могли бы.
Поэтому третий мой совет себе и подобным мне (кэп гордится мною): сосредоточьтесь на главном, мелочи навернуть никогда не поздно. Если боитесь забыть про эту фишку или особенность — запишите себе куда-нибудь.
Сюда же, в эту же итерацию я положу и свою жуткую привычку, от которой почти уже избавился, — во всех спорных вопросах предоставлять выбор пользователю в настройках. В моём случае всё еще хуже, ведь любое раздвоение в трактовке модификаций я интерпретировал как новое правило.
Так, например, в Подкидном докладывать атакующие карты на стол должен первым делом атакующий, если же ему докладывать больше нечего, по часовой стрелке и в строгой очередности докладывают другие игроки. В жизни же я видел совершенно иные условия — карты на стол клали все подряд, не соблюдая никаких очередей. Кто успел, тот и съел. Какой вариант лучше? Да оба! Так появились «Подкидной» и субмодификация к нему — «Советский» (когда при подкидывании соблюдается строгая очерёдность). Однако это ещё не самый страшный случай.
Больше всего мне стыдно за «Пустого» «Дурака» (карты берутся из колоды только в том случае если карт на руках не осталось вовсе) и его субмодификацию «Фальшфеерный» (карты берутся сразу же как только закончились). Я просто не мог решить как лучше и не смог найти нигде информации о том в какой момент выдаются карты — сразу же по окончанию их в руке или в конце хода. «Ок, — решил я. — Разделим на две модификации». Стыд и позор.
Позже я прочитал об этом у Купера. Он утверждает, что любой спорный вопрос разработчики склонны выносить в настройки, но это в корне неверная позиция — если создатель программы не может решить как лучше, то уж пользователь точно не будет этот вопрос решать.
И я лишний раз убедился в этом, когда недавно обнаружил, что в классическом 2048, в настройках оказывается можно выбрать поле 5×5. Признаться, обычно я в любой игре первым делом лезу в настройки. Но в мобильных приложениях все настолько стремительно, так часто ты достаешь телефон на какие-то пять минут, пока ждешь чего-то, что не до настроек. Поэтому разработчики, не знающие как сделать лучше, и решающие сделать и так, и так, а выбор предоставить в настройках, вот мое к вам обращение: вы все равно делаете этот выбор, выбирая дефолтное состояние. Предоставлять альтернативу или нет — решать вам, но помните, что большинство людей до настроек и альтернативного варианта скорей всего просто никогда не доберутся.
Третья итерация наивности: я взялся сразу за самый крупный кусок
Прошло полгода, я закончил «Дурака» со всеми 40 модификациями и субмодификациями, которые для себя выбрал. Начался отпуск и весь его я просидел, отлаживая и доводя до ума эту каракатицу. При этом накопившаяся усталось давала о себе знать — иногда, если я видел ошибку, я просто вставлял ещё один if, не вникая в суть того, что здесь не так, так мне хотелось поскорее уж закончить. К тому моменту я что-то подотчаялся и собирался уже было выпускать одного только «Дурака» с модификациями.
К этому времени классы «Дурака» разрослись до неимоверных размеров, стали шаткими и нагромождёнными. Я подсчитал, что с учётом всех ограничений на сочетания модификаций, количество вариантов правил составляет более 11 млрд комбинаций. Естественно, что о тестировании всех вариантов не могло быть и речи. Поэтому известная парадигма «ладно, тут мы закончили, остальное поймаем на этапе тестирования» просто не работала. Мне приходилось умозрительно для каждой модификации перебирать в уме все остальные и думать где может возникнуть коллизия. Уверен, что абсолютно всё я так и не отловил, ведь мне следовало бы пройтись в том числе по всем сочетаниям, когда модификаций одновременно три, четыре, пять и так далее.
Надо отметить, что к моменту окончания работы над «Дураком» концепция этой игры на глобальном уровне претерпела значительные изменения. Я стал рассуждать о том что может подтолкнуть человека покупать новые модификации и пришёл к выводу, что ничего кроме как бонус к победным деньгами. Тут, конечно, многие мне могут возразить, что естественным двигателем является интерес к геймплею, а не приз, но начав перебирать модификации в уме, я первым делом прошёлся по тем из них что увеличивают количество карт в колоде и пришел к выводу, что сам ни за что не стал бы играть двумя колодами за те же победные деньги. Ведь заработок в этой ситуации, поделенный на время, уменьшился бы. Поэтому я постарался примерно оценить увеличение не только времени, но и сложности; как-то справился с тем, чтобы цена модификации соответствовала увеличению прибыли в процентном соотношении и внедрил эти коэффициенты повышения заработка. Однако в этой ситуации всплыла сложность: я не мог позволить игроку включать купленные единожды модификации, поскольку это в скором времени привело бы к бардаку со всеми одновременно включенными правилами и огромными заработками. Поэтому в качестве ограничителя я решил ввести жетоны. Один жетон — одно активированное правило (при условии, что оно куплено). Жетоны выдавались по одному за каждую победу в «Дурака» и в случае проигрыша все активированные правила сбрасывались (позже я счел такой подход слишком жестоким и немного изменил правила отключения модификаций при проигрыше, но это уже такие мелочи, до которых мы тут опускаться не будем).
«Дурак» по своей сути вывернутая наизнанку относительно победы игра. Суть её не в том, чтобы стать первым вышедшим из игры, а в том, чтобы не остаться в дураках. И по идее следовало бы не давать ничего вышедшему, у дурака же отнимать определенную сумму. Но лично я в этой ситуации, видя, что дело пахнет жареным, просто выходил бы из игры, избегая каждый раз наказания. Можно было бы считать количество прерванных игр и оценивать по ним степень честности игрока, но такой алгоритм имеет кучу дыр: начиная от ошибок в системе, при которых игра внезапно завершается, и заканчивая отключениями телефона из-за севшей батареи или высвобождения внезапно понадобившейся памяти. Поэтому было решено проигравшему не давать ничего, оставшимся вышедшим — давать монеты и жетон.
С покупкой модификаций все было тоже не так-то просто. Нельзя было — и я это понимал — просто дать линейный список модификаций и позволить покупать любые. Иначе человек купил бы все интересные ему правила, на остальные бы просто забил, изучив их суть и умозрительно сыграв партейку в них. К тому же меня всегда привлекали всяческие блок-схемы развития. В этом плане схема развитя техники в WoT мне всегда нравилась куда больше, нежели параллельная схема покупки уровней и техники в Hill Climb Racing. Поэтому я разработал схему развития модификаций, постаравшись объединить ветки по тематикам и засунуть в самый конец наиболее радикальные искривленя правил игры.
Однако если с модификациями все было еще куда ни шло, то вот с соперниками, аренами и рубашками было очевидно, что никто их покупать не будет. То есть будут, но только после того как исследуют все влияющие на игру изменения правил. Я бы по крайней мере именно так и поступил — сначала функционал, потом только красОты. И если с соперниками шанс еще какой-никакой был, ведь это новые фразочки, разбавляющие игру, то с рубашкам и фонами проблема была более чем очевидна. Один раз залезли бы посмотреть какие есть варианты и больше не возвращались. Поэтому я ввел такое понятие как «Лотерея» и начал разыгрывать не влияющие по сути на геймплей элементы в ней. «Лотерея» появлялась у меня после определенного количества побед. Таким образом в моей игре появились вещи, которые нельзя было просто купить за деньги — их можно было только выиграть путем длительной игры.
После третьего разработанного мною экрана — «Лотереи» — я наконец-то понял основные моменты, которые использовал на каждом из экранов и написал абстрактные классы, выполняющие все типичные действия. Работа над «Пирамидой», «Сундучками» и «Кингом» пошла значительно быстрее — на них всех ушло около 6 месяцев ежевечерних упражнений. К тому времени я и сам поднабил руку, выработав подход и решения для типичных задач вроде анимации или переключателей режимов отрисовки. Тем не менее, система продолжала предподносить сюрпризы.
Так например, я с ужасом обнаружил в какой-то момент, что механизм анимаций и отложенного выполнения у меня слишком уж тяжеловесный.
Я сразу решил, что проверять в потоке рисования долетела ли анимируемая карта, а потом вклиниваться в поток управления и выполнять какое-то логическое действие, неправильно. Поэтому я делал так — с одной и той же временной константой вызывал анимацию и запускал отложенное действие. Это отложенное действие наследовалось у меня от AsyncTask'а, в котором onBackground выполнялось Thread.sleep (), а onComplete — то, что мне нужно сделать.
Таких отложенных действий в каждый момент времени выполнялось у меня с десяток, основными потребителями были, конечно же, противники. Они думали какой картой пойти или какую подбросить; автоматически после каждого прикосновения к экрану они ждали, что уж это-то прикосновение последнее и ближайшие полчаса ничего происходить не будет, поэтому нервно поглядывали на таймер, чтобы с определенной минуты начать вопить: «Эй, ты где там?»; параллельно с этим они следили за тем на каком действии игрока игра застопорилась, чтобы крикнуть: «Эй, карты побей» или что-нибудь в этом роде. В результате, с ростом количества отложенных действий (и противников) система просто начинала жутко тормозить, а то и вообще отваливалась. Оказалось, что андроидовский AsyncTask в своем doInBackground действительно кушает ресурсы и эта функция там не просто так, в нее надо что-то запихивать — получение ли данных с удаленного сервера или какие-то параллельные вычисления, а не пустое ожидание. Поэтому отнаследованный от AsyncTask'а класс я переписал, после чего все проблемы с производительностью исчезли:
public abstract class Action {
protected int interval; // интервал, через который рванет
private boolean cancelled = false; // флаг отмены действия
public Action(int interval) {
this.interval = interval;
}
public void cancelTask() {
this.cancelled = true;
}
public void execute() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (!cancelled) {
actionAction();
}
}
}, interval);
}
// непосредственно действие
protected abstract void actionAction();
// фабрика клонирования этого отложенного действия
public abstract Action copyForDelayedExecute();
}
Впрочем, я отвлекся.
Очевидно же, что начни я с «Пирамиды», к которой не предполагалось никаких модификаций, и опыт написания движка от начала и до конца был бы у меня куда раньше. Глядишь, и архитектруа «Дурака» была бы не такой грязной. Я бы успел узнать много нового о том как следует писать систему, а в случае чего мог бы без проблем «Пирамиду» впоследствии и переписать. Начав же с «Дурака», я нагородил в нем кучу ошибок по неопытности, но таки заставил его работать, подперев со всех сторон чем мог и теперь боялся на него дышать.
Поэтому еще одно правило, добытое кровью и потом, для всех, кто только начинает: среди подобных друг другу крупных элементов начинать надо всегда с наименьшего.
Прочти я этот совет с год назад, я бы сказал: «ну это понятно, только вот я хочу сначала справиться с самыми тяжелыми элементами, чтобы на потом оставить что попроще. Таким образом, когда я закончу с этим большим и разветвленным алгоритмом, до победного конца останется уже всего-ничего». Так-то это так, только вот с ненабитой рукой тяжеловесный и разветвленный алгоритм пишется хуже. «Дурака и «Пирамиду» в этой последовательности в сумме я писал почти год. Начни я с «Пирамиды» и общий срок составил бы всего каких-нибудь 7–8 месяцев.
К тому же, берясь за самое тяжелое с самого начала, есть шанс попросту отступиться, не справившись. И это будет куда хуже, нежели после уже созданного частично кода, наткнуться на непреодолимое препятствие. Совершенные к тому моменту подвиги подтолкнут к поиску компромисса, в то время как о