Настройки, состояние и коллекции
Разделяйте общие параметры и изменяемое состояние экземпляров.
Где хранить значение
| Значение | Место |
|---|---|
| Максимальное здоровье типа противника | ActorSettings, возможно общий Resource |
| Текущее здоровье конкретного противника | Отдельный HealthModel внутри получателя |
| Порядок предметов, локальный расчёт | .NET-массив или List по задаче |
| Поиск записи по ключу в C# | Dictionary с выбранным типом ключа |
| Коллекция на границе Export/Variant | Поддерживаемая движковая коллекция |
| Прогресс после выхода из приложения | Явная схема сохранения в user:// |
Наличие слова Array в имени не делает .NET-массив, List и Reckfell.Collections.Array взаимозаменяемыми. Выбор должен учитывать границу API, порядок, поиск и копирование. Подробные варианты приведены в коллекциях C#.
Один ресурс, два состояния
ActorSettings.cs
using Reckfell;
[GlobalClass]
public partial class ActorSettings : Resource
{
[Export(PropertyHint.Range, "1,10000,1")]
public int MaximumHealth { get; set; } = 100;
}HealthModel.cs
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;
}
}DamageReceiver.cs
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;
}
}ResetFromSettings копирует MaximumHealth в новую модель. После этого изменение общего ресурса не меняет уже созданные модели. Явный повторный ResetFromSettings создаёт новое полное здоровье — это команда сброса, а не незаметное обновление максимума.
Если новое значение некорректно, ResetFromSettings возвращает false и сохраняет прежнее здоровье. Range в Inspector — подсказка редактора; код всё равно проверяет значение.
Что именно копировать и сохранять
Передача Resource по ссылке разделяет данные. Новый HealthModel создаёт отдельное состояние. Дублирование контейнера не следует считать гарантированным клонированием всех вложенных ресурсов.
PackedEntity в этом примере сохраняет экспортированный Settings, но не обычное поле _health. После создания из префаба _Ready создаёт модель заново. Для сохранения текущего здоровья нужна отдельная запись данных и проверка при загрузке.