Карта и система меток для метроидвании на Unity

Карта и система меток для метроидвании на Unity

Одной из самых важных фич в метроидваниях является карта.

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

Я около года занимаюсь разработкой своей метроидвании на Unity. Карта для нее была разработана уже давно, а вот до меток все никак не доходили руки

🗺 Карта на основе RawImage

В Тень Ориды карты рендерится в реальном времени — через отдельную камеру Unity, которая видит только нужные слои уровня (тайлы, стены, двери и т.д.).

Карта и система меток для метроидвании на Unity

Для этого камере указывается Target Texture — специальный RenderTexture, а затем это изображение выводится в UI через RawImage:

miniMapCamera.targetTexture = mapRenderTexture; mapImage.texture = mapRenderTexture;

Такой подход даёт нам несколько преимуществ:

  • Карта всегда точна – она обновляется вместе со сценой, включая динамические элементы.
  • Не нужно рисовать вручную – визуализация строится прямо из геометрии уровня.
  • Можно применять эффекты – например, лёгкое затемнение или маску "неизученных" областей.
  • Работает с любой локацией без дополнительных манипуляций

В отличие от заранее подготовленных текстур, этот подход ближе к реалистичной миникарте. Камера «смотрит» на карту и формирует её прямо в момент игры.

🧭 Проверка доступности карты

Карта открывается не всегда – только если нашел ее на локации..Для этого в коде есть простая, но наглядная проверка:

case "Level3": mapAvalible = _saveData.mapLevel3; break;

Карта каждой локации имеет свой флаг, который сохраняется в SaveData. Если карта недоступна, то игрок вместо нее видит заглушку:

Карта и система меток для метроидвании на Unity

🔖 Система пользовательских меток

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

Когда игрок кликает по карте, происходит следующее:

  • если рядом уже есть метка – она удаляется;
  • если нет – создаётся новая и сохраняется.

На отладку этого добра ушло часа четыре. Проблема была в том, что нужно было учитывать соотношение размера RawImage и параметров камеры. Без этого метки не фиксировались на карте.

Ключом к успеху стал этот фрагмент кода:

Vector3 worldPos = miniMapCamera.transform.position + new Vector3( (localPoint.x / mapImage.rect.width) * miniMapCamera.orthographicSize * 2f * miniMapCamera.aspect, (localPoint.y / mapImage.rect.height) * miniMapCamera.orthographicSize * 2f, 0f);

Он позволяет правильно масштабировать смещение курсора (localPoint) в мировые координаты, учитывая текущий зум камеры (orthographicSize) и её aspect ratio.

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

Метки за границами текущего обзора карты
Метки за границами текущего обзора карты

💾 Как хранятся метки

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

_saveData.SetMarkersForLevel(currentScene, worldPositions);

Ключом служит имя сцены, а значением – массив Vector2 с мировыми координатами. Когда игрок возвращается на локацию, мы просто подгружаем эти точки и воссоздаём метки.

Таким образом, карта запоминает все отметки игрока.

💡 Подсказка для новичков

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

Карта и система меток для метроидвании на Unity

Она исчезает автоматически, как только игрок впервые ставит метку.

🔍 Зум и движение по карте

Карта поддерживает плавное движение курсора и масштабирование. В Тень Ориды я использую Input System для управления игрой, чтобы корректно работать и с клавомышью, и с геймпадом.

Для удержания зума добавил мини-таймер, который делает увеличение пошаговым и плавным:

private float zoomHoldInterval = 0.1f;

Каждые 0.1 секунды при удержании кнопки изменяется orthographicSize камеры, и игрок чувствует лёгкое «прокручивание» карты.

zoomTimer -= Time.unscaledDeltaTime; if (zoomTimer <= 0f) { if (zoomingIn) { ZoomMap(1); zoomTimer = zoomHoldInterval; } else if (zoomingOut) { ZoomMap(-1); zoomTimer = zoomHoldInterval; } }

🧩 Архитектура

Я сознательно отказался от сложных ScriptableObject-систем и других решений. Всё реализовано на чистом Unity UI, с минимумом зависимостей:

  • RawImage – визуальная часть карты;
  • RectTransform – дочерний контейнер для меток;
  • Camera + RenderTexture – слой визуализации;
  • Хранение меток и доступности карты реализовано через SaveData, который используется для хранения вообще всех состояний игры

А сами метки это обычные объекты с Image, созданные из префаба:

GameObject markerGO = Instantiate(mapMarkerPrefab, markersContainer);

Система получилась лёгкой, гибкой, и она не ломается от изменений в уровнях.

🧠 Что нам это дало

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

🚀 Что дальше?

Я продолжаю готовить Тень Ориды к выходу в Steam, работаю над новыми механиками и устранением ошибок в игре.

Следить за разработкой и развитием игры можно в моем скромном Telegram канале.

3