К карте
ВЕРФЬ · UNITY · КВЕСТ 2
Тень в глубине
0
Прогресс0 / 5
СДЕЛАЙ ПЕРВЫЙ ХОД

Нажми — и увидишь, что делает команда

Жми кнопки по очереди — это три настоящие команды.
ПЕРЕД СТАРТОМ
⏱ Сколько займёт
30–50 минут, 5 шагов. Каждый шаг заканчивается результатом на экране.
💻 Что нужно
Компьютер с Windows или macOS. Понадобится Unity — бесплатная для учёбы, поставим на первом шаге. С телефона этот квест не проходится.
⏸ Если прервёшься
Ничего не потеряется: прогресс сохраняется на этом устройстве. Вернёшься — продолжишь с того же шага.
🎓 Чему научишься
движение и физика · поворот к курсору · плавная камера
ШАГ 1 ИЗ 5 · ВЕРФЬ · UNITY · КВЕСТ 2

WASD под водой

ЧТО ПРОИСХОДИТ
ЭПИЗОД 2Мелководье у верфи

В прозрачной воде под мостками ходит тень. Длинная.

«Не бойся, это твоя», — Марк смеётся. — «Сегодня ты не убегаешь от хищника. Сегодня ты и есть хищник».

Хищник поворачивается туда, куда смотрит, и не дёргается рывками — плывёт. Камера идёт следом, чуть отставая, будто её тянут на верёвке.

Марк · корабельный мастер верфи
ЧТО ПОЛУЧИТСЯ
ЗАПИСЬ ГОТОВОЙ ИГРЫ
Нос всегда смотрит по курсу, повороты плавные, а камера догоняет с небольшим опозданием. Из этих трёх мелочей и складывается «приятное управление».

Ролик 3D — он про ощущение управления, а не про твою сцену. Ты соберёшь то же самое в 2D: плоская акула, курс по курсору, камера с отставанием. Приёмы одинаковые, картинка другая.

СНАЧАЛА — ПОСМОТРИ
ЖИВАЯ ЗАПИСЬ ДВИЖКА
Так выглядит окно Game во время Play: движок рисует сцену кадр за кадром. Кадр из редактора Unity 6 — акула появится в твоём проекте после двух коротких скриптов.
Марк
Читать текстом
Рулевой, сегодня ты не убегаешь от хищника — сегодня ты и есть хищник. Задача: заставить акулу плыть, разворачиваться за курсором и не кувыркаться вверх ногами. И вот мелочь, на которой попадаются все новички. Если просто сложить две клавиши, по диагонали герой поплывёт в полтора раза быстрее, чем по прямой. Игроки находят это мгновенно и начинают всюду плавать зигзагом. Лечится одним коротким словом — normalized.

Сегодня — движение, повороты и первое серьёзное условие в C#.

ЗАДАНИЕ 1 · ДВИЖЕНИЕ
PlayerMovement.csC#
using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerMovement : MonoBehaviour
{
    [SerializeField] private float speed = 2f;
    private Rigidbody2D body;

    private void Awake() => body = GetComponent<Rigidbody2D>();

    private void Update()
    {
        Keyboard kb = Keyboard.current;

        float hor = 0f;
        if (kb.dKey.isPressed || kb.rightArrowKey.isPressed) hor += 1f;
        if (kb.aKey.isPressed || kb.leftArrowKey.isPressed)  hor -= 1f;

        float ver = 0f;
        if (kb.wKey.isPressed || kb.upArrowKey.isPressed)    ver += 1f;
        if (kb.sKey.isPressed || kb.downArrowKey.isPressed)  ver -= 1f;

        Vector2 move = new Vector2(hor, ver).normalized;
        body.linearVelocity = move * speed;
    }
}
[SerializeField] — «покажи это поле в Инспекторе, но чужому коду не отдавай». Так настраивают скорость мышкой, не открывая файл. GetComponent находит деталь на том же объекте. || читается «или».

Повесь скрипт на акулу: перетащи файл из окна Project прямо на объект в Hierarchy.

Проверь заранее: на Player должен висеть Rigidbody 2D с Gravity Scale = 0 (ставили в первом квесте). Нет его — GetComponent вернёт пусто, и Console встретит тебя красной строкой NullReferenceException.

ШАГ 2 ИЗ 5 · ВЕРФЬ · UNITY · КВЕСТ 2

Почему .normalized

