简体   繁体   中英

Unity game engine: get reference to dynamically added script

I have a base class called Weapon and several derived classes eg 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.

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.

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();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM