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
}
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;
}
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.