Best way to find appropriate script for random enemy?

Okay, so I’m making a card game-- and the way that it’s set up, currently, is that when I want to create a card, the call goes to the card manager with an id-- this id being the specific card in question. The card is fetched (the data, I should say) and the prefab is created. This is nice because I can just supply a random id and it will give me a random card. The problem I’ve run into is (theoretically) initializing these cards as enemies.

When the object is created, sometimes I’ll know which card I’m calling (and therefore, which specific class it should be-- ie. Arcanist, Fire Mage, etc) and sometimes I won’t. I’ve had to settle with the less-than-ideal situation of using GetComponent(“scriptname”) to add the appropriate script behavior, but I don’t like the idea of GetComponent having to do a string search, as I feel like this call could get costly (I also don’t like the idea of having a million unique scripts per unique enemy, but I don’t see a way around that). Is there a more efficient, or more OOP to do this? Should I even attach a component?

The idea behind attaching a component with the specific class script was so that I could have a parent class, EnemyAI, run virtual methods like OnHit(), or PostTurnEffect() and then override child methods could be called instead (so that each enemy exhibits specific behavior) but I’m starting to question whether that’s the best way to go about it.

Any ideas? Surely this has been done before?

It sounds like components are a good idea for what you’re doing, so I’d stick with them.

If you don’t know the component ahead of time, you’re always going to need some kind of lookup. String lookups are fragile though; typos and the like can easily break them.

Consider using a C# interface, something like:

public interface IEnemyAI {
    void OnHit();
    void PostTurnEffect(); ...

And make each component an implementation of this interface:

public class Arcanist : MonoBehaviour, IEnemyAI {
    public void OnHit() {...}
    public void PostTurnEffect() {...}

If you want to inherit reusable code, you can always use inheritance, too:

public abstract class BasicEnemy : MonoBehaviour, IEnemyAI {
    public virtual void OnHit() {...}
    public virtual void PostTurnEffect() {...}

public class FireMage : BasicEnemy {
    public override void OnHit() {

When you get a prefab instance, you can store a reference to the interface:

GameObject enemyObject = CardManager.GetCard(i);
IEnemyAI enemyAI = enemyObject.GetComponent(typeof(IEnemyAI)) as IEnemyAI;
enemyAI.OnHit(); // Enemy was just hit.

You can still put them in a pool like @ShadoX suggests. It sounds like your card manager already basically does this. Once you pull them out of a pool, you can use the method above to access the component.