Горячее
Лучшее
Свежее
Подписки
Сообщества
Блоги
Эксперты
Войти
Забыли пароль?
или продолжите с
Создать аккаунт
Регистрируясь, я даю согласие на обработку данных и условия почтовых рассылок.
или
Восстановление пароля
Восстановление пароля
Получить код в Telegram
Войти с Яндекс ID Войти через VK ID
ПромокодыРаботаКурсыРекламаИгрыПополнение Steam
Пикабу Игры +1000 бесплатных онлайн игр Новый хит для любителей игры жанра три в ряд! Кот Ученый уже прячет предметы по таинственному лесу, чтобы вы получили удовольствие от поиска вещей и заработали как можно больше изумрудов. Котик рад новым гостям!

Северное слияние - тайна леса

Казуальные, Приключения, Логическая

Играть

Топ прошлой недели

  • Oskanov Oskanov 9 постов
  • Animalrescueed Animalrescueed 46 постов
  • AlexKud AlexKud 33 поста
Посмотреть весь топ

Лучшие посты недели

Рассылка Пикабу: отправляем самые рейтинговые материалы за 7 дней 🔥

Нажимая «Подписаться», я даю согласие на обработку данных и условия почтовых рассылок.

Спасибо, что подписались!
Пожалуйста, проверьте почту 😊

Помощь Кодекс Пикабу Команда Пикабу Моб. приложение
Правила соцсети О рекомендациях О компании
Промокоды Биг Гик Промокоды Lamoda Промокоды МВидео Промокоды Яндекс Маркет Промокоды Отелло Промокоды Aroma Butik Промокоды Яндекс Путешествия Постила Футбол сегодня
0 просмотренных постов скрыто
45
kakawa47
7 лет назад
Лига Разработчиков Видеоигр

Генерация подземелий или как потеряться в массивах. Часть II.⁠⁠

И снова привет, Pikabu! С момента первых двух постов появились некоторые изменения:

Так что, теперь даже есть стимул писать для кого-то - спасибо тем кто ждет и кому интересно! :) Постараюсь не разочаровать моих 11 Кодзим новым постом о генерации подземелий.


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


Одним из удобных графических представлений связей между объектами в 2D плоскости является так называемый Граф:

Граф - это такой абстрактный математический объект, представляющий из себя множество вершин и ребер - соединений этих вершин между собой. Графы бывают разные (и они не обязательно напоминают символ сатаны) - они могут быть взвешенными, ориентированными, двудольными, связными.. В общем, куча их. Так какой же нам выбрать? Давайте подумаем. В нашем подземелье между комнатами будут туннели, и очень желательно чтобы они были как можно меньше (вспомните того шакала из прошлого поста), поэтому дистанция между комнатами - важный параметр. Граф, в котором такой параметр учитывается, называется взвешенным, и у каждого ребра такого графа пишется его "вес". В нашем случае - это дистанция между комнатами, и чем она меньше - тем лучше. Направления, в котором эти комнаты связаны, нам не особо и вперлось - какая разница куда бежать, вправо или влево, вверх или вниз между комнатами? В случае необходимости, мы можем пробежать по туннелю и два раза (мало ли, забыли итем в соседской комнате?). Это значит, что граф неориентированный, т.е., не имеет определенных, залоченных направлений движения. Вот и определились. Теперь нужно подумать, как представить его в коде, а не на бумаге. Можно сделать это структурой, например, где каждый элемент будет вершиной графа, содержащий указатели на все другие вершины.. (фу) Однако, в GMS2 я не особо то и обнаружил возможность нормально реализовать данный метод (или плохо искал). Так что, что мы говорим структурам?

И выбираем матрицу :3

