sundwell.dev | Хроники инди-разработки – Telegram
sundwell.dev | Хроники инди-разработки
693 subscribers
224 photos
105 videos
136 links
Всё про инди от реального человека - девлоги, процесс маркетинга, геймдизайн, разработка и пиксель-арт
Download Telegram
День 73

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

Весь день созванивался, собеседовался насчет небольшой подработки на пару месяцев+, т.к. мало ли что может произойти с основной работой, хоть я в ней и уверен на все 100%, но дополнительная страховка и заначка не помешает

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

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

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

Да вот была проблемка - они только начинали работать с разработчиками из Украины и не совсем еще понимали как правильно отправлять средства на банковский счет ФОП.. и я почти три месяца работал без зарплаты, я просто уже не вывозил, денег не было вообще, я брал микрозаймы в разных конторах, т.к. там льготные проценты на первое взятие, продал дофига вещей типа робота-пылесоса, гитара, геймерское кресло, геймерский стол и т.д., очень тяжелое время было..

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

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

Сейчас же с подработками я быстрее накоплю "капитал" на пол года параллельно откладывая на новый ноут, а то текущий уже на грани смерти

В общем к чему это я - откладывайте деньги, хоть на месяц-два минимальной жизни на мивине + жильё, а то блин в долгах жить это просто ужасно, особенно когда нет понимания когда это все закончится
2🔥2
Media is too big
VIEW IN TELEGRAM
День 74

Самый свежий вчерашний пост

Вчера доделал Упёртую Корову и внес некоторые правки в её логику (в основном числовые)

5 секунд перезарядки для рывка это ощущалось как-то много, так что уменьшил до 2 секунд

Увеличил минимальное расстояние для начала Bull Rush с 60 до 120 пикселей

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

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

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

#godot #ritkarampage #разработка
🔥4👍2
Media is too big
VIEW IN TELEGRAM
День 75

Вчера занимался небольшими улучшениями

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

В общем логика спавна такая:
1. Берём случайную точку за экраном пользователя на круге, получается всего 360 градусов, и если упрощать, то всего 360 точек спавна есть
2. Допустим у нас выпал градус "42"
3. Мы создаем невидимую линию (рейкаст) от игрока к точке спавна, и если на этой линии встречается слой "мира" (вода в нашем случае), то мы добавляем к этой точке 90 градусов и так пока на линии между игроком и точкой спавна не будет препятствий

Если арена квадратная - то этот вариант подходит идеально, т.к. всегда как минимум будет 90 градусов свободных для появления врага

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

Также залил на ютуб канал видео с процессом добавления врага "Упёртой Коровы" в игру

#godot #ritkarampage #разработка
🔥2🤔1
День 76

Сегодня ничего нового в игру не добавил, больше занимался теорией, тем более сейчас в курсе уроки идут по типу "Добавляем новую способность", "Добавляем анимацию персонажу/врагу" и т.п., это всё уже у меня готово, так что я сейчас смотрю эти уроки чтобы не пропустить ничего важного, всё-таки этот курс имеет прям нереальный кредит доверия у меня

Дальше по курсу с нетерпением жду очереди урока "Добавляем вес к врагам", я о нём уже рассказывал в этом посте, но еще не реализовывал. А дальше в основном пойдут всякие улучшения и так называемый "polishing" (полировка) игры, будем делать её красивее и сочнее. А, и еще мета-улучшения (это улучшения, которые остаются между игровыми сессиями, как в Vampire Survivors или любой roguelite игре)

Вообще основателем жанра игр Roguelike считается игра Rogue (отсюда и пошло название - roguelike, похожий на Rogue), а Roguelite это упрощенный жанр для широкой аудитории

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

Roguelite - часто имеет мета-прогрессию, то есть между каждой игровой сессией что-то да открывается. Например в Hades мы можем открывать новые божественные оружия и прокачивать самого персонажа, его жизни, урон, рывки и т.д. Даже тот же The Binding of Isaac это roguelite, потому что мы постоянно открываем новые предметы и игра становится так или иначе легче (если не брать соевое молоко на первом этаже, это рип ☠️)

Сейчас я делаю игру именно жанра Roguelite с мета-прогрессией (все-таки решил что она будет)

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

#godot #разработка
🔥3
Media is too big
VIEW IN TELEGRAM
День 77

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

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

