Первый скрипт: MonoBehaviour как компонент

Пора оживить объекты кодом. В Unity скрипт — это тоже компонент, и он подчиняется тем же правилам, что и встроенные.

Суть: скрипт на C# становится компонентом, когда его класс наследует MonoBehaviour. Имя файла должно совпадать с именем класса. Навешиваешь скрипт на объект — и Unity начинает вызывать его методы по своему расписанию.

До этого мы навешивали готовые компоненты. Теперь напишем свой. Создаёшь скрипт (Create -> C# Script), и Unity генерирует заготовку класса. Главное правило: класс наследует MonoBehaviour. Это базовый класс, который превращает обычный C#-класс в компонент Unity.

Второе правило, на котором спотыкаются все новички: имя файла = имя класса. Файл PlayerController.cs должен содержать class PlayerController. Если переименуешь файл, а класс нет — компонент не навесится.

Как работает под капотом

Когда ты добавляешь скрипт на GameObject, Unity создаёт экземпляр твоего класса и привязывает его к объекту. Дальше движок сам вызывает специальные методы в нужные моменты:

Ты создаёшь PlayerController.cs:

  class PlayerController : MonoBehaviour
  {
      void Start()  { ... }   -> Unity вызовет 1 раз в начале
      void Update() { ... }   -> Unity вызовет КАЖДЫЙ кадр
  }

Навесил на объект "Player" -> объект ожил.

Простейший скрипт выглядит так (C#):

using UnityEngine;

public class HelloWorld : MonoBehaviour
{
    void Start()
    {
        Debug.Log("Привет из игры! Объект: " + gameObject.name);
    }

    void Update()
    {
        // выполняется каждый кадр
    }
}

Debug.Log печатает сообщение в окно Console. Это твой главный инструмент отладки на старте: хочешь проверить, что код вообще выполняется — поставь Debug.Log.

Идею «движок дёргает мои методы» легко прочувствовать. Смоделируем мини-движок на Python, который вызывает методы «компонента»:

# Имитируем, как Unity вызывает Start один раз и Update каждый кадр
class PlayerController:
    def start(self):
        self.frame = 0
        print("Start: герой появился")

    def update(self):
        self.frame += 1
        print(f"Update: кадр {self.frame}")

# "движок" Unity
script = PlayerController()
script.start()                 # вызывается ОДИН раз
for _ in range(3):
    script.update()            # вызывается каждый кадр

Та же логика на Python ▶ — это и есть суть MonoBehaviour: ты пишешь методы, а движок решает, когда их звать. Ты не вызываешь Update сам — это делает Unity 60 раз в секунду.

Частые ошибки

  • Имя файла не совпадает с классом. Самая частая ошибка. Unity ругается «can't add script» — проверь, что имена идентичны.
  • Забыть унаследовать MonoBehaviour. Без него класс — обычный C#, его нельзя навесить на объект как компонент.
  • Вызывать Update вручную. Не надо. Update вызывает движок. Если зовёшь сам — логика выполнится дважды.

Best practices

  • Называй классы по их роли: PlayerMovement, EnemyAI, ScoreManager.
  • Удаляй пустые Update() — даже пустой метод движок вызывает каждый кадр, и на тысячах объектов это заметно.
  • Используй Debug.Log щедро, пока учишься, но убирай отладочные логи перед сборкой.

Итоги: скрипт становится компонентом, наследуя MonoBehaviour; имя файла обязано совпадать с именем класса. Ты пишешь методы (Start, Update), а движок сам вызывает их по расписанию. Debug.Log — твой главный друг при отладке.

Инверсия управления простыми словами

В привычных программах ты сам пишешь главный цикл и сам решаешь, что когда вызвать. В Unity всё наоборот: главный цикл — внутри движка, а ты лишь подкладываешь методы с правильными именами, и движок зовёт их в нужный момент. Это называется инверсией управления: не ты управляешь движком, а движок управляет твоим кодом. Поэтому методы Start и Update не нужно нигде «подключать» или регистрировать — достаточно правильно их назвать, и Unity сам их найдёт по имени и вызовет. Это поначалу непривычно, зато избавляет от тонн рутинного связующего кода: ты пишешь только саму логику поведения, а оркестрацию берёт на себя движок. Понимание этой инверсии — момент, после которого Unity перестаёт казаться магией.

Проверьте себя
1. Что превращает обычный C#-класс в компонент Unity?
AНаследование от MonoBehaviour
BСлово public
CМетод Main()
DИмпорт System
2. Какое требование к имени файла скрипта?
AТолько латиница
BИмя файла должно совпадать с именем класса
CФайл должен начинаться с цифры
DИмя не важно