Глобальная перепись кода — как я пересобрал «Прощай» и что из этого вышло
Следите за анонсами на itch.io
Последние дни я провёл не за написанием новых диалогов и не за рисованием спрайтов, а за тем, что переписал практически весь код игры. Сначала я думал, что можно обойтись точечными правками, но чем дальше, тем больше система давала сбоев: переходы между сценами работали через раз, позиция игрока терялась, меню паузы и дверей конфликтовали, а при сборке билда всё разбегалось кто куда. Пришлось остановиться и пересобрать архитектуру с нуля.
Ниже хроника этой перестройки, трудности, с которыми я столкнулся, и то, как они решались. Надеюсь, мой опыт пригодится тем, кто тоже мучается с Unity.
1. От разрозненных скриптов к единому GameManager
Было:Скрипты сохранения, загрузки, переходов, дней и мета-слоя были раскиданы по разным объектам. Каждый сам решал, когда сохранять позицию, а когда загружать. В результате при переходе из кухни в комнату игрок иногда оказывался за стеной, а день мог сброситься на первый.
Стало:Я ввёл GameManager - синглтон, который живёт между сценами и централизованно управляет переходами (ChangeLocation), днями, позицией игрока. Теперь все переходы идут через него, а сохранения (временные) тоже хранятся в нём.
Трабл:Сначала я намудрил с DontDestroyOnLoad и в итоге получил два GameManager в сцене. Один из них был неактивен, из-за чего корутины не запускались, и двери перестали работать. Пришлось прописать в Awake правильную проверку и удалять дубликаты.
2. Меню паузы и двери: курсор и активность
Было:Меню паузы открывалось по Esc, но курсор не появлялся. А при открытии меню дверей курсор появлялся, но потом его нельзя было спрятать. В итоге игрок мог кликать по UI, не видя мыши.
Стало:Я добавил в PauseMenu и DoorWithMenu явное управление Cursor.visible и Cursor.lockState. При открытии меню курсор виден и свободен, при закрытии скрыт и заблокирован в центре. Также пришлось прописать отключение управления игроком ( player.enabled = false ), чтобы он не ходил, пока висит меню.
Трабл:Сначала я забыл отключать PlayerMovement в меню дверей, и персонаж продолжал двигаться под интерфейсом. Потом наоборот отключал, но не включал обратно при закрытии. Долго ловил эти гонки.
3. Анимации: почему спрайт то появлялся, то исчезал
Это была самая нервная часть. Анимации ходьбы работали, но в некоторых кадрах персонаж исчезал. Я проверил всё: SpriteRenderer, Order in Layer, скрипты. Причина оказалась в анимационном клипе: в нём были пустые кадры и ключи на enabled = false.
Решение:Я заново пересобрал анимации: выделил все кадры в окне Project, перетащил на персонажа - Unity сама создала новый клип. Потом в Animator добавил параметр Speed (Float) и настроил переходы: Idle → Walk при Speed > 0.1, Walk → Idle при Speed < 0.1. Теперь персонаж ходит без пропаданий.
4. Камера в билде: объекты разбегаются
Когда я собрал первый билд после всех правок, ужаснулся: камера показывала только центр сцены, а все объекты сместились. Оказалось, что в билде разрешение экрана отличается от того, что я видел в редакторе.
Решение:Я написал скрипт CameraFitter, который подстраивает ортографический размер камеры под реальное разрешение экрана, сохраняя пропорции заданной игровой области. Теперь в любом окне сцена видна целиком.
5. Настройки: кнопки не привязывались и GameManager выключался
Сначала в инспекторе кнопок настроек и выхода не было методов OpenSettings и QuitGame. Пришлось переписать MainMenu, явно добавив эти методы и убедиться, что объект со скриптом правильно перетаскивается в OnClick.
Потом возникла новая проблема: после закрытия настроек GameManager становился неактивным. Оказалось, что скрипт SettingsManager висел на том же объекте, что и GameManager, и в ClosePanel() вызывался gameObject.SetActive(false). Я вынес SettingsManager на отдельную панель, а в ClosePanel() отключаю только её.
6. Что в итоге
Сейчас код выглядит так:
- GameManager -- один на все сцены, управляет переходами, днями, позицией игрока.
- DayCycle -- просто триггер для смены дня (вся логика в GameManager).
- DoorWithMenu -- вызывает GameManager.ChangeLocation, сам открывает/закрывает меню дверей, управляет курсором.
- PlayerMovement -- только движение и передача скорости в аниматор.
- CameraFitter -- адаптация камеры под любой экран.
- MainMenu -- кнопки и вызов GameManager.StartGame().
- SettingsManager -- настройки на отдельном объекте, не трогает GameManager.
7. Ошибки, которые я запомнил
- Нельзя вешать скрипты, которые отключают объект, на критически важные менеджеры.
- Корутины не запускаются на неактивных объектах. Всегда проверяйте gameObject.activeInHierarchy.
- Анимации нужно пересобирать, если они сломались, а не искать причину в коде.
- Ссылки в инспекторе - самое слабое место. После каждой пересборки префабов они слетают, и это нормально, нужно проверять заново.
8. Что дальше
Теперь, когда архитектура стабильна, я возвращаюсь к контенту:
- Интеграция диалогов (тексты уже написаны).
- Флешбек (центральная сцена).
- Звуки шагов, дронов, атмосферы.