Не зря ведь в заголовке написано "как потеряться в массивах" - надо оправдывать название) Берем наш двумерный массив, пробегаемся по каждой комнате по её id и вызовем функцию GMS distance_to_object(). Запишем значение в соответствующую ячейку, и, вуаля, получим заполненный массив с расстояниями между всеми комнатами. Теперь дело за малым - находим в каждой строке матрицы минимальное значение, не включая элемент, в котором индекс строки совпадает с индексом столбца (очевидно, ведь это путь от себя до себя и он равен 0) и сохраняем отдельно. Теперь у нас есть список наименьших путей, по которому мы сможем соединить между собой все комнаты. Но, думаю, если здесь есть те, кто имеет опыт работы с GMS и уже успели задаться вопросом: зачем заниматься всем этим, заполнять матрицу и искать меньшие значения, если есть чудесная функция instance_nearest(), которая и находит минимальную дистанцию до ближайшего объекта? Отвечу:

А вернее, я буду использовать не только самый короткий путь до комнаты, но и (с долей вероятности) буду искать еще один короткий, не включая предыдущий. Зачем?

Чтобы подземелье не было линейным, а имело ответвления или несколько способов попасть в комнату. Думаю, так будет интересней играть, нежели бежать хоть и по изогнутому, но все-таки коридорному пространству. Вот примерно так это и выглядит:

Итак, самое основное сделано - теперь мы знаем что связать друг с другом и как это сделать. Самое время построить туннели, ведь ради них все и затевалось. Но не так все просто оказалось, нежели я думал. Сначала я взял самое очевидное решение - построить из центра одной комнаты палку вверх, а из центра другой - палку в сторону. И знаете что?

Проблема вылилась практически сразу. Помните шакала с того поста? Его мы пофиксили добавляя маленькие комнаты, которые попадались на пересечении линий между основными комнатами. Однако, эти линии были внутри круга генерации тех самых комнат. Иными словами, если одна основная комната попадет в левую часть круга, а другая - в верхнюю, и они решат соединиться через мой алгоритм - заливать пустоты будет нечем, ведь дополнительных объектов вне круга не генерируется. Примерно вот такая кака:

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

Что пришло мне на ум - у нас есть матрица игрового поля, почему бы не поработать с ней?

Алгоритм вышел такой:

1) Вычисляем положение наших двух комнат в матрице игрового поля

2) "Вырезаем" часть матрицы, в которой эти комнаты располагаются

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

4) Найденную строку и столбец заполняем полностью нулями, что означает для моей матрицы расположение туннеля.

Результат:

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

Финальная версия генерации на данный момент выглядит примерно так:

На картинке еще можно найти некоторые огрехи - маленькие тупики, но там проблема забавная - рядом с этими тупиками есть спрятанная комната, её не видно, но она не вошла в основные или дополнительные и просто сидит рядом. Поэтому, алгоритм удаления тупиков принял её за соседа и оставил туннель.


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


P.S. спасибо тем, кто оставлял комментарии по поводу генерации в прошлом посту - появилось пара идей для реализации)

Показать полностью 10
[моё] Game maker studio 2 Gamedev Длиннопост Инди игра Roguelike Разработка игр
12
48
kakawa47
7 лет назад
Лига Разработчиков Видеоигр

Генерация подземелий или как потеряться в массивах. Часть I.⁠⁠

Привет, Pikabu! С моего первого поста прошло всего несколько дней, но, на удивление для меня, кому-то стало все-таки интересно что творится под капотом страшной фразы "генерация подземелий" и как изнутри выглядит её код говнокод. Поэтому передаю привет моим трём подписчикам:

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


Первое, что приходит на ум при придумывании очередного велосипеда на тему создания подземелий - это наспаунить кучу квадратов и соединить их палками. А что, круто же? Комнаты есть, туннели - есть, бегай да собирай бонусы. Вот так и думал мой препод, для которого левел дизайн это "расставь алмазик в трех местах = три разных уровня". Помимо того, что это не так уж и просто сделать, такой подход еще и выглядит отчасти убого, ведь алгоритм объединения отдельных комнат туннелями в таком случае будет примитивным - соедини две ближних и получишь "змейку" из квадратов. Пара дней сидения за гуглом и спешным транслейтом ангельского языка на русский привели меня к статье на хабре, в которой примерно был описан алгоритм неплохой генерации, но на Юнити. Однако, цитировать его слово в слово я не буду, ведь:

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


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