Например ускорение стрельбы можно взять 5 раз, а вот новую мутацию "Беги и стреляй" - только один раз, что логично, ведь это уникальная способность

И да, первая адекватная мутация в деле - "Беги и стреляй", название говорит само за себя - теперь при стрельбе Ритка не медленно ходит, а бегает

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

К слову нас уже намного больше, чем неделю назад (больше чем +20, очень рад этому) и я хотел бы напомнить, что сейчас я занимаюсь разработкой мини-игр с механиками, которые будут (или не будут) в моей, на данный момент, финальной игре

Моя цель сделать игру в жанре top-down ARPG looter-shooter - в основном буду полагаться на Path of Exile и Диабло 2, обожаю ARPG c прокачкой и лутом 🥳

Как всегда прикрепляю короткое превью того, что сейчас уже получилось (кстати баги спавна врагов присутствуют, надо фиксить)

#godot #ritkarampage #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1🤔1
День 78

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

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

Есть враг Дикобраз-Иглострел и, фактически, его спрайт занимает около 16х16 пикселей, но та анимация с иглами требует места, поэтому я расширил спрайт до 32х32px, а Дикобраз остался в углу, поэтому если просто этому спрайту задавать "flip_h" (отразить по горизнотали) - то дикобраз перемещается с одного угла в другой - поэтому мне нужно было вместо с поворотом спрайта еще менять ему позицию, что казалось диким костылём (так и есть)

И, вчера, когда я смотрел как препод анимирует персонажа и врагов, он (препод) показал как отражать по горизонтали правильно - создавать родительский контейнер Node2D, пихать в этот контейнер спрайты и всякую визуальщину, которая привязана к объекту, а потом просто менять Scale (масштабирование) на -1 и спрайты тоже отражатся, но стоя на месте.. что нереально удобно. Конечно мне кажется что нет "серебряной пули" и это выглядит как слишком идеальное решение, так что спросил у сообщества (кстати это пример очень хорошо составленного вопроса, можете брать на заметку) и посмотрю, что они скажут насчет этого (P.S. ответ получен, все четко, так можно делать если только нода отвечает за визуал)

Прикрепил видео с моей реакцией, объяснением и фиксом к посту

Еще я задал пару вопросов преподавателю (довольно часто задаю вопросы и получаю очень полезные ответы), прикреплю скрины вопросов к посту тоже

Один с вопросов - "Как правильно проверять наличие постоянных улучшений?", т.к. у меня есть улучшение, которое меняет поведение скрипта, а не просто с циферками балуется, то мне нужно каждый раз проверять: "а есть ли улучшение? Ага, есть, тогда делаем так", и сейчас оно выглядит как-то очень-не-очень, каждый раз прописывать mutations.has("some_mutation_id") - ну такое, но если даже сделать какой-то флаг типа var has_run_upgrade: bool и его обновлять когда улучшение было выбрана - это классно, но если мутаций будет довольно много, то очень быстро все превратится в бардак, так что интересно что ответит преподаватель

Второй вопрос про пример кода стейт-машины на GDScript от преподавателя, я видел у него код на C#, но есть определённые трудности в переносе на GDScript, так что тоже жду ответа с нетерпением, а то просто на енамах далеко не уедешь

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

Кстати вот ссылка на репозиторий с игрой, может кому будет интересно/полезно глянуть - https://github.com/Sundwell/ritka-rampage

#godot #ritkarampage #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
День 79

Наконец-то теперь у меня есть идеальный (для меня) вариант создания и использования стейт-машины, я прям преисполнен радостью, от души отлегло 💃

Вчера получил ответы на свои вопросы от автора курса (я очень доволен тем, что он не только вообще отвечает, так еще и быстро это делает)

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

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

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

Я вообще люблю делиться знаниями и помогать другим в обучении, уже на протяжении 3х лет я так или иначе кого-то обучаю, менторю и подобное

Я выделяю как минимум три причины, из-за которых в основном преподают практикующие специалисты:

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

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

Желание.. помогать?
Не знаю как эту причину описать, но я постараюсь

У меня в начале пути было столько проблем, столько страхов, глаза разбегались что учить? Зачем учить? Где это пригодится? Где то пригодится? А надо ли вообще это учить и.. как это использовать? А не трачу ли я свое время зря? А получится ли у меня?

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

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

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

Прикреплю скриншоты ответов от преподавателя и код ДО и ПОСЛЕ рефакторинга моего скрипта для игрока player.gd

