Скрипты C#
Первый скрипт, сборка, жизненный цикл, пути и проверка ссылок после удаления.
Нужен Cube типа MeshInstance3D из создания проекта.
1. Создайте и прикрепите скрипт
- Остановите игру через F8 и выберите
CubeтипаMeshInstance3Dв локальной иерархии. - Нажмите кнопку прикрепления скрипта. Выберите C#, базовый класс
Entity3Dи путьasset://Scripts/Rotator.cs. Создайте папкуScripts, если её ещё нет. - Если редактор предлагает создать решение C#, подтвердите. Оно нужно для сборки кода проекта.
- Откройте
Rotator.csв редакторе кода. Полностью замените содержимое примером ниже и сохраните файл.
Имя файла и имя класса должны совпадать: Rotator.cs и Rotator. Скрипт должен быть прикреплён к кубу, а не просто лежать в Assets. MeshInstance3D наследует Entity3D, поэтому выбранный базовый класс подходит.
Если файл не открывается автоматически, найдите Scripts/Rotator.cs в папке проекта и откройте установленным текстовым редактором. Для первого примера достаточно редактора, который сохраняет обычный текст с расширением .cs, без добавления .txt. Сборку всё равно выполняет Reckfell.
2. Полный скрипт
using Reckfell;
public partial class Rotator : Entity3D
{
[Export] public float DegreesPerSecond { get; set; } = 45.0f;
public override void _Ready()
{
ReckfellApi.Print("Rotator ready");
}
public override void _Process(double delta)
{
float angle = Mathf.DegToRad(DegreesPerSecond) * (float)delta;
RotateY(angle);
}
}3. Соберите и запустите
В редакторе выберите Build Project / Собрать проект в инструментах C#; стандартная комбинация — Alt + B. Дождитесь завершения без ошибок. Сохраните документ и нажмите F6.
Ожидаемый результат: куб вращается вокруг вертикальной оси, а в Output появляется Rotator ready. Если он остаётся неподвижным, проверьте, что последняя сборка завершилась успешно и скрипт прикреплён именно к видимому кубу.
Как читать этот код
| Запись | Простое объяснение |
|---|---|
using Reckfell; | Позволяет использовать типы движка без полного имени перед каждым типом |
class Rotator : Entity3D | Описывает поведение объекта на основе Entity3D |
partial | Позволяет генератору движка дополнить класс необходимой служебной частью |
float | Число с дробной частью; суффикс f в 45.0f задаёт этот тип |
[Export] | Делает свойство доступным в инспекторе после сборки |
_Ready() | Выполняется при готовности объекта и его детей |
_Process(double delta) | Выполняется каждый отображаемый кадр |
RotateY(angle) | Поворачивает объект вокруг оси Y на угол в радианах |
Фигурные скобки { } объединяют инструкции. Точка с запятой ; завершает отдельную инструкцию. public позволяет обращаться к члену класса извне, void означает, что метод не возвращает значение, а override заменяет обработчик, предусмотренный базовым классом.
Зачем нужна delta
DegreesPerSecond задаёт скорость за секунду, а delta — сколько секунд прошло с предыдущего кадра. Их произведение даёт изменение за один кадр. При скорости 45 за две секунды объект повернётся примерно на 90 градусов независимо от обычных колебаний частоты кадров.
Инспектор показывает градусы, но RotateY() принимает радианы. Mathf.DegToRad() переводит одно в другое. Если убрать умножение на delta, получится поворот на заданный угол каждый кадр: скорость станет зависеть от FPS.
Измените скорость без правки кода
Остановите игру, выберите куб и найдите свойство Degrees Per Second в инспекторе скрипта. Поставьте 90, сохраните и запустите: вращение станет вдвое быстрее. Значение -45 меняет направление, 0 останавливает вращение.
Значение в инспекторе сохраняется отдельно от начального значения в C#. Если оно уже переопределено, изменение 45.0f в тексте скрипта может не заменить значение, сохранённое у объекта.
Когда выполняется код
| Метод | Когда нужен |
|---|---|
_EnterTree() | При каждом добавлении в работающую иерархию; подключайте подписки, действующие только внутри уровня |
_Ready() | Когда готовы дочерние объекты; получайте ссылки и задавайте начальное состояние |
_Process(double delta) | Каждый отображаемый кадр; анимация интерфейса и визуальные изменения |
_PhysicsProcess(double delta) | На физическом шаге; движение физического тела и работа со столкновениями |
_ExitTree() | При выходе из иерархии; отключайте подписки на объекты, которые продолжают жить |
Родитель входит в дерево раньше детей, а _Ready() детей выполняется раньше _Ready() родителя. Поэтому в _Ready() удобно связывать уже подготовленные дочерние компоненты. Конструктор C# не означает, что объект уже находится в уровне: не получайте там GetTree() или игровые дочерние объекты.
_Ready() обычно вызывается один раз за жизнь экземпляра. Если тот же объект убрать через RemoveChild() и вернуть через AddChild(), снова выполнятся _EnterTree() и _ExitTree(), но не _Ready(). Если повторная подготовка действительно нужна, вызовите RequestReady() до следующего добавления. Запрос относится к этому объекту, а не ко всем его детям.
Для персонажа используйте _PhysicsProcess() из урока движения. Не переносите туда любой код только ради стабильной частоты: вращение декоративного куба не требует физического шага.
Ссылки на объекты и пути
GetEntity<T>("Child") ищет объект относительно того, на котором выполняется скрипт. Имя и регистр должны совпадать с иерархией. Это не путь к файлу: asset://Props/Crate.rprefab загружается через ResourceLoader, а экземпляр создаётся отдельно. См. создание объектов.
Когда отсутствие дочернего объекта допустимо, используйте GetEntityOrNull<T>() и проверяйте результат. Когда объект обязателен, исправьте структуру уровня: молчаливый пропуск ошибки оставит компонент неработающим.
После QueueFree() native-объект удаляется в конце кадра. C#-переменная сама не становится null. Для сохранённой ссылки проверяйте ReckfellObject.IsInstanceValid(reference), а чтобы не обращаться к уже запланированному на удаление объекту — также reference.IsQueuedForDeletion(). Это особенно важно после await или смены уровня.
Если результат отличается от примера
| Симптом | Что проверить сначала |
|---|---|
| Изменения кода не появились | Сохраните файл и дождитесь успешного Build Project; работающая старая сборка не подтверждает новую |
Rotator ready не появляется | Скрипт прикреплён к кубу, класс называется Rotator, содержит partial, сборка без ошибок |
| Скорость в коде другая, но куб вращается по-старому | Смотрите сохранённое значение Degrees Per Second в инспекторе |
_Ready() не повторяется после возврата объекта | Это тот же экземпляр; для каждого входа используйте _EnterTree() |
NullReferenceException / ошибка поиска дочернего объекта | Сверьте имя, регистр, тип и относительный путь; найдите первую строку своего скрипта в стеке |
| Ошибка обращения после удаления | Проверяйте действительность native-объекта, а не только reference != null |
SDK и сборка из командной строки
Поставка содержит .NET 10 и пакет Reckfell.NET.Sdk/1.0.0.
Сгенерированный .csproj использует такую основу:
<Project Sdk="Reckfell.NET.Sdk/1.0.0">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>
</Project>Для сборки из папки проекта выполните dotnet build через dotnet.exe из поставки. Требуются локальные пакеты Reckfell. После обновления SDK пересоберите проект.
Ошибки сборки и прикрепления скрипта: решение проблем.
Инструменты кода
Подсказки Roslyn, поиск использований и отладка описаны во встроенной IDE. Логику можно также создавать в SharpGraph и преобразовывать в отдельные редактируемые файлы C#.