а) определенное количество основных комнат

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

Решение здесь такое же простое и ленивое - зачем думать над условиями, если программа сама может решить твою проблему? Существует такое понятие как "флокирующее поведение". Это поведение объекта (именуемого агентом) в условии присутствия других таких же объектов. У него существуют несколько ограничений, связывая которые можно получить различный тип поведения, от преследования до убегания. В моем случае, генерируем случайное количество комнат на плоскости со случайным размером в радиусе определенной окружности, определяем вектор каждой комнаты до ближайшего соседа, и просто разворачиваем его в обратную сторону. Иными словами:

Таким образом, расположенные рядом на очень близком расстоянии объекты, разлетаются друг от друга в противоположных направлениях. В итоге, мы получаем гарантированное "несовпадение" по координатам в независимости от размера комнат. В коде это выглядит примерно так:

"если я касаюсь какого-то выродка - посмотреть в его сторону и бежать в противоположную со скоростью 10"

Разбежавшись, комнаты занимают свои позиции и переводят дух. Теперь их ждет вторая стадия - необходимо определиться, кто здесь главный и с кем из соседей этот главный хочешь скорешиться. Забыл упомянуть, как это все хранится: каждая комната это обычный объект GMS2, имеющий координаты, спрайт, а также возможность добавления кода. Для того, чтобы дальше работать с ними как с совокупностью, а не раздельным сбродом, я добавляю id каждого объекта в специальный одномерный массив. Массив хранится в еще одном объекте, который отвечает здесь вообще за всю тусовку связанную с генерацией - obj_dungeonGenerator. Вон сидит, сидит палит

Комнат получается много, поэтому нужно отсечь лишние и взять нужные. Под нужными я понимаю те, которые имеют определенный размер, например, больше среднего. "Лишние" комнаты, однако, совсем не лишние. Почему? Взгляните сюда:

Зеленые квадраты - это нужные комнаты, а красные линии - потенциальные соединения между ними. И знаете что меня напрягает? Вот этот шакал:

Т.е, в некоторых случаях мы получим ситуацию, при которой может сгенерироваться гигантский туннель, незаполненный абсолютно ничем, но счастливо соединяющий нужные нам комнаты. Напоминает "я сделяль", и нас это категорически не устраивает. Игрок, бегущий по такому пространству, быстрее плюнет на игру чем дойдет до соседней комнаты. Чтобы этого избежать можно не идти далеко за грибами - просто берем и включаем в список нужных комнат те, которые умудрились попасть на эту линию. Выходит что-то вроде:

Однако, это еще не конец истории. Окунемся немножко в теорию вероятностей чтобы было понятно о чем речь. В ненавистной мной ТВ (из-за тотального её непонимания когда я сидел на её парах) существует понятие равномерно распределения. Оно используется в любимой нами функции radom(), random_range() и прочих прочих. Согласно термину: "В теории вероятностей случайная величина имеет дискретное равномерное распределение, если она принимает конечное число значений с равными вероятностями." Это значит, что рандомно задавая размер комнаты, мы, каждый раз, можем равновероятно получить как большую, так и среднюю или малую комнату в нашем диапазоне. Как это нам мешает? Такое распределение создает ситуацию, в которой все комнаты получаются примерно одинакового размера. Поэтому, на моменте отбора нужных комнат получится, что мы отберем 10 самых больших, но на фоне останутся, фактически, такие же комнаты, только чуууть меньше или больше. Из этого следует, что в качестве туннелей мы получим не линию из маленьких комнат, а совокупность больших инвалидов, которые уместились по соседству. В своей игре я хочу иметь понятие "основной" и "дополнительной" комнаты - в первой будут сундуки и плюшки с сильными мобами, во вторых - прочая мишура для тира, которую можно пробежать и забыть, не сильно при этом скучая. Поэтому я беру на вооружение так называемое Геометрическое распределение. Оно отличается вероятностью появления каждого последующего события, т.е., чем дальше от начала отсчета "событие", тем меньше вероятность его появления. Таким образом, мы получим маленькое количество больших, и большое количество маленьких комнат, что играет нам на руку - первые в основные, вторые - на мясо. В итоге этого выглядит примерно так (на скрине еще старое, равномерно распределение, но прикрепляю его чтобы видно было дело, а не рисунки с пэинта):

