reckfellENGINE

Префаб или создание из кода

Выбор способа сборки объекта и полный пример двух независимых экземпляров.

На этой странице

Что выбирать

ЗадачаПодход
Настроить визуальную и физическую иерархию, ссылки и значения в редактореПрефаб .rprefab
Создать простой объект или собрать структуру по данным во время игрыnew и AddChild
Описать правила и командыC#-класс или скрипт Entity
Хранить общие параметрыResource .rdata

Префаб и скрипт дополняют друг друга: префаб хранит композицию, скрипт задаёт поведение. Выбирайте по удобству настройки и изменения, а не по обещанию, что один способ всегда быстрее.

Запустить пример

Нужен C#-проект с Reckfell.NET.Sdk 1.0.0 и net10.0. Если проекта ещё нет, начните с настройки C#.

  1. Добавьте все пять файлов ниже в проект, сохранив имена файлов и классов.
  2. Выполните dotnet build в папке с .csproj.
  3. Создайте уровень с корневым Entity, прикрепите ArchitectureExample.cs и сохраните уровень как architecture.rscene.
  4. Запустите этот уровень и откройте вывод приложения.

Ожидаемая строка: First=75; Second=100. Оба объекта получили один ресурс настроек; урон изменил здоровье только первого. Пример затем удаляет созданные объекты. Это короткая проверка устройства системы, а не готовая игровая сцена.

HealthModel.cs
C#
using System;

public interface IDamageable
{
    bool TryApplyDamage(int amount);
}

public sealed class HealthModel : IDamageable
{
    public int Maximum { get; }
    public int Current { get; private set; }

    public HealthModel(int maximum)
    {
        if (maximum <= 0) throw new ArgumentOutOfRangeException(nameof(maximum));
        Maximum = maximum;
        Current = maximum;
    }

    public bool TryApplyDamage(int amount)
    {
        if (amount <= 0 || Current == 0) return false;
        Current = amount >= Current ? 0 : Current - amount;
        return true;
    }
}
ActorSettings.cs
C#
using Reckfell;

[GlobalClass]
public partial class ActorSettings : Resource
{
    [Export(PropertyHint.Range, "1,10000,1")]
    public int MaximumHealth { get; set; } = 100;
}
DamageReceiver.cs
C#
using Reckfell;

public partial class DamageReceiver : Entity, IDamageable
{
    [Export] public ActorSettings? Settings { get; set; }
    [Signal] public delegate void HealthChangedEventHandler(int current, int maximum);

    private HealthModel? _health;
    public int CurrentHealth => _health?.Current ?? 0;
    public int MaximumHealth => _health?.Maximum ?? 0;

    public override void _Ready() => ResetFromSettings();

    public bool ResetFromSettings()
    {
        if (Settings is null || !ReckfellObject.IsInstanceValid(Settings) ||
            Settings.MaximumHealth <= 0) return false;
        _health = new HealthModel(Settings.MaximumHealth);
        EmitSignal(SignalName.HealthChanged, _health.Current, _health.Maximum);
        return true;
    }

    public bool TryApplyDamage(int amount)
    {
        if (_health is null || !_health.TryApplyDamage(amount)) return false;
        EmitSignal(SignalName.HealthChanged, _health.Current, _health.Maximum);
        return true;
    }
}
HitController.cs
C#
using Reckfell;

public partial class HitController : Entity
{
    private IDamageable? _target;

    public void SetTarget(IDamageable? target) => _target = target;

    public bool TryHit(int amount)
    {
        if (_target is ReckfellObject native && !ReckfellObject.IsInstanceValid(native))
        {
            _target = null;
            return false;
        }
        if (_target is Entity entity && entity.IsQueuedForDeletion()) return false;
        return _target?.TryApplyDamage(amount) ?? false;
    }

    public override void _ExitTree() => _target = null;
}
ArchitectureExample.cs
C#
using Reckfell;

public partial class ArchitectureExample : Entity
{
    public string Summary { get; private set; } = "";

    public override void _Ready()
    {
        using var settings = new ActorSettings { MaximumHealth = 100 };
        var first = new DamageReceiver { Name = "First", Settings = settings };
        var second = new DamageReceiver { Name = "Second", Settings = settings };
        var hits = new HitController();
        AddChild(first);
        AddChild(second);
        AddChild(hits);
        hits.SetTarget(first);
        hits.TryHit(25);
        Summary = $"First={first.CurrentHealth}; Second={second.CurrentHealth}";
        ReckfellApi.Print(Summary);

        hits.SetTarget(null);
        hits.Free();
        first.Free();
        second.Free();
    }
}

Перенести объект в префаб

Для авторского префаба создайте корневой Entity со скриптом DamageReceiver, назначьте ActorSettings в Settings и добавьте нужные дочерние объекты. Сохраните композицию как .rprefab. Код создания экземпляра использует PackedEntity.Instantiate; new DamageReceiver создаёт только класс, без сохранённых дочерних объектов и настроек префаба.

При программном Pack дочерний объект должен принадлежать сохраняемой композиции через Owner. Один AddChild этого не задаёт. В примере проверки сохранение и повторная загрузка .rprefab восстанавливают Settings и принадлежащего корню ребёнка.

Текущее здоровье хранится в обычном HealthModel и не экспортируется: новый экземпляр получает начальное здоровье из Settings при _Ready. Сохранение прогресса игрока — отдельная операция, а не побочный эффект сохранения префаба.

Если вывод не появился: проверьте успешную сборку, прикреплённый ArchitectureExample.cs и запущенный уровень. Если здоровье равно нулю в своём получателе, проверьте Settings и результат ResetFromSettings.

Привязка зависимостей · Сохранение прогресса

Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.