Ignite – сохранение игрового процесса

Реализовал, и избавился от кучи сопутствующих багов, механизм сохранения игры. Честно сказать, я и не думал, что это будет настолько трудно. Но сейчас я имею на руках билд с работающими сохранениями и загрузками. Остался только один баг, над поиском которого я работаю сейчас. Он состоит в том, что после того, как игра была загружена (в отличии от создания новой игры), смена освещенности зон карты становится более быстрой и вместо плавной смены видимой области тенями, смена происходит рывками.

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

  • Система сохранения / загрузки – основная проделанная работа в этом патче.
  • Сохранение происходит в файл player в корне игры. Загрузка, естественно, из него же. Я еще не реализовывал никакого интерфейса загрузки, поэтому никакого выбора слотов под сохранение нет, также как и проверки на существование файла (при его отсутствии игра выпадет). По-умолчанию я поставил, как сохраненку своего дебажного перса с кучей всяких штук. Может при пригодится при поиске ошибок.
  • Сохраняться в игре через F10
  • Исправление ошибок предыдущего релиза.
  • Снятие ограничения на количество отрисовываемых кадров в секунду. Не знаю почему, но XNA искусственно занижает значение fps при ручном их ограничении (у меня было 60). Сейчас вы можете увидеть совершенно безумные цифры в 2500+ fps в главном меню и прирост в самой игре на 50-80%.
  • Ускорение анимации передвижения. Игра стала чуть более быстрой в замен еще большей резкости передвижения. Дайте мне знать, что вы думаете по этому поводу!

Изменения в Ignite 0.42

Это список планируемых изменений к следующей версии Ignite. Его содержимое является subject of change, т.е. будет меняться ровно до тех пор, пока я не выпущу следующую версию. У меня заняло почти три месяца переписывание движка игры под архитектуру XNA, но теперь, когда очень многое из задуманного (в плане механики работы приложения) реализовано, я могу начать выпускать полноценные версии гораздо чаще. Как минимум раз в месяц будут выходить сборки с новым контентом.

Планируемые изменения:

  • Меню опций будет сохранять изменения
  • Будет добавлен режим без анимации (как в привычных тайловых roguelike играх)
  • Поддержка большего количества разрешений монитора
  • Ролевая система снова будет работать (она перекочует из 0.40 билда)
  • При генерации мира будет учитываться карта распределения влажности (появятся лужи, озера и океаны)
  • Игровые локации условно будут делиться на биомы с общими характеристиками
  • Некоторые биомы будут представлять опасность для игрока (переохлаждение, тепловой удар)
  • Частота появления редких ресурсов напрямую будет зависеть от опасности биома для игрока
  • Генерация монстров будет напрямую зависеть от биома
  • Больше монстров
  • Больше предметов
  • В мире будут генерироваться руины, которые будут представлять интерес для исследования

Ignite 0.41 – Новая версия!

Привет! Я наконец-то готов представить новую версию Игнайта на новом движке. Сразу оговорюсь, что данную версию стоит рассматривать исключительно, как пре-альфу, а это значит, что она может (и будет) содержать баги и недоработки. Прошу относится к этому с пониманием.