ВАЖНАЯ МЕЛОЧЬ
ДИАГОНАЛЬ БЫСТРЕЕ ПРЯМОЙ
Зажми W и D одновременно — акула поплывёт по диагонали. Без .normalized её скорость станет примерно в 1,41 раза выше, чем по прямой: длина вектора (1, 1) равна корню из двух. Игроки такое находят мгновенно и начинают всюду бегать зигзагом. .normalized укорачивает вектор до единицы, сохраняя направление.

Эта мелочь встречается в каждой игре с движением по восьми направлениям. Теперь ты про неё знаешь.

Что делает .normalized с вектором (1, 1)?
Делает его нулевым
Укорачивает до длины 1, оставляя то же направление
Округляет числа
Почему скорость записана как [SerializeField] private, а не просто public?
Так поле видно в Инспекторе, но недоступно чужим скриптам — меньше шансов сломать
public работает медленнее
Разницы нет
НАСТОЯЩИЙ ЭКРАН UNITY — КУДА НАЖИМАТЬ
ТВОЙ ЭКРАН UNITY — КУДА НАЖИМАТЬнажми на кружок — покажу место
Окно редактора
  • 1Hierarchy — выдели акулуСписок объектов сцены. Клик по строке — и справа откроются все её детали. На кадре выбран Ground, у тебя это будет Player.
  • 2Список деталей объектаСюда, ниже Mesh Renderer, встанет твой PlayerMovement.cs — перетащи файл из Project прямо на акулу. Рядом появится поле Speed: это и есть [SerializeField].
  • 3Camera — на неё вешают CameraFollowКамера тоже строчка в списке. Выдели её, повесь скрипт и перетащи акулу мышкой в поле Target — пустое поле, и камера никуда не поедет.
  • 4Play — проверь управлениеWASD или стрелки. Пока игра идёт, крути Speed и Smooth и сразу чувствуй разницу — но запиши удачные числа на бумажке: после Stop они сбросятся.
  • 5Game — игра глазами игрокаЗдесь видно то, что видит камера. Смотри, как она догоняет акулу с опозданием: smooth 2 — лениво тянется, 15 — почти прилипла.
Отмечено:0 из 5

Это настоящий экран Unity 6 — такой же, как у тебя. Нажимай на кружки по порядку: метка покажет место, строка ниже объяснит, зачем оно. Отмечай пройденное — прогресс сохранится.

ШАГ 3 ИЗ 5 · ВЕРФЬ · UNITY · КВЕСТ 2

Нос по курсору

ЗАДАНИЕ 2 · ПОВОРОТ
SharkRotation.csC#
using UnityEngine;
using UnityEngine.InputSystem;

public class SharkRotation : MonoBehaviour
{
    private SpriteRenderer sprite;

    private void Awake() => sprite = GetComponent<SpriteRenderer>();

    private void Update()
    {
        Vector3 mouseScreen = Mouse.current.position.ReadValue();
        Vector3 mouseWorld = Camera.main.ScreenToWorldPoint(mouseScreen);
        Vector3 look = mouseWorld - transform.position;
        look.z = 0f;

        transform.right = look;        // нос смотрит на курсор

        if (look.x < 0f)               // курсор слева — акула вверх ногами
            sprite.flipY = true;
        else
            sprite.flipY = false;
    }
}
ScreenToWorldPoint переводит точку экрана в точку мира — без неё координаты мыши ничего не значат для сцены. У 2D-камеры мир лежит перед ней, поэтому Z у ответа получается −10; строка look.z = 0f убирает эту глубину, чтобы поворот считался только по плоскости. transform.right — «куда смотрит правая сторона объекта». Присвоил ей направление — объект развернулся.

Три строки на разворот и три на анти-кувырок. Без flipY акула, повёрнутая влево, плывёт кверху брюхом — забавно, но неправильно.

НАЙДИ ОШИБКУ
SharkRotation.csнажми на строку с ошибкой
1private void Update()
2{
3 Vector3 mouseScreen = Mouse.current.position.ReadValue();
4 Vector3 look = mouseScreen - transform.position;
5 look.z = 0f;
6 transform.right = look;
7}
Акула разворачивается, но не туда: курсор в центре, а нос смотрит в угол.

Акула разворачивается, но не туда. Курсор в центре экрана, а нос смотрит в угол. Найди строку.

ЭКСКУРС
КАК В НАСТОЯЩИХ ИГРАХ

Камера, которая отстаёт нарочно

Если камера приклеена к герою намертво, картинка дёргается и от неё быстро устают глаза.

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