На нем видно окружность, из которой выползли уже готовые комнаты, а также их разделение на основные и дополнительные. Однако, многие посмотрят на скриншот и спросят:

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

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

Пробегаемся вложенным циклом по этому двумерному массиву с таким условием: "если по координатам этой ячейки ничего нет - кладем туда #, если есть главная комната - кладем 2, если дополнительная - кладем 1", а затем, пробегаем второй раз с другим условием: "если рядом с единицой или двойком в матрице есть # - заменяем его на +", получая тем самым заполненную матрицу с расположением комнат, стен, а также пустых пространств.

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


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

Показать полностью 12
[моё] Инди игра Разработка игр Gamedev Game maker studio 2 Пиксель Roguelike Длиннопост
14
36
kakawa47
7 лет назад
Лига Разработчиков Видеоигр

Вперед и с песней. Мой первый серьезный проект⁠⁠

Анонс игры на стадии разработки. (Название? Да и пёс с нем, придет с вдохновением)

Всем привет! На Пикабу я давно, однако, я больше любитель поскроллить ленту чем писать посты, так что, лучше приберегите свои тапки для моих патчноутов - это будет продуктивнее)

Начну издалека. Время идет, годы летят и вот уже скоро настанет момент вступления в скучную и невеселую жизнь, ознаменует которую скорейшее получение степени Бакалавра в купэ с бесполезной синей бумажкой. Чтобы хоть как-то скрасить нарастающую тоску и ужас, в качестве темы для дипломной работы я решил выбрать не очередную бесполезную софтину, название и код которой полетят в помойку сразу же после получения отметки, а хоть что-то полезное, или, хотя бы то, к чему лежит душа. Так уж сложилось, что с давних пор я пытаюсь отчасти реализовать свой творческий фонтан делая маленькие игрушки, которые, конечно, никому не вперлись, но хоть как-то развлекают меня самим процессом создания. Последнее свое творение я даже пытался пропихнуть в еще живой тогда Гринлайт под названием Star Punisher, который я делал АЖ ДВЕ НЕДЕЛИ (а по тому времени для меня это казалось титаническим таймингом по разработке), который, однако, потерпел фиаско, зависнув там на дне как говешка в проруби.

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

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


Что из себя в общем представляет игра? Это рогалик. Со всеми вытекающими. Рандомные подземелья, куча шмота и мобов, НО. Увидев как-то (и в последствии купив) Nuclear Throne и Gungeon я понял, чего я хочу от своего детища - кровованов экШОна. Рандомная генерация отлично дополняется элементами TDS, что весьма кстати, ведь я сам являюсь фанатом мясных шутеров. Графику решено делать в богоподобном гиперреализме с кучей сисек пиксель арте, ведь для одного человека, фактически, ничего и не остается выбирать, да и мои навыки рисования хоть и не на уровне Вася пятикласник, но и не Сальвадор Дали. Досконально над механикой и конечным результатом я не задумывался - работаем по методу увидел - спиздил "ОГО, КРУТО, ХОЧУ ТАК ЖЕ" и делаю также..) Конечно, отношусь я к этому не столь безолаберно, однако, построить полностью модель будущей игры пока что не под силу юному геймдизайнеру, поэтому приходится обходиться вдохновением и желанием, попутно подставляя костыли в реализованные фичи.

Изначально наработки напоминали скорее помесь геймдизайнерской параши в купе с гениальным графоном

Ладно, я сам ору с этого скрина, но это, все-таки, первый день разрабоки..) Да и в начале я сосредоточился не на геймплее и графике, а именно на генерации подземелий. Спустя определенное время игра (а вернее, карта игры) начала принимать свой примерный вид, начиная с пустых и безликих обрамлений комнат

до вполне себе оформленных обьектов:

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

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

