ack
ack

Reputation: 14985

Reference a class from a ScriptableObject

I have an EnemyData ScriptableObject that holds data about enemies. I'd like to have a field on EnemyData that references some logic about how this enemy behaves on its turn (in turn-based card game). My current attempt at this is to structure that as a ScriptableObject too, basically like this:

public class EnemyData : ScriptableObject
{
    public int health;
    public EnemyAIBase enemyAI;
}

public abstract class EnemyAIBase : ScriptableObject
{
    public abstract void PlayTurn(Enemy thisEnemy);
}

public class PirateShipAI : EnemyAIBase
{
    public override void PlayTurn(Enemy thisEnemy)
    {
        thisEnemy.Heal();
        AttackPlayer();
    }
}

So as an example, I've got a "PirateShip" asset of type EnemyData, whose enemyAI field points to a "PirateShipAI" asset of type PirateShipAI.

But this feels wrong, every time I code up a new enemy's AI I have to also instantiate an asset just so it can be referenced by an EnemyData. I feel like EnemyAIBase shouldn't even be an SO, it's not like it has any variables that different assets will override. There will be a 1-to-1 mapping between EnemyData assets and custom AI for that enemy. So this SO is just a container for some logic, which doesn't feel right. But I don't know any other way to reference that logic in my EnemyData SO.

I guess I wish an SO could reference a C# class directly, but I don't think this is possible.

One option is that I could build an Editor that hides the EnemyAI asset as a sub-asset of the EnemyData asset, kinda like I did over here: Building an Editor for nested ScriptableObjects to compose abilities in a card game

But that feels really wrong here, because I don't intend to make any of this AI generic.

How can I attach behavior/logic to a ScriptableObject?

Upvotes: 1

Views: 817

Answers (1)

derHugo
derHugo

Reputation: 90862

You can indeed simply make it not a ScriptableObject. To define different behaviors I would use a generic here:

public abstract class EnemyData<T> : ScriptableObject where T : EnemyAIBase
{
    public int health;
    public T enemyAI;
}

public abstract class EnemyAIBase
{
    public abstract void PlayTurn(Enemy thisEnemy);
}

And then from these create your actual implementations

[CreateAssetMenu]
public class PirateShip : EnemyData<PirateShipAI>{ }

public class PirateShipAI : EnemyAIBase
{
    public override void PlayTurn(Enemy thisEnemy)
    {
        thisEnemy.Heal();
        AttackPlayer();
    }
}

Upvotes: 2

Related Questions