0

I have a base class called Weapon and several derived classes e.g. Weapon_Rifle, Weapon_Pistol etc.

In another class I need to reference whatever derived class of Weapon exists on the GameObject in question. In pseduocode what I'm trying to do is this:

public class OtherClass : MonoBehaviour
{

     public string weaponType;
     public SCRIPT_I_WANT_TO_REFERENCE;

     void Awake(){
          if(weaponType =="Rifle"){
               SCRIPT_I_WANT_TO_REFERENCE = GetComponent<Weapon_Rifle>();
          } else {
              SCRIPT_I_WANT_TO_REFERENCE = GetComponent<Weapon_Pistol>(); // etc etc
          }
     }

     void DoStuff(){
          SCRIPT_I_WANT_TO_REFERENCE.ShootWeapon();
     }
}

Trouble is of course I can't use a dummy type like Object for the SCRIPT_I_WANT_TO_REFERENCE as the compiler complains where I try to access methods of that script like ShootWeapon().

Any way this can be done?

Many thanks.

2 Answers 2

2

You could try using an interface. Something like IWeapon where you have ShootWeapon in it's definition.

interface IWeapon
{
    void ShootWeapon();
}

Then you would just implement the interface in the class definition's header.

public class Weapon_Rifle : MonoBehaviour, IWeapon
{
    void ShootWeapon()
    {
       ...
    }
}

That way you can refer to the Rifle with the interface in the "is a" relationship. Any other methods you need to access from both classes can also be defined, and then (must be) implemented in the classes. The type you can use is IWeapon to refer to both classes.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for that. Since IWeapon can't derive from Monobehaviour how would I use Weapon as a base class, since I need to use Monobehaviour methods? Would I have something like public class Weapon : MonoBehaviour, IWeapon and then the derived classes like , public class Weapon_Rifle: Weapon?
Actually in Unity a class can't derive from two other classes but you can implement as many interfaces as you like, along with deriving from MonoBehaviour. Both weapon classes would still inherit from MonoBehaviour in order to still be Components so they'd both be Weapon_X : MonoBehaviour, IWeapon. You can check out a good intro on interfaces at Unity's site here if you like.
Thank you, so I'll set up something like a state machine for weapon types
0

You can use reflection to do what you want:

var method = typeof(GameObject).GetMethod("GetComponent", new Type[] {});
var specific = method.MakeGenericMethod(typeof(Rifle));
var instance = specific.Invoke(shooter, null) as IWeapon;

eg.

using UnityEngine;
using System;
using System.Reflection;
using NUnit.Framework;

public interface IWeapon
{
    void ShootAt(GameObject target);
}

public class Rifle : MonoBehaviour, IWeapon
{
    public void ShootAt(GameObject target)
    {
        Debug.Log("Rifle");
    }
}

public class Shotgun : MonoBehaviour, IWeapon
{
    public void ShootAt(GameObject target)
    {
        Debug.Log("Shotgun");
    }
}

public class WeaponTests
{
    private GameObject Shooter()
    {
        var foo = new GameObject();
        foo.AddComponent<Shotgun>();
        foo.AddComponent<Rifle>();
        return foo;
    }

    private MethodInfo method = null;
    private IWeapon GetWeaponByName(GameObject shooter, string name)
    {
        if (method == null)
        {
            // This is slow, cache the result
            method = typeof(GameObject).GetMethod("GetComponent", new Type[] {});
        }
        if (name == "Rifle")
        {
            MethodInfo specific = method.MakeGenericMethod(typeof(Rifle));
            return specific.Invoke(shooter, null) as IWeapon;
        }
        else if (name == "Shotgun")
        {
            MethodInfo specific = method.MakeGenericMethod(typeof(Shotgun));
            return specific.Invoke(shooter, null) as IWeapon;
        }
        return null;
    }

    [Test]
    public void TestGetWeaponByName()
    {
        var target = new GameObject();
        var fixture = Shooter();
        IWeapon weapon;

        weapon = GetWeaponByName(fixture, "Rifle");
        Assert.True(weapon != null);
        weapon.ShootAt(target);

        weapon = GetWeaponByName(fixture, "Shotgun");
        Assert.True(weapon != null);
        weapon.ShootAt(target);

        weapon = GetWeaponByName(fixture, "Laster");
        Assert.True(weapon == null);
    }
}

Notice also there's no particular need for IWeapon. You could as easily directly load the specific instances:

MethodInfo specific = method.MakeGenericMethod(typeof(Rifle));
var rifle = specific.Invoke(shooter, null) as Rifle;
rifle.RifleSpecificThing();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.