reckfellENGINE

Prefab or construction from code

Choose how to assemble an object and run a complete example with two independent instances.

On this page

Choose by task

TaskApproach
Author visual/physics hierarchy, references and values in the editor.rprefab prefab
Create a simple object or assemble runtime data-driven structurenew and AddChild
Define rules and commandsA 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.

  1. Add all five files below, preserving file and class names.
  2. Run dotnet build in the directory containing the .csproj.
  3. Create a level with an Entity root, attach ArchitectureExample.cs and save it as architecture.rscene.
  4. 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
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();
    }
}

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.

Supply dependencies · Save progress

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.