Ещё один приём — камера чуть смещается вперёд по ходу движения, чтобы игрок видел, куда летит, а не то, откуда прилетел.

ШАГ 4 ИЗ 5 · ВЕРФЬ · UNITY · КВЕСТ 2

Камера едет следом

ЗАДАНИЕ 3 · КАМЕРА
CameraFollow.csC#
using UnityEngine;

public class CameraFollow : MonoBehaviour
{
    [SerializeField] private Transform target;    // за кем ехать
    [SerializeField] private float smooth = 4f;   // насколько плавно

    private void LateUpdate()
    {
        if (target == null) return;

        Vector3 goal = target.position;
        goal.z = transform.position.z;            // камеру по Z не двигаем!

        transform.position = Vector3.Lerp(transform.position, goal, smooth * Time.deltaTime);
    }
}
LateUpdate работает после всех Update — камера едет туда, где герой уже оказался, и картинка не дрожит. Vector3.Lerp — плавный переход между двумя точками. Поле target заполни так: выдели Main Camera в Hierarchy → в Инспекторе найди компонент Camera Follow (Script) → перетащи мышкой строку Player из Hierarchy в поле Target. Поле осталось пустым (None) — камера будет стоять на месте.

Если забыть строку с goal.z, камера уедет в плоскость героя и покажет чёрный экран. Классическая ошибка первого дня.

Что произойдёт, если поставить smooth = 100?
Камера будет прилипать к герою жёстко, почти без плавности
Камера станет медленнее
Unity выдаст ошибку
ШАГ 5 ИЗ 5 · ВЕРФЬ · UNITY · КВЕСТ 2

Настрой ощущения

ЗАДАНИЕ 4 · ФИНАЛЬНОЕ
НАСТРОЙКА ОЩУЩЕНИЙ — ЖМИ НА КРУЖОКнажми на кружок — покажу место
FileEditAssetsGameObjectComponentWindowHelpLayout⬡ HierarchySampleSceneMain CameraDirectional LightPlayerBackgroundWaterSurface◈ SceneGame⚙ InspectorPlayerTransformSprite RendererRigidbody 2DBox Collider 2DAdd Component▤ ProjectConsoleAssetsScenesScriptsSprites▶ Game
  • 1Жми Play — игра запускается прямо в редактореПока идёт игра, значения в Инспекторе можно крутить и сразу чувствовать разницу.
  • 2Поле Speed в твоём скриптеВыдели Player: в самом низу Инспектора, под физикой и коллайдером, стоит компонент Player Movement (Script), а в нём поле Speed. Оно видно, потому что в коде написано [SerializeField]. Крути прямо во время игры.
  • 3Main Camera → скрипт CameraFollowПоле Smooth: 2 — камера лениво тянется, 15 — почти прилипла. Для аркады берут 5–8.
  • 4Запиши удачные числа на бумажкеПосле нажатия Stop все правки, сделанные во время игры, сбросятся. Это ловушка, в которую попадают все.
  • 5Проверь границы мираУплыви к краю. Хочется, чтобы дальше было море, а не пустота — растяни фон в окне Scene.
Отмечено:0 из 5

Настройка чисел — половина работы над игрой. Программист пишет код один раз, а числа крутит неделями.

НОРА · ВЕДУЩАЯ СТУДИИ
Твоя акула плавает, разворачивается за курсором и не кувыркается, а камера мягко идёт следом. Это уже управляемый персонаж — то, ради чего вообще пишут первые скрипты.
Марк
Читать текстом
Акула плавает, нос идёт за курсором, камера мягко догоняет с опозданием. Это уже управляемый персонаж — то, ради чего вообще пишут первые скрипты. А отставание камеры называют сглаживанием: без него от картинки быстро устают глаза. Дальше море наполнится жизнью: рыба пойдёт косяком, и её станет можно съесть.

Задание студии: сделай ускорение по Shift. Подсказка: заведи вторую переменную fastSpeed и выбирай нужную через условие if (kb.leftShiftKey.isPressed).

Поднимай флаг.

Квест пройден!

Хищник плавает, разворачивается за курсором, камера идёт следом. Грейд РУЛЕВОЙ.

Что дальше. Пустое море — скучное море. Марк высыпает за борт ведро мелкой рыбы.

🏅 Забрать диплом Следующий квест: Охота в глубине
🔒

Этот остров ещё закрыт

Сначала пройди предыдущий квест — хотя бы просмотри все шаги.

⚑ Экспедиционный режим