Не совсем уж и густо, однако, до релиза еще больше полугода, так что надеюсь позже перечитать этот пост и увидеть гигантскую разницу.
Почему я написал этот пост? Хочу узнать что об этом думают другие люди, а также, надеюсь, что попадутся те, кто имеет опыт игры в подобные жанры и подскажет, что его (или их?) раздражает или наоборот, привлекает в тех или иных продуктах. Буду рад примерам и советам, идеям и предложениям, надеюсь в итоге получить что-то хоть малость играбельное. Игра, кстати, планирует посетить Стим (это важно, сейчас в дипломе для хорошей оценки требуется т.н. "внедрение"). Дата примерного релиза - Май 2018. Путь долог и тернист, но не менее интересен и увлекателен, ведь еще надо додумывать сюжет, искать музыку, допиливать графон.. мле. А че так много то? Памагите. Что планируется добавить в скором или ближайшем времени:
- Освещение. Простое, но без него рогалик как плов без вязанки дров.

- Карта. Бегать в слепую это классно, настолько классно, что нет.

- Динамическое проявление комнат. Ака туман войны, ну, вы поняли..

- Оптимизация. Видели все эти квадратики на полу? А это обьекты. АХАХАХАХА (я еще не разобрался как размещать тайлы в новом GMS2, так что игра не лагает только на моей gtx1080)

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

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

Показать полностью 10
[моё] Инди игра Game maker studio 2 Gamedev Пиксель Roguelike Длиннопост
18
7
MrMouseSE
8 лет назад
Лига Разработчиков Видеоигр

Игра с нуля без мам пап и кредитов на GMS2. build_0_0_5⁠⁠

Доделал рубку корабля наконец-то, буду летать с комфортом!

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

Итак. Билд 5 ознаменовался для меня победой сил разума над силами добра и я, наконец-то, упаковал все свистелки-перделки метеорита в сам метеорит.

Что это за хуйня? тут происходит? Во-первых - вся эта шушера, что вращается и выделяет метеориты - отрисовывается через прозрачку, обратнопропорционально дистанции до объекта, т.е. чем ближе к кораблю - тем больше непрозрачность объекта. Во-вторых - по тому же принципу меняется цвет. Тут всё приведено в абсолютных величинах и это косяк. Надо считать в величинах относительных типа

effect_alpha = 1 - distance_to_object(obj_player) / display_get_height();
effect_color_shift = clamp(2*distance_to_object(obj_player) / display_get_height(),0,1)*255;
effect_color = make_colour_rgb(255, color_offset, color_offset);

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

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

ну тут всё ещё проще: берём один пиксель и скейлим его, меняя значение колор по тому же принципу - температура движка пихается в диапазон от 0 до 255 и является параметром для G и B каналов в make_colour_rgb(). Если вам надо в какой-то другой цвет уводить значение - используйте сочетание каналов в том виде, в котором оно вам нужно. Ну а прирост самой линии - просто скейл пикселя в draw_sprite_ext(), прямопропорционально параметру (тоже в диапазоне значений, лично у меня сделано через множитель).

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

Ну и гифка с геймплеем

движки перегреваются и вырубаются, а при перегреве корабля - вырубается отрисовка всей инфы. Такие дела.

Показать полностью 5
[моё] Тег Indiedev Инди игра Gamedev Game maker studio 2 Гифка Длиннопост
17
MrMouseSE
8 лет назад
Лига Разработчиков Видеоигр

Игра с нуля без мам пап и кредитов на GMS2. build_0_0_4⁠⁠

Прикупил новые энергохранилища... бу. А то старые постоянно текли. А эти - классные! Продавец сказал, что не фонят... почти.

Ну и для привлечения внимания. Тут уже кое-что происходит.

В прошлом посте мне какой-то кадр написал, что дистанцию меряют одометром... В космосе... одометром... который измеряет количество оборотов колеса. ВОТ ЧТО С ВАМИ НЕ ТАК?! Вас в школу не пускали, чтобы остальные не отупели?!

Погнали!

