Skip to content

Customizing Entities

This guide takes you through customizing an Entity by extending or overriding the functionality it provides. If you aren't familiar with the Entity system, refer to the Entities page before continuing.

This example shows how to add functionality to an existing Entity.

Entities within IdleKit are easy to extend or override, so it is simple to implement custom functionality. An example of customization is to create a IGeneratorEntity?text=Generator, which automatically upgrades to level 1 on purchase.

To help understand what's involved in customizing an Entity, we will look at a simple extension of an Upgradeable Currency to create an IEquippableUpgradeableCurrency. This type of Upgradeable Currency operates just like a regular Upgradeable Currency, with the only difference being that for the currency's Modifier Datas to apply to IModifiables the currency has to be equipped by the player.

Tip

You can find a full implementation of the EquippableUpgradeableCurrency in the idlekit-showcase repository in the Assets/Samples folder. Please look at the code directly as a complement to this guide.

Controller

The Controller is the class that encapsulates the logic and functionality of an Entity.

In the case of the EquippableUpgradeableCurrency we are extending the Upgradeable Currency Controller" and implementing a simple new interface IEquippable, so the EquippableUpgradeableCurrency can perform logic to Equip and Un-equip the currency.

The main functionality of this example is the IEquippable.Equip(bool) method in the following code. The UI would call this method on an IEquippableUpgradeableCurrency when the player wants to Equip/Un-equip the currency.

public virtual void Equip(bool equip)
{
     CurrencyEquippedModifierAction equippedAction = _actionService.Get<CurrencyEquippedModifierAction>();
     equippedAction.Initialize(this, equip);
     _actionService.Dispatch(equippedAction, this);
}

Note

The modifying of Saved Data should always be performed from an IStateAction. It's for this reason that the CurrencyEquippedModifierAction is implemented within the EquippableUpgradeableCurrency example and implements the IStateAction.

Static Data

The Entity Static Data is responsible for the storage of any non-changing data used by the Entity. Static Data is the definition data for the Entity, which IdleKit uses to generate a default instance of an Entity. A designer typically creates this data. An example could include data such as the UnitTargetData for the different levels of a Generator.

In the following code, the EquippableUpgradeableCurrencyData extends the UpgradeableCurrencyData by adding a _isEquippedByDefault field, which determines whether this currency starts as equipped when obtained. A designer can adjust this field in the inspector.

[Serializable]
public class EquippableUpgradeableCurrencyData : UpgradeableCurrencyData, IEquippableUpgradeableCurrencyData
{
     [SerializeField]
     protected bool _isEquippedByDefault;

     public virtual bool isEquippedByDefault => _isEquippedByDefault;

Note

The Static Data is different from the Saved Data. Static Data doesn't change at runtime, unlike the Saved Data, which can change and store data between sessions.

Creation via Static Data

As well as being responsible for holding non-changing data, the Entity Static Data is also responsible for creating the Entity itself (i.e. the Controller and its Saved Data). Entity creation happens via each Entity's CreateEntity method.

In the following code, we can see that this method is responsible for creating an Entity instance.

public override IEntity CreateEntity()
{
    return new EquippableUpgradeableCurrency(Id);
}

Dependencies for Entities are resolved via the Resolver inside each Entity's Inject(IResolver resolver) method. This method also exists inside the EquippableUpgradeableCurrency.

public override void Inject(IResolver resolver)
{
      base.Inject(resolver);

      _equippableUpgradeableCurrencyData = resolver.Resolve<IEquippableUpgradeableCurrencyData>(Id);
      _equippableUpgradeableCurrencySavedData = resolver.Resolve<IEquippableUpgradeableCurrencySavedData>(Id);
}

Data Asset

The Data Asset for an Entity is the ScriptableObject from which the Entity's Static Data is loaded. This asset is generated when static data is imported.

In the following code, the EquippableUpgradeableCurrencyDataAsset extends ScriptableObjectBaseData and implements IEquippableUpgradeableCurrencyDataAsset.

/// <summary>
/// The asset that contains the <see cref="IEquippableUpgradeableCurrencyData"/>
/// </summary>
///
[CreateAssetMenu(menuName = "IdleKit Examples/Equippable Upgradeable Currency")]
[GuidReferenceable(typeof(EquippableUpgradeableCurrencyData))]
public class EquippableUpgradeableCurrencyDataAsset : ScriptableObjectBaseData<IEquippableUpgradeableCurrencyData, EquippableUpgradeableCurrencyData>, IEquippableUpgradeableCurrencyDataAsset
{

You can see how we tag the Data Asset as being GuidReferenceable. This tag dictates the types displayed in the Unity Inspector when the GuidReference tag exists on a SerializableField in the Entities Static Data.

Note

The Data Asset must inherit from the base DataAsset interface type (and not a derived concrete type) to benefit from IdleKit's heavy use of polymorphism fully.

Saved Data

An Entity's Saved Data holds data that is changed during runtime. The Saved Data is serialized and deserialized on save and load.

In the case of the EquippableUpgradeableCurrencySavedData, the following data extends what is held in the base implementation and adds a property and a method to save/adjust the currency's equipped state.

[SerializeField]
private bool _isEquipped;
public virtual bool isEquipped => _isEquipped;

protected EquippableUpgradeableCurrencySavedData()
{
    // Empty
}
In the following code, you can see how the EquippableUpgradeableCurrencySavedData overrides the BaseSavedData.Deserialize(out ISavedData savedData) method to allow for deserialization of data specific to our IEquippableUpgradeableSavedData.

protected override bool Deserialize(out ISavedData savedData)
{
    EquippableUpgradeableCurrencySavedData deserialized = new EquippableUpgradeableCurrencySavedData();

    bool status = _serializer.Deserialize(_savedId, ref deserialized);
    if (status)
    {
        _amount = deserialized.Amount;
        _upgradeLevel = deserialized.UpgradeLevel;
        _available = deserialized.Available;
        _obtained = deserialized.Obtained;
        _isEquipped = deserialized.isEquipped;
    }

    savedData = deserialized;
    return status;
}
After implementing the Controller (EquippableUpgradeableCurrency), the Static Data (EquippableUpgradeableCurrencyData), the Saved Data (EquippableUpgradeableCurrencySavedData) and the Action which modifies the state of the Entity (CurrencyEquippedModifierAction) we now have a version of Currency that includes brand new functionality, demonstrating the ease of extension which IdleKit provides. Please refer to the code in the IdleKit-Showcase repository under Samples/EquippableUpgradeableCurrency and in the EquippableCurrency scene for more information.