Reputation: 14985
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
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