Итак, худо-бедно, я добрался до четвёртого билда. Тут я прикручивал температуру двигателям, каждому свою. И прикручивал на это и кое-что ещё ивенты. Выглядит это вот так:

вот такая вот портянка. Всё это упихано в obj_player (так как это поведение плэера). Я уже говорил по этому поводу, что накосячил с представлением переменных и впихал их все в глобал - это не правильно, надо это было всё в качестве свойств объекта оформлять и работать с объктами.

Кроме этого - подобные партянки надо заворачивать в скрипты и дополнительные объекты в зависимости от целей. Например абзац с комментарием

//temperature decrease

можно целиком заворачивать в отдельный скрипт сразу. И вызывать его в obj_player Step. В совокупности с неймингом типа obj_player.Main_jet_temp - вы всегда сможете в теле скрипта быстро разобраться. Нейминг скрипта в таком случае должен содержать описательное слово для функции, которую он выполняет, например:

decrease_ship_temperature

Зачем я сделал так как сделал? Потому что дурак криворукий! На самом деле - для меня несколько сложно держать в голове весь листинг, это требует определённой подготовки. И мне проще было катать всё в одну страницу. Это можно пережить, но с парой условий! Во-первых - нужна четкая разметка и нейминг, чтобы через час/день/неделю вы сами смогли бы разобраться в своих каракулях и была бы надежда, что разберётся кто-то другой. Во-вторых при условии, что после отладки вы свернёте всё это и отфильтруете тухлый базар кривой нейминг в более понятный. Ещё раз - читая скрипт должно быть понимание того, что там происходит. типа:

if obj_player.asshole_temperature > 100500 then obj_player.asshole_temperature --;

Кроме того я прибрался в Objects, поудаляв всё лишнее. И да, я по-прежнему считаю, что создавать объект на любой пук - это плохо. Нужно подходить к этому обдумано и логично.

по здравому размышлению, позже, я удалил ещё и obj_expl, который проигрывает анимацию взрыва корабля. И джетфайр, перенеся этот функционал в obj_player и реализовав в скриптах. Я считаю, что это удобнее потому, что текст скрипта в коде будет в явном виде и его так или иначе захочется прочитать, а ссылка на создание инстанса, на мой взгляд, не такая уж и явная. Но, тут надо оговориться, что я решаю конкретную задачу - у меня один корабль, в котором используется один раз взрыв и отрисовка факела. Если объектов, которые используют эти сущности больше чем один - смысл создавать им общий объект - скорее всего - есть.


Ну и видео геймлпея на момент билда. Прикручена температура и евенты (отключение движков и системы при перегреве, подрыв корабля при сходе с дистанции).

Показать полностью 4
[моё] Тег Indiedev Инди игра Gamedev Game maker studio 2 Гифка Длиннопост
8
MrMouseSE
8 лет назад
Лига Разработчиков Видеоигр

Круговая индикация (fixed)... GMS2⁠⁠

В прошлой теме мне справедливо заметили про рукожопость про низкую производительность решения, с чем я согласен. Гораздо более правильно отрисовывать индикатор в один примитив, чем в 100500 линий. @Nefrace , спасибо тебе за поджопник в нужном направлении подсказочку. Был ешё вариант с постепенной отрисовкой спрайта, но, конкретно для этой задачи, данный способ считаю неоптимальным, но, в принципе, более универсальным.

Погнали!

Итак, в чем прикол? Круг отрисовывается в N трианглов целиком, а не из последовательной отрисовки каждой отдельной линии, из которой круг состоит. Не думаю, что можно подвесить приложуху тем круговым индикатором, что был в первый раз, уж больно он прост, но, если напихать вдесятером - то и саша порвётся сильно захотеть - можно что угодно повесить.

Листинг:

почему картинкой? Ну потому что - прошаренные чуваки и так всё напишут, а те, кому это может быть полезным - при переписывании подправят под себя (или хотя бы проникнуться тем, что происходит в скрипте)... хотя кого я обманываю. Если кому-то нужен формат для копипасты: https://pastebin.com/vfnLzgqU

ну и для развлекалова, что можно намутить из такой штуки:

