- PVSM.RU - https://www.pvsm.ru -
В данном посте я расскажу о своем опыте написания игры-симулятора эволюции одноклеточных организмов на прямоугольной плоскости. Кроме разработки алгоритмов симулятора, речь пойдет о проблемах с которыми я столкнулся при разработке данного проекта на C#, а также о его портировании для работы в браузере. В конце статьи будет ссылка на готовую к игре версию и на все исходники. Если я вас заинтересовал — прошу под кат.
Перед тем как мы приступим — я хочу коротко рассказать о тех проектах, которые вдохновили меня на написание данного симулятора. Первую аналогию вы могли провести еще по скриншоту в шапке поста, ведь мой проект внешне довольно сильно похож на игру «Жизнь» [1], придуманную математиком Джоном Конвем в 1970 году. Еще больше меня вдохновили вот эта [2] и эта [3] статьи других хаброюзеров. Чтоб не гонять уважаемого читателя по ссылкам, коротко опишу о чем идет речь в данных статьях: первая — модификация игры Конвея с добавлением туда естественного отбора, а вторая — моделирование разумной жизни на базе нейронных сетей.
Писать еще один клон игры «Жизнь» я не хотел, да и идея естественного отбора мне настолько понравилась, что я решил сконцентрироваться именно на эволюции. Название пришло само собой — «The strongest survives».
Вот требования, которые я ставил себе при разработке:
В TSS клетки имеют много показателей, от которых зависит их следующее состояние. Они могут анализировать окружающую обстановку и принимать на основе этих данных решения, которые помогут им выжить. На их приоритеты при осмотре окрестностей влияют модификаторы, записанные в геноме. Например, есть параметр агрессия. Когда клетка видит другую клетку с чужеродным геномом, то она прибавляет к стремлению двигаться в ту сторону этот модификатор (агрессию). То же самое с голодом, коллективностью, тягой к яду и тягой к мертвым клеткам. После расчетов выбирается сторона с наибольшей суммой модификаторов.
Основные правила игры:
Клетка может сделать один ход раз в тик. Точнее, она осматривает площадь вокруг, как это показано на картинке и выбирает приоритетное направление: вверх, вниз, влево, вправо или стоять на месте.
Также клетка может размножиться. Размножение происходит делением, один раз за тик, если у клетки достаточно энергии. При этом, рядом должно быть пустое пространство, где создается новая клетка с таким же геномом, либо клетка с мутировавшим геномом. При этом ее уровень энергии делиться поровну между родительской и дочерней клетками. Требуемый для размножения уровень энергии определяет пользователь, но модификатором к нему выступает параметр «репродуктивность». Этот параметр храниться в геноме. Чем он выше — тем меньше энергии нужно клетке для размножения.
Как-то так представлял себе я эту игру, в то время. В целом, что-то подобное и получилось.
Геймплей заключается в том, что пользователю предоставляется редактор констант вселенной, в котором он может изменять условия обитания организмов и наблюдать за тем, как они приспосабливаются. Звучит не очень впечатляюще, но здесь довольно много значений, доступных игроку (около 30), меняя которые можно получить множество уникальных вариаций результата. Подробней о каждой константе вы можете почитать в мануале в папке с игрой или под спойлером.
Mutation_Enable — позволяет включить или отключить мутацию клеток при размножении.
Mutation_AttackChildrenMutantsOfFirstGeneration — если это свойство отключено, то клетки не могут атаковать своих потомков первого поколения, когда те мутируют.
Mutation_AttackParentIfCellIsYouMutant — если это свойство отключено, то мутировавшие клетки не могут атаковать своих предков первого поколения.
Mutation_ChangedValuesAtOne — показывает сколько раз изменяются значения, отвечающие за поведение клеток, при каждой мутации. Например, если значение 10, то 10 раз будет выбрано и изменено на 1 случайное свойство клетки, отвечающее за поведение. Может быть от 1 до 200.
Mutation_ChancePercent — шанс мутации при размножении.
CellAge_Max — максимальный возраст клетки.
CellAge_AdultCell — возраст взрослой клетки. У клеток-детей уровень агрессии не выше CellGenome_Child_Aggression и они не могут размножаться.
EnergyLevel_CreatingCell — уровень энергии у клеток, при их генерации на старте.
EnergyLevel_NeededForReproduction — уровень энергии, при котором клетка может размножиться. Может варьироваться из-за CellGenome_ReproductionRange.
EnergyLevel_MaxForCell — максимальный уровень энергии, которую может накопить клетка.
EnergyLevel_DeadCell — уровень энергии, получаемый от мертвых клеток.
EnergyLevel_DefFood — уровень энергии, получаемый от еды.
EnergyLevel_PoisonedFood — уровень энергии, получаемый от яда.
EnergyLevel_MovesFriendly — уровень энергии, получаемый клеткой, когда к ней движется родственник или она движется к нему. Как правило он намного меньше чем уровень энергии обычной еды. Способствует созданию колоний.
EnergyLevel_MovesAggression — показывает сколько энергии отнимает клетка у чужеродных клеток при нападении.
CellsCount_MaxWithOneType — максимальное количество клеток на поле с одинаковым геномом.
CellGenome_Child_Aggression — уровень агрессии у клеток-детей.
CellsCount_MaxAtField — максимальное количество клеток на поле.
EnergyEntropyPerSecond — уровень энергии, который теряет клетка при каждом тике.
Special_FoodCountForTick — количество еды, генерируемое при каждом тике вселенной.
Special_PoisonCountForTick — количество яда, генерируемое при каждом тике вселенной.
CellGenome_HungerRange — диапазон значений голода при генерации клетки.
CellGenome_AggressionRange — диапазон значений агрессии при генерации клетки.
CellGenome_ReproductionRange — диапазон значений репродуктивности при генерации клетки. Чем выше значение, тем меньше энергии нужно клетке для размножения.
CellGenome_FriendlyRange — диапазон значений коллективности при генерации клетки.
CellGenome_PoisonRange — диапазон значений влечения к яду при генерации клетки. Обычно отрицателен.
CellGenome_CorpseRange — диапазон значений влечения к мертвым клеткам при генерации клетки.
Так выглядит этот редактор в веб версии.
А в версии под Windows можно еще и редактировать место, где генерируется еда или яд.
В результате нескольких месяцев разработки, я написал 4 версии своей игры. Первые две — для тестирования и отладки логики вселенной симулятора, третья — релизная версия под Windows, четвертая — версия для браузеров. Сейчас я быстро пробегусь по первым двум и уже потом буду рассказывать об особенностях основных версий.
Это первая рабочая версия моей программы. В данной версии еще не реализовано большей части игровой логики и она имеет много багов. Рендеринга тут нет, все выводится в текстовое поле в виде символов. Такой вот текстовый вывод работал очень медленно (1-2 тика в секунду), но, все же, есть в нем что-то ламповое.
Как ни странно – вторая версия программы. Ее я писал для лабораторных. В этой и последующих версиях игровая логика идентична.
На эту версию я потратил больше всего времени, но она и является наиболее проработанной. Рендеринг фреймов здесь занимает 20-30 мс и не зависит от размеров поля, да и сам тик обрабатывается довольно быстро. Пользователь может создавать огромное игровое поле (хоть 2000х2000 ячеек). Есть возможность просматривать информацию о каждой клетке, просто кликнув на нее.
Демонстрация работы программы.
При написании данной версии своего проекта мне пришлось решить множество проблем. Самые запоминающиеся решения я опишу здесь.
1) Ручной рендеринг. Так как я решил писать велосипед — я делал отрисовку без движка, используя стандартные средства WPF для отрисовки примитивов. Но это позволило мне максимально оптимизировать отрисовку именно под свою программу.
Когда я только начала делать отрисовку — вся канва перерисовывалась с нуля при каждом фрейме, что очень било по производительности. Но потом я написал алгоритм, который хранил прошлый кадр в буфере и при отрисовке нового — закрашивал места, где были объекты, но теперь нет, а на месте, где они появились — рисовал объект. Не знаю насколько быстро это работало бы на движке, но здесь производительность выросла в разы и перестала зависеть от размеров поля.
Отсутствие движка также упростило портирование под браузер, там я использовал тот же алгоритм.
Но в этом способе есть и минусы — часто возникают помехи на изображении, особенно это заметно в WPF версии.
2) Динамический редактор классов. Чтоб не переделывать по сто раз форму, на которой отображались поля редактирования настроек вселенной, я использовал рефлексию и написал динамический редактор, который читал поля передаваемого объекта (в данном случае — объект с настройками) и строил форму для их редактирования.
Вот так выглядел этот редактор в версии WPF.
Через некоторое время после написания WPF версии мне захотелось портировать ее под браузер. Результат вы можете увидеть в шапке статьи, либо, лично перейдя на сайт и попробовав.
Я немного знал Javascript, но мне совсем не хотелось переписывать полторы тысячи строк кода игровой логики на нем. Но выход нашелся — я решил использовать Bridge.NET, открытый компилятор C# в Javascript. Да, дорогой читатель, ты все правильно понял — теперь мы пишем под браузер на C#. Благодаря этому компилятору я смог использовать язык, который хорошо знал. Оставалось только переписать рендеринг и остальной код, связанный с отображением. По причине Javascript лени, веб версия менее функциональна, чем версия под Windows, но служит неплохой демонстрацией работы симулятора.
Справедливо отметить, что мне, все же, очень пригодились знания Javascript и HTML из-за особенностей работы браузеров.
При разработке данного проекта я сильно подтянул свои навыки в программировании в целом. На данный момент все версии игры доступны на этом сайте tss-game.cc.ua [4]. Если вы сами хотите приступить к разработке или просто посмотреть код — вот мой гитхаб [5], тут вы можете найти все версии моей программы с обширными комментариями. Надеюсь, вам было интересно читать о моем опыте, возможно, эта статья вдохновит и вас на что-то подобное, как меня вдохновили другие статьи в свое время.
Автор: KogerCoder
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-2/254251
Ссылки в тексте:
[1] «Жизнь»: https://ru.wikipedia.org/wiki/%D0%96%D0%B8%D0%B7%D0%BD%D1%8C_(%D0%B8%D0%B3%D1%80%D0%B0)
[2] эта: https://habrahabr.ru/post/154015/
[3] эта: https://habrahabr.ru/post/265201/
[4] tss-game.cc.ua: http://tss-game.cc.ua/
[5] гитхаб: https://github.com/KogerCoder
[6] Источник: https://habrahabr.ru/post/327792/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox
Нажмите здесь для печати.