Prefab or construction from code
Choose how to assemble an object and run a complete example with two independent instances.
Choose by task
| Task | Approach |
|---|---|
| Author visual/physics hierarchy, references and values in the editor | .rprefab prefab |
| Create a simple object or assemble runtime data-driven structure | new and AddChild |
| Define rules and commands | A C# class or Entity script |
| Store shared parameters | .rdata Resource |
A prefab and script complement each other: the prefab stores composition, while the script defines behavior. Choose for authoring and maintenance rather than assuming either approach is always faster.
Run the example
Use a C# project with Reckfell.NET.Sdk 1.0.0 and net10.0. If you do not have one, start with C# setup.
- Add all five files below, preserving file and class names.
- Run dotnet build in the directory containing the .csproj.
- Create a level with an Entity root, attach ArchitectureExample.cs and save it as architecture.rscene.
- Run that level and open the application output.
Expected output: First=75; Second=100. Both objects received the same settings resource; damage changed only the first receiver. The example then deletes its created objects. This is a short architecture check rather than a finished gameplay scene.
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;
}
}HitController.cs
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
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();
}
}Move the object into a prefab
For an authored prefab, create an Entity root with DamageReceiver, assign ActorSettings to Settings and add the required children. Save the composition as .rprefab. Instance creation uses PackedEntity.Instantiate; new DamageReceiver creates only the class, without the prefab's saved children and settings.
When using Pack in code, a child must belong to the saved composition through Owner. AddChild alone does not assign that membership. The verification example saves and reloads a .rprefab, restoring Settings and the child owned by its root.
Current health belongs to a plain HealthModel and is not exported: a fresh instance initializes health from Settings in _Ready. Saving player progress is a separate operation rather than a side effect of saving a prefab.
If output is missing, check the successful build, attached ArchitectureExample.cs and running level. If your receiver's health stays zero, check Settings and the ResetFromSettings result.