Камера для авиасимулятора на Unity.
Я продолжаю работать над аркадным авиасимулятором. Это мой первый проект, и я хочу поделиться, с какими сложностями мне пришлось столкнуться при реализации камеры.
Лирическое отступление
Когда я принял решение делать авиасимулятор, одним из первых моих шагов было поиграть в различные игры, где нужно управлять самолётом. Цель проста — нужно понять, какие есть варианты управления камерой и самим аппаратом, как они ощущаются и что можно перенять.
Сам я летал на самолёте только в GTA, и заранее держал в голове, что камеру и управление буду перенимать оттуда. Однако для чистоты эксперимента решил попробовать представителей жанра авиасимов. Вот их перечень: ИЛ-2 Штурмовик, Project Wingman, X-Plane 12, Sky Rogue, Aviassembly.
Спектр оказался очень широким, и выбирать было из чего. Управление, в целом, было схожим (кроме сверххардкорного Project Wingman). В итоге за образец управления самолётом и камерой я всё таки взял полёты в GTA V.
Реализация
За основу я взял код из учебника Unity in Action. Знакомство с движком я начал с изучения этой книги, и у меня остались учебные примеры оттуда.
Управление камерой там совсем примитивное, но для начала сойдёт.
Мы видим, что камера летает вокруг самолёта, но проходит сквозь текстуры. Это сильно портит впечатление от игры.
Я написал функцию проверки коллизий между камерой и целью для того, чтобы этого избежать.
Уже намного лучше. Но теперь появился ещё один недостаток: в глобальных координатах камера не двигается относительно объекта, если не шевелить мышью. Из-за этого во время манёвра она может оказаться против хода движения, и мы не увидим, куда летит самолёт. Нужно, чтобы камера выравнивалась по ходу движения.
Чтобы решить эту задачу, я завёл переменную inputTimer, которая каждый Update уменьшается на Time.deltaTime, но если игрок шевелит мышью — таймер восстанавливается до изначального значения.
С учётом этого таймера я разбил функцию управления камерой на два блока. Первый блок мы уже видели — он выполняется, если игрок двигает мышью. Второй блок начинает работать во время «простоя» мыши.
Стало намного приятнее летать! Теперь камера плавно следует за самолётом и в виражах повторяет его повороты. Но вскрылась ещё одна проблема. Если после автоматического следования камеры пошевелить мышью, она резко скачет.
Причина в том, что переменные _rotationY и _rotationX ничего не знают про автоматическое следование и остаются на тех же значениях, которые были в момент окончания таймера ожидания. Когда игрок двигает мышью, они начинают именно с того места, где «уснули».
Чтобы исправить это поведение, нужно рассчитывать текущие углы камеры в момент начала ввода. После этого камера будет вращаться корректно.
Почти идеально. Осталось ещё кое-что: если самолёт кренится или уходит в пике, камера начинает вести себя странно. При вращении мышью продольная ориентация камеры перестаёт совпадать с самолётом.
Причина в том, что камера крутится в глобальных координатах. Пока вертикальная ось самолёта совпадает с мировой — всё нормально, но стоит ей отклониться, и камера начинает вести себя неправильно. Эта задача решается простым перемножением кватернионов:
Примерно так. Повествование я разбил на те же этапы, которые вызывали у меня затруднения. Сейчас камера работает вполне приемлемо для прототипа. В дальнейшем я её ещё отполирую, но пока этого более чем достаточно.
Спасибо за внимание!
Если интересно, подписывайтесь на мой телеграм-канал. Там я регулярно делюсь прогрессом по своему проекту.