Red dust. Странные решения в разработке
Хочу рассказать про неоднозначные/спорные/костыльные решения проблем в моей игре, но сначала вступление.
Некогда мне друг показал Receiver, многим известую игру с подробной механикой пистолетов. Не сразу, но игра захватила мой интерес и одновременно с моментом когда игра была пройдена вдоль и поперек огромное количество раз, я решил сделать небольшую игру, само собой на Unity. Самым очевидным на тот момент стало решение сделать клон ресивера добавляя в него то, чего мне очень не хватало в receiver`е, а именно:
- анимированные руки
- видимое тело (это я люблю в любых играх от перого лица)
- случайная расстановка противников
- генерация уровня в 3 осях(в итоге реализованно только 2)
- хоть какая-нибудь оптимизация (в сравнении с оригиналом)
Еще много чего хотелось, но эти задачи были в приоритете. И, конечно, была мысль "я быстренько слеплю игру, может за пару другую месяцев, а потом по желанию буду дорабатывать". Я никогда в жизни так не ошибался©. На самом деле ошибался в последующем, точно также, много раз. Зато теперь более менее научился оценивать затраты времени.
Игра в своем роде учебная практика, что-то вроде первого блина комом, на котором я учился. Поэтому в ней очень много недочетов. Но чтобы привести ее к нормальному состоянию понадобится начать ее с нуля, делать этого я не буду, а следовательно она останется "как есть".
А теперь о странных, на мой взгляд, решениях которые я применил в этой игре. Это не лучшие решения, но они работают, хотя и требуют доработки.
Коллиматор
Хочется отметить как меня сильно раздражают в играх прицельные маркеры которые нарисованы прямо внутри коллиматора, тем более, для меня такое решение никак не подходило. На тот момент я не нашел информации как сделать прицел просто. Вот моё простое решение правильно работающего прицела.
За прицел устанавливается модель в форме усеченной пирамиды закрывающая прицельный маркер, но с отверстием под окошко коллиматора. На эту модель вешается материал с простым шейдером и устанавливается порядок рендера например 3001 (Transparent + 1), а на маркере очередь рендера например 3002. Маркер отодвигаем на нужное расстояние, например метров на 50-100, увеличиваем в размере, чтобы было видно из камеры. Таким образом сам маркер мы будем видеть только через небольшое отверстие в центре перекрывающей модели, и маркер будет рендрится поверх перекрывающих его объектов.
собственно в самом шейдере практически ничего нет
Tags{ "Queue" = "Overlay" "RenderType" = "Transparent"}
LOD 100
Ztest Always
Blend Zero One
Pass{}
HUD
Начать с объяснения как обычно разделены камеры в шутерах от первого лица. У персонажа есть 2 камеры, одна из них рендрит только мир, вторая только руки персонажа. Это необходимо чтобы длинное оружие, да и руки тоже не провалиались в стены. Иногда правда получается нестыковки размера оружия и близко расположенных объетов мира, в нормальных играх это все лечится.
Задача - сделать иконки для объектов, и в первую очередь для патронов, которых здесь без очков на полу не отыщешь. Также надо было обозначить бустеры по назначению, чтобы игрок поднимая с пола какую-нибудь гадость точно знал, какой бонус он от нее получит. В задачи также входило чтобы эти иконки были видны только на определенном расстоянии, чтобы не засорять экран кучей иконок со всей видимой части карты. Вот мое решение.
На объект вешается спрайт с билборд шейдером, нулевым скейлом и очередью рендера >3002, и сам объект рендрится на камере с руками. Теперь все иконки рендрятся поверх всех объектов, включая колиматор. Также дальность отрисовки зависят только от дальности рендера камеры рук, которую обычно ставят <5м, в виду того, что дальше и надо. В игре увеличивая дальность камеры рук можно дальше видеть противников за стенами, замечать мины и сундуки, обозвал этот параметр "radar range". Кстати, получилась самая необходимая вещь в игре.
У такого подхода есть плюс, можно буквально засорить такими спрайтами игру. Я так делать не стал, но обвел верхнюю часть обрыва, чтобы во время затмения без фонарика был хоть какой-то шанс не свалиться.
А теперь о самом главном минусе. Чем дальше от центра экрана стоит такой спрайт, тем он больше по размеру. Это особенность 3д рендера на плоскость, то что ближе к краю будет больше по размеру. Так как у всех спрайтов скейл нулевой, а размер диктуется шейдером, то они какбы находятся на одной плоскости перпендикулярной камере.
Да, это костыльное решение, но согласитесь, что это разгрузит процессор от просчета дистанций до каждого патрона, каждого врага, каждого бокса и прочего интерактивного объекта. Правда я немного увлекся и сделал весь HUD с помощью таких спрайтов)
Активация противников
Долго не мог победить баг со срабатывание мин через стену, или турелей которые сгенрились слегка в стене, и в момент когда точка из которой выпускается луч в сторону персонажа погружается в стену, турель начинает видеть через нее. Тут всё на самом деле довольно просто, я развернул луч в обратную сторону, теперь луч выпускался из персонажа в сторону врага. Персонаж в стене не сгенерируется и сам в нее не попадет. Конечно, при правильном подходе таких багов вообще не должно случаться, но чем переделывать с нуля...
Повороты дроида
ИИ дроида это вообще смех. Но сейчас не об этом. Я пытался сделать повороты дроида и его движение по поверхности более менее неотторгающими. Но что бы я не делал, он то и дело проскальзывал по земле ногами, или буксовал при повороте в сторону как на льду. Сама физика перемещения мена устраивала, не устраивало как ведет (а скорее как выглядит) робот при перемещении.
Решение - управлять мешем с анимацией отдельно от физического объекта дроида. По сути он просто брал вектор скорости из риджид боди, и поворачивал меш в этом направлении. Теперь меш робота был повернут всегда в ту сторону куда он бежал, хотя фактически был повернут к цели. Правда если дроид стоит и вдруг резко начинает бежать в сторону, само собой это происходит мгновенно, бороться с этим я уже не стал, от этого не так сильно течет кровь из глаз, по крайней мере уже не брызжет.
Погладь кошку
В самом конце разработки я добавил кошкодевочек, и очень мне хотелось чтобы можно было их гладить. Это значит что надо будет вешать ИК на руку, а в руке пистолет, а на нем не мало скриптов висит, его отключение сулило много багов, которые я со временем буду расхлебывать еще не один месяц. А еще совсем не хотелось переключаться между контроллерами анимаций. Одним словом делай я это заранее было бы лучше.
Тут никаких слов кроме как костыль не приходят в голову. Просто добавил еще одну пару рук. Одни опускаются за камеру, вторые включаются. Ругайте материте, но как по мне, решение оправдано, на производительность оно не влияет.
Возможно это не самые странные решения, но игру я делал один и в геймдеве не работал, так что как решают подобные проблемы я не знаю. Надеюсь кому-то будет полезно, или по крайней мере интересно.
Игру можете посмотреть по ссылке.
Спасибо за внимание.