Основы C# и жизненный цикл скрипта
- О чём эта тема
- Минимум языка C#, нужный для скриптов Unity: переменные, методы, условия — и главное: как устроен скрипт-наследник MonoBehaviour и в каком порядке движок вызывает его методы.
- Аннотация
- Конспект начинается с простейшей программы на C# и базовых конструкций языка: переменные и типы, неявные преобразования, методы с модификаторами доступа, перегрузка методов, условные операторы и логические операции. Затем пишется первый скрипт Unity: класс-наследник MonoBehaviour добавляется на объект сцены и выводит сообщение в консоль; код разбирается построчно. Завершающая часть — жизненный цикл скрипта: порядок вызова методов от Awake до OnDestroy, различие Update и FixedUpdate, пары OnEnable/OnDisable и OnCollision/OnTrigger; порядок закрепляется интерактивным симулятором.
- Пререквизиты
- Конспект A05: сцена, объекты, компоненты, добавление компонента через Add Component, вкладка «Консоль». Опыт программирования на любом языке полезен, но изложение его не предполагает.
- Мотивация
- Машина состояний противника из A02 уже была записана на C#: перечисление, метод Update, условия переходов. Тогда мы приняли на веру, что «Update вызывается каждый кадр». Пришло время разобраться, кто, когда и в каком порядке вызывает методы скрипта — без этого невозможно ответить даже на простой вопрос, почему счётчик в Update у одних игроков растёт быстрее, чем у других, а физика при этом ведёт себя одинаково.
1. Первая программа на C#
Прежде чем писать скрипты для движка, посмотрим на C# в чистом виде. Минимальная программа:
using System; public class MainClass { public static void Main() { Console.WriteLine("Unity это круто!"); } }
- using System; — позволяет использовать классы стандартной библиотеки без полного пути (System.Console.WriteLine → Console.WriteLine);
- class — все функции в C# находятся внутри классов;
- Main() — обязательный метод, с которого начинается выполнение программы;
- Console.WriteLine() — стандартный способ вывести текст в консоль;
- ; — конец инструкции для компилятора.
2. Переменные
Переменные хранят данные. Основные типы, с которых мы начнём:
- int year = 2025; — целое число в диапазоне от −2 147 483 648 до 2 147 483 647;
- float pi = 3.14f; — число с плавающей точкой (обратите внимание на суффикс f);
- string msg = "Hello!"; — строка в двойных кавычках.
Тип переменной должен соответствовать содержимому, но с оговоркой о преобразованиях. Целое число можно присвоить переменной типа float: 100 превратится в 100.0 без потери точности — это неявное преобразование. Обратное неявно не работает: у числа с плавающей точкой есть дробная часть, и при переводе в целое она была бы потеряна, поэтому компилятор требует явного указания.
using System; public class MainClass { public static void Main() { int year = 2025; float pi = 3.14f; Console.WriteLine(year); Console.WriteLine(pi); } }
3. Методы и модификаторы доступа
Метод — упрощённо — список действий, которые надо выполнить. В программировании не принято копировать один и тот же код, раздувая программу: повторяющиеся действия оформляются в метод, которому передаются разные данные.
public int Add(int a, int b) { return a + b; }
Разберём сигнатуру. public — модификатор доступа: метод доступен всем; парный ему private открывает доступ только внутри класса, где метод объявлен. int — тип возвращаемого значения. Add — имя метода: любые буквы, цифры и подчёркивание, первый символ — буква или подчёркивание, без пробелов и знаков пунктуации, не ключевое слово языка; хорошим тоном считается имя с большой буквы. В круглых скобках — аргументы; фигурные скобки — зона ответственности метода. return возвращает результат и завершает метод: команды после него не выполнятся.
Метод может ничего не возвращать — тогда вместо типа пишется void («пустота»), и переменную со значением такого метода объявить нельзя:
public void PrintMsg() { Console.WriteLine("Hello!"); }
3.1. Перегрузка методов
Перегрузка — использование одного имени метода с разными аргументами: другим их количеством или типом. Нужно сложить не два, а три числа — пишем метод с тем же именем и тремя аргументами; нужно сложить числа с плавающей точкой — с аргументами float:
public int Sum(int a, int b) { return a + b; } public int Sum(int a, int b, int c) { return a + b + c; } public float Sum(float a, float b) { return a + b; }
В классах Unity перегрузка используется постоянно. Убедиться легко: в редакторе кода щёлкните по интересующему методу с зажатой Ctrl — увидите все варианты перегрузки, например у методов класса GameObject.
4. Условия и логические операции
int a = 5; int b = 5; if (a > b) { Console.WriteLine("YES"); // a больше b } else if (a == b) { Console.WriteLine("EQUALS"); // a равно b } else { Console.WriteLine("NO"); // остаётся: a меньше b }
Условие в if — выражение типа bool: «правда» (true) или «ложь» (false). Если условие ложно, управление переходит к else if со своей проверкой, а затем к else — ветке «во всех остальных случаях». Три состояния сравнения двух чисел (больше, равно, меньше) покрываются ровно этой конструкцией.
Логические операции соединяют условия: && — «логическое И», истинно, только когда верны оба условия; || — «логическое ИЛИ», истинно, когда верно хотя бы одно.
5. Первый скрипт Unity
Подготовка окружения делается один раз: в Package Manager (Window → Package Manager, фильтр In Project) должен стоять пакет поддержки вашего редактора кода — если его нет, найдите его в Unity Registry и нажмите Install; затем в Edit → Preferences → External Tools выберите редактор в пункте External Script Editor.
Скрипт создаётся в панели «Проект» так же, как материал: Create → C# Script; назовём его HelloWorld. Двойной щелчок открывает редактор кода:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class HelloWorld : MonoBehaviour { // Start is called before the first frame update void Start() { Debug.Log("Hello World!"); } // Update is called once per frame void Update() { } }
Сохраняем (Ctrl+S) и добавляем скрипт на любой объект сцены — например, на шар из A05: выделить объект в иерархии → Add Component в инспекторе → в поиске набрать имя скрипта. Запускаем проект, открываем вкладку Console — там наше приветствие.
5.1. Разбор кода построчно
- using Название.Пространства.Имен — подключение пространства имён (библиотеки). Класс Debug и его метод Log доступны, потому что подключено пространство UnityEngine.
- public class HelloWorld : MonoBehaviour — объявление класса с модификатором доступа и наследованием от MonoBehaviour. От этого класса наследуются все скрипты Unity — благодаря этому в них работают базовые методы Start, Update, Awake и другие.
- // текст — комментарий: компилятор игнорирует всё после двойной косой черты до конца строки.
- void Start() — базовый метод MonoBehaviour: выполняется один раз при появлении объекта на сцене — поэтому сообщение в консоли появилось однократно.
- Debug.Log("Hello World!") — класс Debug, метод Log: принимает строку и выводит её в консоль.
- void Update() — выполняется каждый кадр; здесь он пуст, и его можно удалить.
Небольшое упражнение из материалов: перенесите Debug.Log из Start в Update, запустите игру и объясните, что изменилось. Ответ проверьте в симуляторе следующего раздела.
6. Жизненный цикл скрипта
В каждом скрипте-наследнике MonoBehaviour есть базовые методы, и Unity вызывает их в строго определённой последовательности. Самые востребованные — в порядке вызова:
- Awake — один раз при запуске приложения. Здесь кэшируют ссылки на компоненты того же объекта. Особенность: вызывается, даже если скрипт на объекте отключён.
- OnEnable — при каждом включении объекта (SetActive(true)).
- Start — один раз, после включения объекта и перед первым вызовом любого из Update-методов. Обычно здесь запускается игровой процесс; годится и для кэширования ссылок.
- FixedUpdate — строго определённое число раз в секунду (по умолчанию 50, настраивается); используется для расчётов физики.
- OnCollisionEnter / Stay / Exit — обработка физического столкновения объектов, по очереди; есть 2D-версии (OnCollisionEnter2D и т. д.).
- OnTriggerEnter / Stay / Exit — пересечение коллайдеров без дальнейшего расчёта физики (Is Trigger из A05); тоже с 2D-версиями.
- Update — каждый кадр: частота зависит от частоты кадров, в отличие от FixedUpdate. Типичное применение — считывание нажатий клавиш.
- LateUpdate — после FixedUpdate и Update; часто — расчёт положения камеры, следящей за игроком.
- OnDisable — противоположность OnEnable: при каждом выключении объекта (SetActive(false)).
- OnDestroy — один раз при уничтожении объекта.
Слева — методы скрипта, справа — журнал вызовов. Управляйте «приложением»: запустите его, прокрутите кадры, выключите и включите объект, уничтожьте его — и проследите, какие методы вызывает Unity. Проверьте особенность Awake: поставьте галочку «объект выключен при старте» и посмотрите, что вызовется всё равно.
Полная схема порядка выполнения (включая методы отрисовки и корутины) — в документации Unity:
Контрольные вопросы
-
Целое число превращается в число с плавающей точкой без потери точности (100 → 100.0). У float есть дробная часть, которая при переводе в int была бы отброшена, — такую потерю данных компилятор требует подтвердить явным преобразованием.
-
public открывает доступ к классу, методу или переменной всем; private — только внутри класса, где элемент объявлен.
-
Несколько методов с одним именем, но разными аргументами (по количеству или типам). Позволяет вызывать одно и то же действие для разных данных: Sum(int, int), Sum(int, int, int), Sum(float, float). В классах Unity перегрузка используется повсеместно.
-
Один знак — присваивание значения переменной; два знака — сравнение на равенство, возвращающее bool. В if и else if используется только сравнение.
-
Скрипт можно добавить на объект сцены как компонент, и Unity начинает вызывать его базовые методы жизненного цикла: Awake, OnEnable, Start, Update, FixedUpdate и другие.
-
Update вызывается каждый кадр — частота зависит от производительности; FixedUpdate — фиксированное число раз в секунду (по умолчанию 50). Физику и движение считают в FixedUpdate, чтение ввода — в Update.
-
Awake вызовется даже у объекта с отключённым скриптом — это его особенность. OnEnable и Start не вызовутся до включения объекта: OnEnable сработает при SetActive(true), Start — один раз перед первым Update после включения.
-
OnCollisionEnter/Stay/Exit обрабатывают физическое столкновение с расчётом физики; OnTriggerEnter/Stay/Exit — только факт пересечения коллайдеров, когда у коллайдера включён Is Trigger, без физической реакции. У обоих наборов есть 2D-версии.
Источники
- Order of execution for event functions // Unity Documentation : [сайт]. — URL: https://docs.unity3d.com/Manual/ExecutionOrder.html (дата обращения: 08.07.2026).
- MonoBehaviour // Unity Scripting API : [сайт]. — URL: https://docs.unity3d.com/ScriptReference/MonoBehaviour.html (дата обращения: 08.07.2026).
- Руководство по языку C# // Microsoft Learn : [сайт]. — URL: https://learn.microsoft.com/ru-ru/dotnet/csharp/ (дата обращения: 08.07.2026).