Итак, когда дисклаймер закончен, перехожу к требованиям. Игра стала более требовательна к железу (но, как мне кажется, должна без тормозов пойти на любом компьютере, который обновлялся в последние 5 лет).
С точки зрения требования к ПО, у вас должны быть установлены пакеты NET Framework 4.0 (http://go.microsoft.com/fwlink/?linkid=182804) и XNA4 Framework (http://www.microsoft.com/Download/en/details.aspx?id=20914). Достаточна высока вероятность, что у вас уже установлены эти пакеты (т.к. достаточно много игр требуют их).

Ignite prealpha 0.41
Зеркало: http://dl.dropbox.com/u/31655535/Ignite_pa041.rar

Этого должно быть достаточно, чтобы запустить игру. Основные фичи данной версии:

  • Генерация мира на основе псевдослучаных алгоритмов и всяких карт с учетом динамических термальных изменений (разведите костер на границе снежной территории)
  • Возможность выбора разрешения игры (правда пока в пределах соотношения сторон 4:3)
  • Собирание ресурсов и крафтинг предметов из полученных материалов
  • Возможность строительства из подручных материалов
  • 14 предметов для крафта, среди них: факел для освещения местности вокруг себя, костер для обогревания, оружие и инструменты для выживания
  • Волки периодически будут находить вас в глуши и будут пытаться съесть
  • Система повреждений, которая разделяет персонажа на несколько зон с разными типами повреждений
  • Несколько эффектов повреждения зон тела (пробитое легкое, поврежденные мускулы, подрезанное сухожилие и др.), которые распространяются как на игрока, так и на его противников
  • Несколько видов повреждений(колющий, дробящий)

Что я не успел реализовать, но на что есть намеки в игре:

  • Открытые раны не загнивают и не приводят к инфекции, они просто проходят со временем
  • Нет критического эффекта огненного урона. Факел просто наносит урон, но не может поджечь жертву.
  • Нет критических повреждений связанных с головой/пастью
  • Нет термального воздействия окружающей среды на персонажа
  • Выбор разрешения в пределах соотношения сторон монитора 4:3. Буду раз, если вы расскажете, каких разрешений не хватает именно вам
  • Опции не сохраняются между сессиями

В первую очередь я жду от вас репорта о том удалось ли запустить игру (т.к. я использовал для загрузки текстур не принятый официально метод, то есть небольшая вероятность того, что движку не будет хватать набора XNA4 Framework Redistributable для загрузки текстур), и пожеланий об улучшении игры.

Спасибо за внимание.

Состояние на 11.04.2012

Я сейчас усиленно работаю над тем, чтобы в скорейшем времени выпустить пре-альфу в публичный доступ. Фактически все, что осталось сделать – это добавить еще несколько эффектов ранения (сейчас персонажи только истекают кровью при ранении проникающим и режущим оружием), добавить всплывающие подсказки для противников, настроить динамическую сложность, чтобы можно было посмотреть не только на то, как орда волков спавнится в ближайшем лесу, но и на крафт со строительством.

Также открытым остается вопрос о том, что делать при смерти персонажа. Пока я не хочу усложнять (себе) реализацию игры путем того, чтобы вставлять переключатель хардкор-софткор режимов. Поэтому наверняка в пре-альфе будет работать только софткор и при смерти, персонаж будет ронять все свои вещи и случайно переноситься на небольшое расстояние. Если у вас есть какие-то дополнения или пожелания по этому пункту, то высказывайте их в комментариях.

Изменения на 09.04.2012

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

Боевая система: 

  • Монстры теперь охотятся на игрока
  • Игровой персонаж может наносить удары руками и ногами в дополнении к повреждениям от оружия.
  • Волк царапает лапами и кусает пастью
  • Тело любого персонажа разделено на области повреждения
  • С увеличением тяжести ранения той или иной области тела, персонажу становится все труднее владеть ею: при сильных ранах рук, он хуже сможет владеть оружием (наносить урон или парировать удары), при повреждении ног, ему сложнее будет передвигаться и т.д.
  • В бою учитывается рост персонажей: низкий персонаж будет стараться нанести удар в нижние части тела высокого противника.

Местные новости

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

Но вернемся к нашим баранам Игнайту: сегодня практически все время, что я смог уделить разработке игры, я потратил на отлов багов. Самый шикарный из них был баг, который снижал производительность примерно в 10000 раз (до менее 1 кадра в сек) из-за того, что я сменил свою “интеллектуальную” систему атрибутов на обыкновенное присваивание:

C#
1
GameAttribute ga = game.Attribute;

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

Кроме этого бага, я отловил львиную долю багов в системе поиска пути и добавил расчет пути для монстров размеров в 9 тайлов:

… а также добавил нового монстра – волка.

Алгоритм поиска пути (часть 2)

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

Алгоритм поиска пути

Привет, сегодня я расскажу о алгоритме поиска пути, который используется в Игнайте. Это алгоритм А* с некоторыми нестандартными условиями:

  • первое из них – изменяющийся размер юнитов (1 – 16 клеток)
  • второе – несмотря на свой размер, юнит всегда за раз передвигается на 1 клетку (т.е. на расстояние в 1/4 – 1 собственного размера)
  • третье – некоторые юниты должны иметь возможность проходить сквозь стены (разрушая их) в случае, если нет ближайшего обходного пути
  • четвертое – перемещение в 4-е стороны
  • и последнее – алгоритм не должен замедлять выполнение программы и, одновременно, рассчитывать собственный путь для каждого юнита отдельно

Предупреждаю сразу, что это первая итерация моего алгоритма и я приветствую любые замечания и улучшения, особенно те, которые направлены на ускорение его работы.

Итак, для начала определимся с тем, что у нас уже есть до начала работы алгоритма:

  • алгоритм пересчитывается только после изменения определенных параметров (в моем случае – это инкрементация счетчика времени)
  • путь просчитывается не для всех существ на карте, а для готовой выборки из рядом находящихся юнитов (этот список готовится отдельно)
  • более того, если существо не передвигалось в этом ходу, то для него не нужно искать новый путь

Теперь можно запускать сам алгоритм:

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

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

C#
1
2
3
4
5
6
7
8
9
10
11
private bool MovementCheck(MovementDirection md)
{
int x, y; // положение юнита
//...
if (md == MovementDirection.Left && unitSize == UnitSize.Size3x3)
{
return Tiles[X - 1, y].Passabillity && Tiles[X - 1, y - 1].Passabillity
&& Tiles[X - 1, y + 1].Passabillity;
}
//...
}

, которая проверяет проходимость сразу нескольких клеток.
Для дальнейшего ускорения расчетов, можно получать от этой функции не bool, а числовое значение сложности перехода (и, например, -1, если прохода нет).

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

  • Удаляем первую родительскую клетку из открытого списка, т.к. ее больше не нужно проверять и заносим ее в закрытый список. Клетки которые находятся в закрытом списке никогда не должны попадать в открытый

Оценка пути
Теперь, когда в открытом списке есть несколько элементов, встает вопрос: какой же из них нужно выбрать для последующего анализа? Единого ответа на этот вопрос существовать не может, т.к. вариантов тут такое же множество, как и задач, которые можно решить с помощью данного алгоритма.
В нашем случае должна быть предварительно проведена оценка стоимости пути для каждой клетки. Определить стоимость пути можно по следующей формуле:
F = G + H
, где F – стоимость продвижения на клетку А
G – стоимость продвижения со стартовой клетки до клетки А
H – примерная стоимость продвижения с клетки А до конечной клетки

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

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

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

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

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void Update()
{
if (game.updateCounter == UpdateCounter.TimeIncrement)
{
openList.RemoveAll();
closedList.RemoveAll();
Push(new GridElement(x,y), openlist);
SavePath = null;
} else if (game.updateCounter == UpdateCounter.TickUpdate && PathDidnotFound)
{
int i = 0;
while (i < _MAXSTEPS)
{
GridElement Next = FindNextElement(openList);
if (SavePath == null && i != 0) SavePath = Next;
CalculateGridElement(Next);
i++;
}
}
}

Теперь, если мы предположим, что основным побуждением изменения таймера внутриигрового времени являются действия игрока, и эти действия имеют задержку выполнения, например 250 мс (т.е. не больше 4-х действий в секунду), то имея частоту обновления игры 60 Гц, мы получаем, что данные вычисления будут выполняться, как минимум 15 раз до того, как игрок совершит следующее действие (которое побудит существо пересчитать свой путь). Константа _MAXSTEPS должна быть вычислена экспериментально.

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

Система повреждений: зоны урона

Только что закончил рисование и программную часть отображения зон урона для игрока. Этот индикатор находится в нижней-левой части скриншота. Здоровье игрока (и всех персонажей) теперь представлено не просто безликим числом, а состоянием его тела. Тело любого гуманоида делится на голову, торс, ноги и 2 руки. Игрок умрет, когда состояние его тела станет критическим и продержится на таком уровне определенное время. Каждая зона имеет собственные уязвимости перед повреждениями. Например, кинжалом можно пробить грудь и повредить легкие, что приведет к удушью персонажа, а позднее – к смерти, если быстро его не вылечить; или топором можно отрубить конечность и тогда персонаж теряет возможность пользоваться предметами этой рукой.. и т.д.

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

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

Что я планирую показать в следующей бете

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

  1. Создание уровня. Я достаточно сильно поменял структуру уровня, по-сравнению с предыдущими версия Игнайта. В первую очередь это можно заметить в том, что персонажи могут быть разного размера (сейчас 4 и 9 клеток) и они по-умолчанию больше “клетки уровня”. Это изменение полностью готово.
  2. Система добычи материалов и крафта. Это то, на чем я акцентировал внимание последние несколько дней разработки. Персонаж может практически полностью разрушать окружающий мир (сейчас по-средством инструментов, в в последствии магии и как эффект боя) и иногда получает за это полезные материалы, которые могут пригодится ему в крафте вещей. Это изменение практически готово, не хватает только пары финальных (для этой версии игры) рецептов для крафта металлического оружия.
  3. Биомы: температура и влажность. В Игнайте существует динамическая система регулирования окружающего мира: растет трава, несколько деревьев сегодня могут стать началом большого леса завтра и т.д. Это то над чем я работаю сейчас. Я создал интересную систему создания карт температуры и влажности, которая позволяет мне регулировать перепад этих величин из одной области мира в другую. С помощью этих показателей я могу генерировать биомы, которые плавно переходят один в другой. На данный момент готово несколько из запланированных биомов: тайга, пустыня, средняя полоса.
  4. Погода: в демоверсии температура окружающей среды будет меняться с течением суток, но остальные погодные эффекты будут реализованы позже.
  5. Персонаж. Сейчас персонаж-игрок имеет только инвентарь. Ближе к релизу, я перенесу характеристики из прошлой версии Игнайта и сделаю его зависимым от условий окружающей среды, в частности температуры. Также я планирую использовать в Игнайте более сложную систему повреждений, чем была в прошлом, но это также будет реализовано позднее.
  6. Монстры. В релизной версии будет присутствовать несколько монстров, в основном животных. Уже сейчас работает система боя, но монстры пока не могут находить игрока, т.к. я еще не реализовал A* для своих реалий.
Фактически, это все изменения, которые я планирую реализовать до выхода следующей публичной версии игры. Я постараюсь завершить ее в течении 2-3 недель. И я уверен, что это получится, если загрузка на работе не будет слишком высокой.