0

In Unity, is it possible to automatically set a value when a ScriptableObject is created?

In the following example, I have a parent class, PickupData, and a child class, MoneyPickupData. Whenever an SO of the child class is created (via right-click in the Editor), I would like it to automatically set its type to EPickupType.Money.

I have tried using the Awake method, and I have also tried using the OnEnable method.

What I find is that when the SO is created, the value will be set to Money for a moment while I type in the name of the SO. But as soon as I press Enter and the SO finishes creating itself, the value gets reset to the first value in the enum.

How can I make it so that the value gets set to Money and does not reset?

Parent class

public class PickupData : ScriptableObject
{
    // The type of this pickup
    public EPickupType type;
}

Child class

public class MoneyPickupData : PickupData
{
    public void Awake()
    {
        // Set the type of this pickup
        type = EPickupType.Money;
    }
}
Ben
  • 15,938
  • 19
  • 92
  • 138

2 Answers2

1

The answer was sort of included in my question. The problem was the resetting. So I checked the Unity docs and found the Reset method:

Reset is called when the user hits the Reset button in the Inspector's context menu or when adding the component the first time.

This means that the change I make in Awake gets overridden by this automatic call to Reset.

The solution for me was to change Awake to Reset.

public class MoneyPickupData : PickupData
{
    // Reset is called when creating the SO in the Editor
    public void Reset()
    {
        // Set the type of this pickup
        type = EPickupType.Money;
    }
}
Ben
  • 15,938
  • 19
  • 92
  • 138
0

In such a case I would probably rather go for a property and do

public abstract class PickupData : ScriptableObject
{
    // The type of this pickup
    public abstract EPickupType type { get; }
}

and then

public class MoneyPickupData : PickupData
{
    // has to override this
    public override EPickupType type =>  EPickupType.Money;
}

so there is actually no way for any Inspector or runtime script to ever change this value.


If you really need to support both you could still do it like e.g.

public class PickupData : ScriptableObject
{
    [Tooltip("Default type selection, unless the type property is explicitly implemented")]
    [SerializeField] protected EPickupType _type;

    // The type of this pickup
    public virtual EPickupType type => _type;
}

public class MoneyPickupData : PickupData
{
    // doesn't need to override this but can
    public override EPickupType type =>  EPickupType.Money;
}

which would of course be slightly uncanny because it would still show up in the Inspector but your derived type could decide to ignore this and overrule the property with a fixed type.

derHugo
  • 83,094
  • 9
  • 75
  • 115