такие загогулины делаются путём добавления в lenghdir_x/lenghdir_y во второй аргумент (угол) функции типа sin/cos/tan и всё такое, можете поэксперементировать сами.

з.ы. вкратце для тех, кто не шарит и хочет разобраться: в скрипт передается значение индикатора (например скорость, под переменную current_value), дальше значение преобразуется в угол дуги через отношение макс.угла к макс.возможному значению счётчика. Потом проверка на активацию (activation_button - это кнопка, которая активирует увеличение значения скрипта). В каскаде условий ещё свистоперделки напиханы, типа замедления увеличения значения обратнопропорционально текущему(типа чем выше скорость, тем медленнее она прирастает). При достижении капа - счетчик сбрасывает рандомное значение, ну типа имитирует реал... впрочем похуй, выглядит збс! :D Дальше в цикле прокатывается i вплоть до текущего значения счетчика в градусах, где шаг - отношение к радиусу. Почему к радиусу? Ну потому что физический смысл получится - кол-во сторон многоугольника... Из свистелко-перделок - определение цвета в зависимости от значения. Если это не надо - можно вынести arc_color выше цикла и завязать на текущее значение

arc_color = make_color_hsv(70 - clamp(70/max_value*current_value,10,70),255,255)

тогда меняться будет вся полоса, а не радугой. Ну и расширение первого значения в hsv - расширит диапазон цветов, дуги. Последняя точка рисуется вне цикла, чтобы прирост дуги был не скачками кратно шагу i, а плавненько.

з.ы. в листинге вариант с половинным градиентом, если хочется, что бы полоска стухала и наружу и внутрь - нужно делать ещё один проход draw_primitive_begin/draw_primitive_end, с циклом, в точках которого указывать альфу наоборот (про толщину тока не забываем). Почему так?

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

з.з.ы. а ещё можно в поверхости бублики вырезать

Показать полностью 5
[моё] Game maker studio 2 Gamedev Гифка Длиннопост VFX
9
MrMouseSE
8 лет назад
Лига Разработчиков Видеоигр

Игра с нуля без мам пап и кредитов на GMS2. build_0_0_3⁠⁠

Гифка для привлечения внимания, на которой ничего не происходит...

Привет! Мне уже всячески рассказали, насколько кривые у меня руки... Вот она популярность! Погнали!

Итак, билд0_0_3. И reFUCKtoring!

Честно говоря это стало для меня неожиданностью. Вернее не сам рефакторинг, его-то я как раз ожидал (изначально всё начиналось, если кто помнит, так, что рефакторинг был лишь делом времени), а вот то, что назреет так быстро - нет. Как я уже говорил в пред. посте - основная проблема нодального программирования в ГРОМОЗДКОСТИ. Адовой, неподъемной громоздкости. В этом отношении GMS2 ещё и проигрывает той же UE4, где можно зафигачить всё более-менее наглядно:

и это реально - НАГЛЯДНО и более-менее понятно. В GMS2 же всё куда как хуже: парадигма расположения блоков в GMS - сверху вниз, в итоге в каждом действии у вас будет вот такая партянка:

как видно - всего десять узлов, а места занимает существенно больше. Тут есть несколько аспектов - в UE вы можете пихать хоть вдесятером... реализовывать сразу всю логику в одном блюпринте, располагая в двухмерной плоскости так, как вам лично будет наглядно. GMS2 честная целочка и пихать в себя позволяет только по очереди распределяет все действия на уровне свойств объекта, поэтому всё в кучу сложить не получится, а самое главное - отойти от вертикали вам позволит только ветвление условия, т.е. "башня" сохранится и станет только толще...

Честно говоря - я не очень уверен, что условия в нодальном GMS2 удобней и читабельней, чем в GML (game maker language):

но совершенно очевидно, что из-за своей громоздкости работать с ними - невозможно.

Итак, рефакторинг! Почему и что привело? Я уже показывал скрин obj_player - там я делал всё на уровне свойств объекта (create,step,collision, etc), что, как уже писал - не удобно с точки зрения того, что постоянно приходится переключаться между закладками и невозможно охватить части функции целиком. Поэтому у меня и встал вопрос: как это всё свалить в кучу, чтобы можно было сразу охватить всё, что происходит.