#godot #ritkarampage #разработка
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍1
День 80

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

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

А я скорее всего сделаю так, чтобы при смерти любого врага и персонажа тоже проигрывался кадр смерти (для Ритки это будет анимация + замедление времени) и чтобы лужа крови появлялась изпод врага и во время этой смерти будет вылетать полупрозрачная душа этого врага, типа снизу такой хвост как у привидения, сверху часть тела врага и лапы/руки скрещены на груди или же сложены вместе типа молитвы, а сверху нимб над головой, и эта душа будет улетать вверх, становиться все более прозрачной и во время полёта будет двигаться влево-вправо 😅

Мило и жестоко одновременно, как раз в тему для игры

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

#godot #ritkarampage #разработка
2🔥1
День 81

Наконец-то готовы и внедрены анимации смерти врагов

Вчера я сделал DamageComponent (вероятно название могло быть и понятнее) и DeathComponent. Первый отвечает за "выброс" крови и мигание спрайта красным при получении урона врагами, а второй при смерти испускает дух врага 😅

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

Еще обязательно нужно доделать чтобы при смерти врагов и Ритки растекались лужи крови

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

Также прикрепил видео с результатом на сейчас и еще с небольшим процессом пиксель-арта

#godot #ritkarampage #разработка
🔥1
День 82

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

— Начало математических извращений —

Что я понял вообще - что lerp это плавный путь к достижению цели НО без достижения самой цели, то есть у нас есть функция, которая вызывается каждый кадр (будь-то 10, 60 или 300 кадров в секунду) это все работает идеально именно из-за этого "НО" и просчитывается все практически пропорционально, например:

У нас есть delta - время, которое прошло с момента предыдущего кадра, если FPS 60 - то каждый кадр delta = секунда / кол-во кадров = 1 / 60 = 0.0167, если бы кадров было 2 в секунду - то delta = 1 / 2 = 0.5, что делает игру независимой от кол-ва кадров (как-то расскажу об этом тоже), ну щас о другом

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

Максимальная скорость закрывания двери - 60км/ч (нормальный пинок кста), назовём эту скорость DOOR_SPEED, и каждую секунду дверь замедляется наполовину от текущей скорости, т.е.:
1 секунда - 60км/ч
2 секунда - 30км/ч
3 секунда - 15км/ч
...и так далее, и она никогда не будет равна нулю (странная дверь, закрываться не хочет и останавливаться тоже)

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

Что у нас означает замедление - банально уменьшение скорости от 60 до 0, вот формула lerp для такого:
lerp(текущая_скорость_двери, 0, 1 - (delta * 30) = lerp(текущая_скорость_двери, 0, 1 - (0.0167 * 30) = lerp(текущая_скорость_двери, 0, 0.5) => это значит, что каждый кадр скорость двери будет уменьшаться наполовину от текущей скорости, что в свою очередь значит.. что дверь за долю секунды практически закроется с бешеной скоростью..

У нас 60 кадров в секунду в игре
1 кадр - 60км/ч
2 кадр - 30км/ч
3 кадр - 15км/ч
...
То есть буквально за 7-8 кадров (это почти десятая часть секунды) дверь уже будет закрыта, но нам же надо закрывать дверь плавно, а не быстро, каждую секунду надо, а не кадр

Я упущу расчеты коэффициента.. для уменьшения вдвое каждую секунду он должен быть 0.6931
lerp(текущая_скорость_двери, 0, 1 - (delta * 0.6931) => lerp(текущая_скорость_двери, 0, 1 - (0.0167 * 0.6931) => lerp(текущая_скорость_двери, 0, 0.0116

То есть каждый кадр при 60 кадрах в секунду у нас текущая скорость двери приближается к желаемой со скоростью 1.16% за кадр (т.к. 1 = 100%, 0.0167 = 1.16%). В таком случае каждую секунду у нас будет уменьшаться скорость двери примерно вдвое
0 кадр - 60.0000
1 кадр - 59.3040
2 кадр - 58.6161
3 кадр - 57.9241
4 кадр - 57.3282
...
60 кадр - 30.0000
...
120 кадр - 15.0000

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

— Конец математических извращений —

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

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

Рандом спавн еще не сделал - но завтра доделаю, логику уже понял

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

#godot #ritkarampage #разработка
🔥3