Как написать игру за 1 день или Очередной сопливенький пост-наполовину мануал о том, как быстро освоить C#

в 7:37, , рубрики: .net, game development, история, разработка

Задумали мы с приятелем (и по совместительству одногруппником) написать курсовую работу «Танчики» (самые обычные, 2D). Впрочем, не такие уж обычные, а танки в лабиринте. Вообще, задумывалось все как грандиозный и улучшенный клон флешевой одноименной игрушки.

И не надо фукать, игру за один день написать реально. Ну, может быть, вы не сделаете из нее конфетку, может быть в ней будет куча багов… Но если нужно завтра показать прототип проекта, клаву в руки — и вперед!

Изначально план был примерно таков (пишется все на C#, WindowsForms, графика — GDI+, сервер — WCF):

  1. Разобраться с алгоритмом генерации лабиринта (или, точнее, декомпилировать вышеупомянутую флеху и слямзить код оттуда);
  2. Нарисовать все это дело + один (пока — свой) танк;
  3. Заставить танк двигаться (причем так же, как в оригинальной игре);
  4. Приделать WCF-службу, которая будет раздавать клиентам лабиринт;
  5. Добавить службе второй танк и синхронизацию движений между игроками;
  6. Добавиьт полет снаряда;
  7. Прикрутить базу данных, допилить графику, перевести проект с Windows Forms на WPF.

Как видно, план весьма подробный, но все же недостаточно для того, чтобы сказать, что это четкое руководство к действию. Хотя, жить можно. Забегая вперед скажу, что, все-таки, нельзя. Мы начали не с того…

Времени у нас было предостаточно — три недели, но так уж вышло (ну да, ну да, не надо тут...), что сели делать мы его за 4 дня до сдачи. Почему пост называется «Как написать игру за 1 день»? Потому что фактически мы писали ее один день.

Лабиринт

Трудности начались почти сразу же — а как сгенерировать лабиринт? Лабиринт ведь не простой, алгоритм Эллера as is тут не подойдет. Это — не «идеальный» лабиринт, он имеет множество дорожек вокруг одного препятствия и может содержать замкнутые области.

Декомпиляция исходной игры ничего не дала, т.к. код был не читабелен. Вернее, читабелен, но то ли создатель постарался, догадываясь, что найдутся умельцы вроде нас, то ли декомпилятор криво код достал… Но разбираться в миллионе переменных с названиями _loc2, _loc4, _loc6 и подобными у меня желания не было вообще никакого, к тому же, время поджимало. Пришлось думать самому.

После нескольких часов раздумий и большого количества чая в моей голове мелькнуло слово «рекурсия» — и алгоритм был придуман. В коде лабиринт был представлен двумерным массивом структур MazeCell, которые, в свою очередь, имели два поля — нижняя граница ячейки и верхняя граница (оба поля — простые bool, изначально установленные в true). Может быть, код выложу чуть позже, а пока объясню суть: лабиринт не строить нужно, а ломать. Т.е. сначала определяем количество ячеек (комнат) в лабиринте и устанавливаем им все препятствия (оба поля — в true). Потом определяем две ячейки, где стоят наши танки. Обязательным условием является прямой доступ одного танка к другому. На карте могут быть замкнутые области, но танки должны быть либо вне их, либо оба — внутри такой области. Поэтому тут вступает в дело рекурсия — берем ячейку правого танка и идем к левому, в качестве параметра передавая следующую ячейку. Когда доходим до танка — идем назад тем же маршрутом, но уже разрушая нужные стенки в тех ячейках, через которые мы проходим.

Ну и, наконец, финальная стадия — просто бегаем по лабиринту (напомню, это обычный двумерный массив) и ломаем случайные стенки в случайных ячейках. Все, лабиринт готов, надо его просто нарисовать, сущие мелочи! Алгоритм был реализован спустя пару дней. Именно поэтому мы и писали игру 1 день.

Движение

С рисованием особых трудностей не было, поэтому писать там просто не о чем. Вот то ли дело — движение… Заставить двигаться танк по диагонали было не так уж просто. Признаться, мы так и не успели это сделать. Вернее, он двигается по диагонали, но то, КАК он это делает, лучше не видеть. Плюс ко всему при смене направления танк замирает на полсекунды на месте и только потом двигается куда надо. У нас не было времени и инструментов, чтобы проверить теорию, но, думаю, это потому, что мы обрабатывали нажатия кнопок по событию формы KeyDown, хотя надо было бы отлавливать их по таймеру.

WCF-служба, второй танк и синхронизация движений между игроками

Вот тут-то и начались проблемы. Как мы поняли позже, начинать работу надо было именно с этого пункта, и уже под него подстраивать лабиринт, клиентов и все остальное, и вот почему. Главная проблема — это двумерный массив. WCF не работает с двумерными массивами. Нам пришлось изрядно извращаться, чтобы переделать сие чудо в List<MazeCell[]>. Ну, если бы мы решились изменить архитектуру, проще было бы сделать обычный массив. На поиск ошибки ушло немало времени, но еще больше — на ее исправление.

Переписывать почти весь класс лабиринта не было ни сил, ни времени, поэтому мы сделали просто небольшую обертку, которая там, где надо, разворачивала список в массив, а после всего сворачивала его назад в список. Но и это не все — WCF полна подводных камней, на которые мы наткнулись во время работы. Если нет практики — вы их непременно обнаружите. Сюда относятся и потоки на стороне службы, и куча разных параметров у контракта, и передача пользовательских классов клиенту (Внимание! Напомню тем, кто забыл — в таких классах не может быть методов, это исключительно контракт данных!). В общем, было весело.

Теперь о координатах. Мы решили (и правильно сделали) передавать не весь лабиринт от клиента клиенту, а только лишь изменяемые характеристики — координаты танков. Танк уехал, координаты изменились — отправляем новую позицию сопернику, а его клиент сам все перерисует. Так же задумали поступить и со снарядами.

Завершение: база данных, графика, WPF

Мы просидели за игрой весь день и почти всю ночь — я пошел спать в 3:30 утра, т.к. уже почти уткнулся носом в клавиатуру и ничего не соображал. Мой друг посидел еще часик и тоже пошел спать. Защита назначена на 9 утра. К 3:30 у нас был почти реализован клиент и был сервер. Базу, нормальную графику и WPF присобачить не успели. Сдали ли мы проект? Нет. Мы слишком споткнулись на службе, т.к. практики в этой сфере у нас не много, пришлось много экспериментировать, что съело очень много времени. Зато сейчас мы почти спецы по WCF.

За курсовую работу нам поставили тройку, сказав, что идея очень классная, но реализация хромает (да мы и не отрицаем). Но реально ли сдать такой проект за 1 день? Да, более чем. Главное — вера в себя, как бы банально это ни звучало. И желание творить. За время работы мы трижды сделали «крайне маловероятное» и раза два «невозможное». К «невозможному» можно отнести и саму игру. Да, кодим мы уже около двух лет (в смысле, учимся), но это первый проект такого масштаба. Когда мы поступали, мы вообще не понимали, как можно написать игру. Вернее, понимать-то мы понимали, но для нас на тот момент это было невозможно. Но если пробовать и верить в свои силы, даже невозможное станет реальным. Просто, может быть, это займет чуточку больше времени. К такому же «невозможному» можно отнести и передачу двумерного массива с WCF-службы на клиент. Да, напрямую это сделать нельзя, но выкрутиться всегда как-то можно. А насчет «выучить C# за день»… Ну, выучить, конечно, не выучишь, но вот в экстремальных условиях быстро въехать в суть проблемы и набраться опыта точно получится.

За сутки мы проделали колоссальный объем работы и, более того — это повод для моей маленькой гордости. Все-таки, прототип игры мы сделали, и сделали за 1 день. Будь у нас больше практических навыков, мы бы успели прикрутить даже нормальную базу. Негативный опыт — тоже опыт, теперь у нас есть навыки планирования, проектирования систем и много знаний по WCF-службам.

Так что удачи вам, главное — пробовать и не бояться!

Автор: Cheaterz

Источник

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