Classes, Entity, Resource and prefabs: the difference
How a C# type, an engine instance, configuration data and a saved hierarchy relate.
Four different concepts
| Concept | Meaning | Example |
|---|---|---|
| C# class | A type with fields and methods; inheritance is defined in C# | HealthModel, DamageReceiver |
| Entity | A hierarchy object with a parent, children and lifecycle | A DamageReceiver instance |
| Resource | Engine data that can be saved and shared between objects | ActorSettings |
| .rprefab prefab | A saved composition of entities, properties and references | An enemy template |
A C# script really declares a C# class. The engine also represents the script file as a Script resource; that is a different layer. A plain HealthModel does not inherit ReckfellObject, cannot be added with AddChild and receives no _Ready callback.
Inheritance and composition
DamageReceiver inherits Entity and implements IDamageable. Its HealthModel is a separate object containing health rules. ActorSettings supplies initial parameters. Two receivers can reference one ActorSettings while owning different HealthModel instances.
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;
}
}ActorSettings.cs
using Reckfell;
[GlobalClass]
public partial class ActorSettings : Resource
{
[Export(PropertyHint.Range, "1,10000,1")]
public int MaximumHealth { get; set; } = 100;
}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;
}
}What a prefab changes
PackedEntity.Instantiate creates a hierarchy from stored data. It does not declare a new CLR type: the root script type remains DamageReceiver. .rscene denotes a level and .rprefab a reusable object; both use PackedEntity. These are file roles rather than two Entity subclasses.
Parent determines hierarchy and child deletion. Owner determines membership in the saved composition; it does not identify a gameplay score owner, team or network owner.