C# в Unity: как написать первый скрипт и понять, почему он работает
Скрипт без ошибок лежит в Project, но в игре ничего не происходит. Для новичка это выглядит странно: код написан, Unity его видит, почему объект стоит на месте? Обычно не хватает связи между классом и объектом сцены либо ожидаемый метод вообще не вызывается.
Разберём основы C# именно в контексте Unity: как скрипт становится компонентом, где хранятся данные, когда вызываются методы и как проверить результат. Начнём с вращающегося куба, затем добавим пример здоровья — небольшую игровую модель с понятными условиями.
ТОП-5 курсов обучения Unity:
C# и Unity отвечают за разные части задачи
C# — язык программирования. В нём вы описываете переменные, классы, методы и условия. Unity предоставляет API для объектов, физики, звука и других возможностей движка. Выражение transform.Rotate(...) использует синтаксис C#, но обращается к объекту Unity.
Поэтому учиться удобно по двум направлениям. Для вопроса «как работает if» откройте руководство Microsoft по C#. Для вопроса «когда Unity вызывает Update» нужна документация движка. Версия языка и набор доступных библиотек в проекте зависят от среды Unity; примеры из самого нового .NET не всегда переносятся без изменений.
Создайте скрипт и подключите его к объекту
- В новом проекте создайте Cube и сохраните сцену.
- В Assets создайте папку Scripts.
- Создайте C#-скрипт SimpleRotator.cs и откройте его в редакторе кода.
- Замените содержимое кодом ниже и сохраните файл.
- Вернитесь в Unity, дождитесь компиляции и добавьте скрипт на Cube через Inspector или перетаскиванием.
Нажмите Play. Куб должен вращаться вокруг своей вертикальной оси. Измените Degrees Per Second в Inspector и сравните движение. Перед постоянным изменением настройки остановите Play: обычные правки компонентов во время запуска не сохраняются как изменения сцены.
Unity описывает создание файлов скриптов в руководстве по скриптам. Файл и класс компонента должны иметь согласованные имена. Красные ошибки компиляции сначала исправляют в Console, затем проверяют поведение.
Прочитайте пример по строкам
using UnityEngine позволяет обращаться к типам пространства имён UnityEngine без полного имени. SimpleRotator — наш класс. Наследование от MonoBehaviour делает его компонентом, который можно использовать на GameObject.
degreesPerSecond — поле типа float. Значение 90f означает число с плавающей точкой; суффикс f соответствует float. Модификатор private ограничивает доступ из другого кода, а SerializeField позволяет Unity сохранить поле и показать его в Inspector.
Update — метод, который Unity вызывает у работающего компонента во время кадров. Внутри мы обращаемся к Transform своего объекта и поворачиваем его. Time.deltaTime переводит скорость в изменение за прошедшее время кадра.
Без умножения на время значение «90» означало бы поворот на 90 градусов при каждом вызове. При разных частотах кадров скорость заметно отличалась бы. Когда задаёте свойство физической скорости Rigidbody, расчёт другой: его не нужно повторно переводить в перемещение за кадр.
Данные, условия и методы на примере здоровья
Модель здоровья должна отвечать на несколько вопросов: сколько его было в начале, сколько осталось, можно ли принимать урон и что происходит при нуле. Создайте файл Health.cs:
Добавьте Health на отдельный объект. В Play откройте контекстное меню компонента и выберите Test → Take one damage три раза. Console покажет уменьшение здоровья, а после третьего вызова объект выключится. Проверку выполняйте в Play, чтобы Awake уже инициализировал состояние.
Возврат через return останавливает метод, если урон некорректен или персонаж уже отключён по правилу здоровья. Max не даёт числу стать отрицательным. Public-метод TakeDamage — точка входа для другого кода, а свойства Current и IsAlive дают читать состояние без произвольного изменения поля current.
Это учебная модель одной жизни. Простое повторное включение объекта не восстанавливает здоровье: для возрождения нужен отдельный метод сброса или другое правило инициализации. Такой предел примера полезно понимать до подключения к системе появления персонажей.
Когда использовать Awake, Start, Update и FixedUpdate
Awake удобно использовать для локальной инициализации и получения собственных компонентов. Start — для стартовой работы после начальной инициализации объектов. Update подходит для кадровой логики и чтения ввода. FixedUpdate используют для действий, согласованных с шагом физики.
Не полагайтесь на случайный порядок Update двух разных компонентов. Если системе нужен явный сигнал о событии, лучше передать вызов или событие. Подробности жизненного цикла находятся в документации порядка выполнения.
Как один скрипт получает доступ к другому
Когда объект известен заранее, объявите сериализованную ссылку и назначьте её в Inspector. Когда компонент должен находиться на том же объекте, используйте GetComponent. Поиск по всей сцене нужен в других ситуациях и имеет собственные ограничения.
Например, попадание вызывает TakeDamage у конкретного Health. Враг не должен угадывать, какая из десятков сущностей является целью, по первому случайно найденному объекту. Разные способы поиска разобраны в статье о поиске объектов из C#.
Почему скрипт не работает: порядок проверки
- Есть красные ошибки: откройте первую содержательную ошибку компиляции и исправьте её. Остальные могут быть следствием.
- Компонента нет на объекте: файл в Project сам по себе не запускает поведение объекта.
- Объект или компонент выключен: проверьте активность и условия вызова нужного метода.
- Метод написан с другим именем: update и Update — разные имена.
- Ссылка равна None: назначьте нужный объект или найдите причину отсутствия ссылки.
- Значение в Inspector отличается от кода: сохранённое значение компонента может оставаться прежним после изменения инициализатора поля.
Для наблюдения добавьте временный Debug.Log в ожидаемый метод. Если сообщение не приходит, проверяйте вызов. Если приходит, выводите нужные данные и проверяйте условие. Такой способ постепенно сужает проблему; бессистемное изменение нескольких мест одновременно затрудняет проверку.
Что изучать дальше
После этих примеров полезны коллекции, события, ссылки на объекты, исключения и простая организация классов. Каждый новый приём закрепляйте механикой: список предметов для инвентаря, событие изменения здоровья для интерфейса, состояние для меню паузы.
Если хочется собрать эти основы в результат, переходите к первой законченной игре. Главное достижение начального этапа — уметь объяснить, какие данные меняются, какой метод это делает и как проверить ожидаемое поведение.