Визуальная новелла 18+
Всем привет! Это мой второй пост по визуальной новелле, которую я начал делать на днях! И к вашему вниманию представляю первого женского персонажа. Ее имя Кайла! Ниже будут два ее рендера. Ах да оставляйте свои отзывы и предложения и надо ли выкладывать NSFW РЕНДЕРЫ?
Jaws & Claws: облака
Мы продолжаем работу над сюжетным режимом нашей игры.
На этой неделе мы добавили в уровни новые объекты, чтобы сделать прохождение регионов более интересным, а также немного поработали над визуальной составляющей экрана телешоу. Добавили стаи летящих птиц и медленно движущиеся облака.
Эффекты реализованы при помощи анимации и обычных спрайтов. Мы не используем 3D объекты для экономии ресурсов, так как изначально позиционируем нашу игру, которая будет работать на очень слабом железе. Не знаем, окажется это правильной стратегией, или нужно было позволить игре кушать ресурсы ПК, как это делает Хром. В любом случае мы продолжаем придерживаться выбранной стратегии.
Напоминаем, что уже доступна демо-версия нашей игры.
Визуальная новелла 18+
Как-то вечером, когда делать было совсем нечего, я загорелся идеей создать визуальную новеллу 18+. Создавать я решил на известном движке Renpy. Хотя навыков в программировании у меня не было, это не стало препятствием, так как движок очень прост в обращении. Все модели и сцены делаю в программе Daz Studio, ниже приведены первые скриншоты. Пишите свои отзывы и предложения:)
И если вас заинтересует проект, можете отслеживать мои посты. Хотя я не знаю можно тут это делать или нет, впервые на пикабу...
StarCraft шутер 2 часть
Решил ещё немного поковыряться в своём клоне-гибриде двух игр - стрелялки и стратегии: подтянул графон, добавил пару юнитов.
Модель с голой текстурой
Первым делом разобрался с материалами, чтобы персонажи хоть минимально приобрели узнаваемость. Оказывается, у Юнити своё понимание карт нормалей, не как у старкрафтовского движка. То есть, там у юнита выпуклость - тут она углубление и наоборот. Из-за этого все карты нормалей пришлось инвертировать вручную.
С картой затенения
Странная штука - если ставить диффузную карту в слот альбедо, получается всё чёрное. Но если закинуть текстуру в слот для вторичной карты, то цвет получается ок. Не сразу я понял этот прикол, а только методом тыка.
Такой зерглинг получился
Логическим апгрейдом стало добавление улучшенных собачек с крылышками. Увеличил им скорость и наглость. Анимация стандартной собачки легла на кости апгрейженной безупречно. Получается, в бескрылую модель уже зашиты анимации крыльев.
Быстрый, дерзкий
Ради разнообразия заморочился с тараканом. Переходное звено между дальней и ближней атакой. Но стандартная "родная" текстура как-то странно легла на когти. И вообще в целом какая-то она менее вменяемая - нечёткие границы, мало деталей.
Таракашка
Ну и гидра с новыми настройками материала стала выглядеть свежее. Хотя опять же не без камней. В Юнити странная система бликов. Если сделать спекуляр чуть выше, вся модель покрывается стеклянной глазурью, зеркалом отражая окружение. Поэтому пришлось убавить бликастость почти до минимума.
Свежая гидра
По сравнению с оригиналом, мои гидры получились суховатыми.
Слева сухо, справа мокро
Так и не смог разобраться, как сделать в материале цвет команды. Поэтому все участки на теле персонажей, предназначенные для цветовой маркировки, у меня белые. Уместно для нейтральных сил, но было бы прикольно контролировать это явление.
Цвета команды в оригинале
Чисто из любопытства захотелось проверить, как это будет выглядеть в UE. Там всё-таки рэйтрэйсинг и все дела. Но, потеребив новый для меня движок около часа, я понял, что есть, куда расти)
К тому же незнакомый мне формат текстур dds вносит свои корректировки в процесс создания материалов.
Анриал энжин и гладкие собачки
Вернувшись к Unity, стал причёсывать игровую логику.
Добавил гидралискам способность к рукопашке. Точнее сначала разделил все атаки юнитов на обычную и дистанционную. Пока что, кстати, на все войска действует один и тот же скрипт. Программистом никогда не был, поэтому каждая механика даётся с жёсткими затупами.
Сделал им этот костяной шип, но он категорически отказывался лететь под правильным углом. То боком вылетал, то в небо летел плашмя. В результате после колдовства с pivot в 3д редакторе и костылём в виде следящей за игроком точки спавна в голове у гидры получилось заставить эту штуку лететь правильно. Интересно, что в движке функция слежки немного наперёд предугадывает движение объекта, поэтому, если резко остановиться или развернуться, гидралисты стреляют немного в сторону, будто предугадывая траекторию. Вроде даже забавно получилось.
Также, если подойти близко к гидралиску, он начнёт махать лапами, если отбежать достаточно далеко, станет ползти до расстояния выстрела.
До гидралисков были тараканы. У них, как и положено, атака зелёной едкой соплёй на небольшой дистанции.
У них есть ещё одна особенность - регенерировать под землёй. Решил реализовать её так: чувствуя, что следующее попадание будет последним, таракан зарывается. Пока что на этом его способности всё) Также он может передвигаться в зарытом состоянии. Ну и его можно застрелить. На данный момент всех можно. Закапывание пока что для зергов не так выгодно, как должно)
Само закапывание, его создание, вызвало у меня немало произнесённых скверных слов. Потому что никак не могло до меня дойти, как сделать, чтобы звук закапывания/выкапывания вызывался 1 раз, а не каждый кадр, заставляя барабанные перепонки покидать чат. В результате вроде что-то получилось, не хватает пока пыли и камушков, летящих из-под земли, ну и самой ямки.
Зато зерглинги ведут себя теперь очень похоже на свои прототипы из оригинала - выскакивают и бегут.
В целом, на виде сверху тоже очень похожее поведение. Если обратить внимание, при быстром убегании толпа зерглингов делится на две кучки: простых и шустрых с крыльями. В оригинальной игре скорее всего тоже был бы такой эффект, но, как правило, там одновременно у игрока могут быть либо те либо те.
Добавляя юнитов на карту, обратил внимание на неестественность поз, все смотрят в одну сторону. Крутить каждого бедолагу вручную облом, писать какой-то код для случайного поворота при выставлении тоже не стал, а добавил в поведение спокойствия немного случайного вращения. Теперь, выставив толпу глядящих в одну сторону юнитов, можно наблюдать, как они разворачиваются в случайном порядке в разные стороны, нетерпеливо топчась на месте. Кстати говоря, в самом Старкрафте это тоже есть, для таких разворотов даже предусмотрены анимации, левосторонняя и правосторонняя.
Теперь на карте есть полноценные четыре сорта энписи, уже можно пилить сюжет)
Доработал склады провизии, теперь их можно складывать как в игре, только не по кнопке, а шмальнув в искрящий терминал неподалёку. Таким же способом открываются двери.
Пушку для главного героя я позаимствовал у модели морпеха ремастер скина. То есть винтовка времён первой части.
Ну и немного обновлённого геймплея.
Зацените трейлер для моей первой игры! Пожалуйста ^_^
Я делаю игру под названием "Girlfriend From Hell" вдохновившись культовой игрой "Как достать соседа!"
Демо версия уже почти готова, надеюсь скоро залью её в стим)
Если вам не сложно добавьте игру в Вишлист Steam ^_^
Jaws & Claws: истории боссов
Совсем недавно мы начали работу над боссами сюжетного "остров" нашей игры. На данный момент мы еще не закончили работу над этими персонажами, но в игре они должны выглядеть примерно так.
Телохранители Хитрого Хорька
В этом посте, я хотел бы рассказать небольшие истории про телохранителей Хитрого Хорька и раскрыть немного информации о нем.
Газель.
Самый красивый телохранитель и подружка Хорька.
Jaws & Claws - Газель
Родилась в небольшом городке на юге Волчалии. С детства была очень красивой и скромной девочкой. Мечтала стать актрисой. По наступлении совершеннолетия отправилась в Слоновию, чтобы попасть на большие экраны.
Так наступило время хождения Газели по бесконечным кастингам на второстепенные роли, которые заканчивались отказами.
Параллельно девушка принимала участие в конкурсах красоты и смогла выиграть один из них. Это был широко освещаемый в СМИ конкурс, организованный утенком Дампом. Победительница была замечена Гиеном, который уговорил ее участвовать в бонобо-стримах.
Легкие деньги вскружили голову красавице и отпустили ее внутренние тормоза. Девушка решила, что готова попробовать себя в роли актрисы леминг-фильмов. Съемки приносили деньги, но счастья и известности, о которой Газель мечтала с детства, не было.
Все это сказалось на ее психике. Злоба на окружающий мир, стала ее визитной карточкой. А образ мужчины для газели был банкомат на коротких ножках.
На одной из ночных тусовок, Газель познакомилась с Хитрым Хорьком. Красавица тут же в него влюбилась. Почему так произошло, даже для Газели стало загадкой. Возможно, решающую роль сыграл мерзкий характер Хорька. По мнению Газели, они созданы друг для друга с объектом ее обожания.
Работает на Хитрого Хорька около 5 лет и невероятно ему предана.
Любит все розовое и необычные игрушки.
Детей нет. Не замужем.
Лиса.
Самый профессиональный боец - чемпион по смешанным единоборствам.
Jaws & Claws - Лиса
Детство провела в Медвежанции.
Окончив школу, Лиса вместе с родителями перебралась в южный Пандай.
По мнению родителей будущего чемпиона кикбокса, в Пандае были самые сильные школы боевых искусств. Лиса обожала занятия спортом. Одновременно посещала секции ушу, самбо, бокса и тхэквондо. Иногда ее тренировки прерывались только на сон.
Лиса хотела быть лучшим бойцом на планете. Многочисленные победы в соревнованиях стали закономерным итогом напряженных тренировок Лисы.
Она не воспринимала победы в официальных женских чемпионатах, как доказательство своего абсолютного мастерства. В итоге Лиса переехала в Слоновию, для участия в чемпионатах без правил. В общих категориях с мужчинами. Первый же бой против Носорога, многократный чемпион проиграла. Это было первое поражение Лисы в ее жизни. Девушка поняла, что для победы в боях без правил, ей нужно тренироваться еще больше.
Днем она подрабатывала барменом, а ночью отправлялась в самые криминальные кварталы, чтобы разбивать носы и ломать кости районным авторитетам. На одной из подобных разборок была замечена Хитрым Хорьком.
Гениальный злодей предложил девушке то, о чем она мечтала - назначил ее своим телохранителем и главой преступной группировки. Теперь все лучшие бойцы проходили отбор в команду Хитрого Хорька только через Лису.
Девушка могла продолжать совершенствовать свое искусство, благодаря бесконечным спаррингам, практически с любым количество бойцов. И теперь она счастлива.
Работает на Хитрого Хорька около 7 лет.
Любит рыбий жир, музыку диско и наносить своим соперникам небольшие увечья.
Детей нет. Не замужем.
Фосса.
Гениальный хирург, партнер и правая рука Хитрого Хорька.
Jaws & Claws - Фосса
В детстве Фосса, как и все девочки, играла дочки матери и врача с пациентами. Мечта стать врачом пришла к ней довольно рано и не покидала больше детскую голову ни на минуту. Фосса с жадностью читала медицинскую литературу. Посещала различные медицинские семинары и форумы.
Еще до окончания школы идеально знала строение организма животных. Окончила медицинский институт с отличием, за время ординатуры провела десятки успешных операций. Казалось, Фоссе судьбой отведена роль величайшего спасителя зверей. Именно так это и было до определенного момента.
На одной из научных конференций Фосса познакомилась с Котом. Он был красив, умен и галантен. У них быстро завязался роман, который в скором времени завершился свадьбой двух гениальных врачей-ученых. Это была идеальная пара в идеальном мире ученых.
Однако у супруга были необычные пристрастия в постели. Он любил проводить эксперименты, погружавшие его предсмертное состояние, так, по его убеждению, он получал неописуемое удовольствие. Однажды влюблённая пара перешла от использования удушающих или колюще режущих приспособлений к медикаментозным погружениям в состояние комы. В результате организм Кота не выдержал и муж Фоссы умер. С тех пор она не смогла простить себе потерю любимого. Делать операции детям она боялась, обвиняя себя в некомпетентности. Фосса ушла из медицины, переехала в Слоновию.
Однажды, выпивая в баре, Фосса стала свидетелем перестрелки, с большим числом жертв.
Ни секунды не раздумывая, используя подручные средства, женщина спасла большое количество раненых в перестрелке зверей. Хитрый Хорек не мог этого не заметить и пригласил ее к себе на работу.
Резать преступников, находящихся на грани жизни и смерти не пугало Фоссу. Теперь она снова могла спасать звериные жизни. За что стала бесконечно благодарна Хитрому Хорьку.
Более 10 лет режет и спасет жизни раненых преступников. Компаньон и правая рука Хитрого Хорька по бизнесу.
Любит причинять боль и лечить зверей.
Детей нет. Вдова.
Хитрый хорек.
Главный босс.
Jaws & Claws - Хитрый Хорек
Профессор по экономическому анализу. Семикратный чемпион в боях на пальцах.
Бывший мэр города Ферро Сити. Руководитель совета нац. безопасности.
Автор, продюсер и владелец шоу «Jaws & Claws».
Основатель космической корпорации «Юпитер J».
Автор законопроекта «фиксированные налоги». Президент корпорации «Теневое правительство». Зверорублевый миллиардер, инвестор. 18 место в списке Кротс.
Борец за здоровый образ жизни. Вредных привычек не имеет.
Обожает живопись и красивых женщин. Характер мерзкий. Детей нет. Не женат
Сможете найти на картинке цифру среди букв?
Справились? Тогда попробуйте пройти нашу новую игру на внимательность. Приз — награда в профиль на Пикабу: https://pikabu.ru/link/-oD8sjtmAi
Once you go Rust, you never go back. Создание игры для программистов на Bevy
Ранее я уже описывал, как я дошёл до того, чтобы заняться геймдевом, как я готовился к этому и как выбирал инструменты. Здесь же я хочу сосредоточиться именно на самой игре, а также Bevy и Rust, как основных инструментах разработки.
Логотипы выбранных инструментов
Итак, игра с незамысловатым названием HackeRPG (Hacker + RPG), экшн, где управление основано на кодинге. Проект, в силу своей специфики, рассчитан на узкую аудиторию или, другими словами, «на своих». Из этого следует, что было бы хорошим тоном добавить пасхалки и привычные разработчикам фичи.
Дабы упростить дальнейшее понимание решений, которые я реализовывал, будет правильно хотя бы немного описать движок Bevy. Главная его особенность - ECS (Entity component system), где
Component - любая сущность игре(будь то спрайт, свет или текст);
Entity - грубо говоря, контейнер, куда мы складываем все компоненты;
System - действия с компонентами, которые выполняются в бесконечном цикле.
Визуализация ECS
Помимо прочего в движке реализованы состояния (для ограничения работы систем), события (для разового вызова систем) и ресурсы (для хранения данных, которые не связаны с какими-либо сущностями в игре и не могут иметь несколько экземпляров, формально этого же можно достичь с помощью компонентов, но этот вариант в некоторых ситуациях удобнее).
За конкретными гайдам по самому движку - на официальный сайт или искать мануалы на YouTube.
UI
В начале работы мне предстояло определиться с визуальным стилем и его реализацией. Для пользовательского ввода я выбрал mouseless подход: каждое меню в игре - симуляция терминала, а основной геймлуп - ввод текста в консоль. Ну и, разумеется весь текст обязательно должен быть зелёным: куда без заезженной хакерской эстетики?
И не говорите мне, что ваш рабочий день выглядит не так
Задача достаточно тривиальная, но с учётом ECS - не самая удобная. Однако после некоторых оптимизации и разбиения функционала и модулей можно добиться вполне сносной архитектуры.
Изначально я создал системы, которые вызываются только один раз и создают нужные нам компоненты, такого вида (здесь и далее код будет упрощён до минимума, чтобы не перегружать лишней информацией):
fn setup_menu_system(
mut commands: Commands,
game_assets: Res<GameAssets>
) {
commands.spawn(
NodeBundle {
style: Style {
width: Val::Percent(100.),
height: Val::Percent(100.),
flex_direction: FlexDirection::Column,
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
..default()
},
..default()
}
).with_children(|parent| {
spawn_console(
&game_assets,
parent,
);
});
}
Где структура commands добавляет на экран элемент NodeBundle с дочерними элементами, которые создаёт моя собственная функция spawn_console.
Хотелось бы отметить удобство работы с HUD слоем: в Bevy она реализована на основе концепции FlexBox, которая будет привычна любому, кто более или менее знаком с веб фронтенд разработкой.
Важный нюанс используемой мной концепции UI - input и output зачастую отображаются одним и тем же компонентом. Т.е. при наличии такого меню:
Say hello
>hello█
Где первая строка - output, а вторая (кроме первого символа и символа каретки) - input.
Таким образом для удобства пользовательский ввод хранится в отдельном компоненте, а система, которая выводит текст на экран, уже на лету «приклеивает» его. Такой подход так же позволил довольно удобно реализовать логику каретки и истории ввода, но их я разбирать сегодня не буду. Так, для вывода текста в нашем «терминале», я использую системы вида:
fn menu_output_system(
mut console_query: Query<(&mut Text, &TextInput)>
) {
if let Ok((mut output, input)) = console_query.get_single_mut() {
let output_text = get_menu_output();
output.sections[0].value = output_text + text_input.text.as_str();
}
}
Где Query используется для того, чтобы получить сущности, у которых присутствуют указанные компоненты, TextInput - мой кастомный компонент, который хранит данные о вводе и автодополнении, а функция get_menu_output - генерит строку для вывода. Довольно минималистично и аккуратно.
Осталось добавить обработку ввода и MVP терминала готово! Для этого я решил использовать две вот такие системы:
fn menu_char_input_system(
mut ev_char: EventReader<ReceivedChar>,
mut console_query: Query<(&mut TextInput, &mut TextCaret)>
) {
for ev in ev_char.read() {
if ev.char.is_control() {
return;
}
if let Ok((mut input, mut caret)) = console_query.get_single_mut() {
insert_char_at_caret_position(
&mut input,
ev.char.to_string(),
&caret
);
update_caret_on_input(&mut caret);
}
}
}
fn menu_control_input_system(
keyboard: Res<Input<KeyCode>>,
mut console_query: Query<(&mut TextInput, &mut TextCaret)>
mut ev_exit: EventWriter<AppExit>
) {
if let Ok((mut input, mut caret)) = console_query.get_single_mut() {
if keyboard.just_pressed(KeyCode::Return) {
match input.text.as_str() {
"0" => ev_exit.send(AppExit),
_ => {}
}
input.text = "".to_string();
reset_caret(&mut caret);
}
}
}
Первая функция обрабатывает события типа ReceivedChar, отправляя полученный символ в TextInput по позиции каретки, после чего обновляет положение каретки. Вторая - обрабатывает нажатия клавиши Enter и выходит из приложения, если был введён 0(ноль). Добавляя дополнительные состояния, которые будут характеризовать текущий экран, можно реализовать любую навигацию, обработку ввода и отображение информации, используя вышеописанные конструкции.
Результат проделанной работы
На данный момент в Bevy состояния не могут хранить какую-либо информацию, а представляют собой примитивное перечисление. Это вынуждает связывать их с ресурсами или компонентами, которые хранят информацию о них. Насколько мне известно, в ближайшее время не планируется это менять, поэтому приходится с этим жить.
В остальном UI довольно тривиален: отображение текста, анимация спрайтов, движение - типичный контент самых простых туториалов. Поэтому продолжу описывать именно «прогерские» фичи.
Gameloop
Следующий шаг: реализация главной фичи игры - управления персонажем с помощью команд. Для ввода текста можно без проблем использовать ранее описанную menu_char_input_system, но теперь её можно сделать несколько более глобальной. Уберём из названия слово menu и заставим её работать не только на экране меню, но и в самой игре. Удалось переиспользовать ранее написанный код, значит что-то правильное есть в архитектуре, а это хорошо! А вот control_input_system потребуется реализовать другую. Опустим boilerplate code и сразу к сути:
...
if let Some(command) = command_from_string(input.text.to_string()) {
player_commands.queue.push(command);
}
...
Теперь, когда мы нажимаем Enter, мы пытаемся спарсить команду на основе нашего инпута. В случае успеха - добавляем команду в очередь.
Парсинг осуществляется в функции command_from_string, которая в рамках этой статьи останется чёрным ящиком, который делает какую-то магию с регулярками.
После этого в ход вступает система, которая по одной исполняет команды из очереди, если нет текущей активной команды:
fn handle_command_queue_system(
mut commands_query: Query<&mut PlayerCommands>
) {
for (mut commands) in commands_query.iter_mut() {
if check_in_progress(&commands) {
continue;
}
set_current_command(&mut commands_query);
}
}
Можно заметить, что здесь используется for и iter_mut() вместо if let Ok и get_single_mut(). Таким образом мы обрабатываем компоненты, которых в игре может быть несколько. Этот сниппет - программное олицетворение моего оптимизма, который внушает мне, что проект найдёт интерес и признание и запрос на мультиплеер появится. В остальном - происходит проверка есть ли текущая активная команда с помощью check_in_progress, если её нет, то команда переносится из вектора query в переменную current.
Далее управление принимает довольно большое количество систем, каждая из которых обрабатывает одну конкретную команду. Изначально вся эта конструкция представляла собой один большой match, который со временем стал воистину монструозный, из-за чего был беспощадно разрезан на множество систем катаной рефакторинга. Вот одна из таких систем:
fn handle_current_move_command_system(
mut commands_query: Query<(&mut PlayerCommands, &mut Movable)>
) {
for (mut commands, mut movable) in command_query.iter_mut() {
match &commands.current {
Move(x,y) => handle_move_command(x,y,&mut movable),
_ => {}
}
}
}
В вышеописанной функции мы проверяем, является ли текущая команда командой move. Если да, то обрабатываем её. Такое разбиение создаёт некоторый boilerplate, однако убирает ад с огромным количеством Query, практика показала, что это решение достаточно удобное.
Результат
Таким образом удалось реализовать управление посредством команд. В конечном итоге можно добавлять новые команды посредством добавления ключевых слов и элементов в enum при парсинге, а так же одной системы, которая будет эту команду обрабатывать. Довольно неплохо и почти чисто.
IDE
А теперь настало время прыгнуть в кроличью нору: время добавить внутриигровую IDE. Описание основных фичей связанных с реализацией терминала уже было ранее. Разве что перемещение каретки не было описано, но это я оставлю, как домашнее задание. Далее же задача весьма тривиальна - рекурсивный парсинг. Но вот проблема: Rust не дружит с использованием рекурсии в регулярных выражениях, а значит решение одно:
Костыли
Пришлось комбинировать парсинг с использованием регулярных выражений с рекурсией на основе функций. Таким образом появилась возможность создавать ифы в ифах и форы в форах. В результате из строки получается структура типа CodeBlock:
#[derive(PartialEq, Debug, Clone)]
pub struct CodeBlock {
pub name: String,
pub block_type: CodeBlockType,
pub content: Vec<CodeBlockContent>,
}
#[derive(PartialEq, Debug, Clone)]
pub enum CodeBlockType {
Function(Vec<String>),
Daemon,
Virus,
}
#[derive(PartialEq, Debug, Clone)]
pub enum CodeBlockContent {
Block(InnerCodeBlock),
Lines(Vec<String>),
}
#[derive(PartialEq, Debug, Clone)]
pub struct InnerCodeBlock {
pub block_type: InnerCodeBlockType,
pub content: Vec<CodeBlockContent>,
}
#[derive(PartialEq, Debug, Clone)]
pub enum InnerCodeBlockType {
If(String),
For(ForLoopInnerCodeBlock),
While(String),
}
#[derive(PartialEq, Debug, Clone)]
pub struct ForLoopInnerCodeBlock {
pub variable_name: String,
pub from: PlayerCommandInput,
pub to: PlayerCommandInput,
}
Каждый блок кода имеет тип (Function, Daemon или Virus) с нужными для его работы параметрами (только у функций есть вектор имён аргументов), а также хранит содержимое его тело в векторе типов CodeBlockContent. Внутренний контент, в свою очередь, может быть либо строками, которые будут парсится ранее упомянутой command_from_string, либо структурами InnerCodeBlock, которые аналогичны CodeBlock, но могут иметь типы If, For или While.
Аналогично случаю с командами, в случае добавления новых сущностей достаточно добавить элементы в перечисления и в ключевых слов в логику парсинга.
Так выглядит IDE в игре
Итоги
Выше я описал лишь небольшой срез проделанной мной работы, помимо этого есть ещё некоторые интересные решения, которые я реализовал в рамках этого проекта (нюансы парсинга, демоны, вирусы, использование ресурсов для запуска кода, древо прокачки в стиле гит, логика обучения и документация), о которых могу рассказать в следующий раз, если будет интерес к этой теме.
Одной из целей игры является поднять навыки программирования у людей и привить любовь к нему. В какой-то степени она уже сейчас достигнута, ведь в процессе разработки я неплохо прокачал свои навыки и по-настоящему полюбил Rust, и теперь стараюсь отдавать ему предпочтение всегда, когда это возможно и имеет смысл. Движок Bevy себя показал крайне хорошо. Да, были ситуации неприятных багов (которые, кстати были пофикшены в следующей же сборке), не совсем удобных решений и неудобной миграции при переходе на новую версию, но!
удобство разработки;
качество итогового продукта;
маленький размер сборки;
Всё это однозначно того стоит.