Any way to 'GetComponent' as a base class?

Let's say I have a base class like 'animal' and 3 subclasess like 'dog', 'cat', 'bird' Let's say the base has a function 'speak' that all 3 subclasses implement (bark, meow, chirp).

Then these get added to prefabs.

Now, I'd like to have a script be able to access the script component and call 'speak' and whatever the subclass happens to be, it will make the corresponding sound. Follow?

So, can I just call gameObj.GetComponent(Animal).speak() ?? I would think Unity expects the exact class name (subclass), or GetComponent will fail.

2 Answers

2

In short I believe it (`gameObj.GetComponent(Animal).speak()`) should work, but it may not work with the non-typed versions of GetComponent like that. Here's what I've done that seems to work.

I've got a Component Damageable that extends Monobehaviour. From that I have 2 components that extend from Damageable. DroneHealth and ShipHealth.

DroneHealth and ShipHealth are attached to prefabs. In my collision test code I do

Damageable damagable = gotHit.transform.parent.GetComponent<Damageable>();

To get the component (the DroneHeralth or ShipHealth component that is, I never attach the Damageable component to anything).

I then call applyDamage, which has the signature `public virtual void applyDamage(float amount, NetworkPlayer fromPlayer)` in Damageable (and is overridden in the child classes) via RPC and the correct override in the subclass gets called (I was suprised this worked by RPC when I tested it, but it does. If it works that way I'm pretty sure it'll work for local calls).

Bare bones versions of the components

using UnityEngine;
using System.Collections;

public class Damageable : MonoBehaviour
{

    private float inVulnDuration = 0.0f;
    private float inVulnStart = 0.0f;

    protected bool damagable = true;
    public bool Damagable
    {
        get { return damagable; }
    }

    protected virtual void Update()
    {
        // if invulnerable 
        if (!damagable)
        {
            //check and see if we should become damageable yet
            if ((inVulnStart + inVulnDuration) < Time.timeSinceLevelLoad)
            {
                damagable = true;
            }
        }
    }

    [RPC]
    public virtual void applyDamage(float amount, NetworkPlayer fromPlayer)
    {
        Debug.Log(": " + "applyDamage in Damagable ");
    }
}

using UnityEngine;
using System.Collections;

public class ShipHealth : Damageable
{
    protected override void Update()
    {
        base.Update();
        // if invulnerable 
        if (!damagable)
        {
            // code to make ship blink when invulnerable
        }
    }

    [RPC]
    public override void applyDamage(float amount, NetworkPlayer fromPlayer)
    {
            Debug.Log(": " +"applyDamage in shipHelath");
    }
}

That's just what I needed, thanks!

Although this answer was really helpful, it confused me a bit because of the RPC stuff which is not needed (as said but... well. I'm lost sometimes). All you need to do is: gameObject.GetComponent<BaseClassName>(); Thanks anyway. :)

Sounds like you should be using SendMessage.

gameObj.SendMessage("Speak");

In that case it doesn't matter what the component is called.

That may work, but my example above was simplified, I often need to set several variables, and SendMessage can have only one param, correct? Any idea if you can send a structure as that param?

Actually, BroadcastMessage worked better for me. For some reason, even though objects using the SAME prefab, some got the message, some didn't, seems like a bug.

SendMessage() is supposed to work only on the specified GameObject and its components, not any children or components connected to them; use BroadcastMessage to send a message to all children

@DaveA: yes, you can make a class with several elements and send that.

Good to know, thanks