и тут я подложил себе большую свинью. В силу собственной невнимательности (я как-то сумел себя убедить, что добавлять свойства к объекту - какая-то сложная процедура, а не просто " obj_player.speed_bost = 1 ") я решил всё пихать в global. ... Тут со мной злую шутку сыграла память про типы переменных, типа глобал/локал... короче говно худшее! По-правильному - надо всё пихать в свойства объекта и передавать именно объект в любые другие места! По сути же - я делаю тоже самое! Но пихаю все свойства в объект "global", вместо того, чтобы пихать свойства плеера в объект плеера: "obj_player", в моём случае. Ну и как видно на гифке - листинг хромает. Например

if (keyboard_check(ord("S")) = false) && (keyboard_check(ord("W")) = false)

можно и нужно записывать как:

if !keyboard_check(ord("S")) && !keyboard_check(ord("W"))

Вообще нужно стремиться к мимимизации уменьшению кол-ва символов, в угоду скорости чтения и восприятия. Избавляться от лишнего и всё такое.

Второе худшее говно в представленном листинге, что я, по сути, ебашу функции непосредственно в условии. Т.е. все вот эти

lobal.speed_boost -= global.impulse_value/global.mass_value*global.bc*2;
global.vert_speed_axelerate = -global.impulse_value/global.mass_value*global.bc*2;
global.fuel_tank -= 2;

надо сворачивать в отдельные функции и лишь вызывать из кода, чтобы не захламлять сам листинг, а называть функцию как-то так: vertical_axelerate_increase, vertical_axelerate_decrease, left_axelerate_increase, right_axelerate_increase и т.д. И передавать в них как раз-таки объект, а в самой функции выковыривать из него то, что непосредственно нужно. А так как я - делать не нужно...

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

Так что после нодального представления прототипа - садитесь за рефакторинг и переделывайте всё в код. Это послужит хорошим упражнением для освоения навыков быдлокодинга, которые потом уже можно будет прокачивать в более-менее приемлемые програмистские скилы. Это, конечно же, неправильно - надо сразу учиться хорошо...


ну и текущее состояние:

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

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

Показать полностью 7
[моё] Тег Indiedev Инди игра Gamedev Game maker studio 2 Гифка Длиннопост
12
207
MrMouseSE
8 лет назад
Лига Разработчиков Видеоигр

Круговая индикация, для игры без мам, пап и кредитов... GMS2⁠⁠

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

круговой индикатор, собственно. Скрипт, которому надо скормить несколько параметров и он будет отрисовывать вот это чудо.

настраивается область, диапазон значений, шаг приращения.

ну и для разнообразия пара возможностей

работает слева направо, потому что я живу в РФ, а тут всё слева направо.

листинг:

код в красной рамке на скрине отрисовывает обводку для индикатора. Не делайте так! Ебашьте спрайт и вызывайте один раз. Я это сделал для наглядности. Но оставляю для упоротых, типа меня :D

вызов скрипта:

Юзайте! Хотя кого я обманываю, никому это не нужно :D Но подписчики откуда-то взялись...

Показать полностью 5
[моё] Game maker studio 2 Gamedev Indiedev Гифка Длиннопост
34
Посты не найдены
О нас
О Пикабу Контакты Реклама Сообщить об ошибке Сообщить о нарушении законодательства Отзывы и предложения Новости Пикабу Мобильное приложение RSS
Информация
Помощь Кодекс Пикабу Команда Пикабу Конфиденциальность Правила соцсети О рекомендациях О компании
Наши проекты
Блоги Работа Промокоды Игры Курсы
Партнёры
Промокоды Биг Гик Промокоды Lamoda Промокоды Мвидео Промокоды Яндекс Маркет Промокоды Отелло Промокоды Aroma Butik Промокоды Яндекс Путешествия Постила Футбол сегодня
На информационном ресурсе Pikabu.ru применяются рекомендательные технологии