Unity游戏引擎:获取对动态添加的脚本

时间:2016-04-03 11:18:53

标签: c# dynamic unity3d reference

我有一个名为Weapon的基类和几个派生类,例如Weapon_Rifle,Weapon_Pistol等。

在另一个类中,我需要引用游戏对象中存在的任何派生类武器。在pseduocode中,我想要做的是:

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

麻烦当然是我不能为SCRIPT_I_WANT_TO_REFERENCE使用像Object这样的虚拟类型,因为编译器抱怨我尝试访问该脚本的方法,如ShootWeapon()。

任何方式都可以做到这一点?

非常感谢。

2 个答案:

答案 0 :(得分:2)

您可以尝试使用界面。像IWeapon这样的东西,你的定义就是ShootWeapon。

interface IWeapon
{
    void ShootWeapon();
}

然后,您只需在类定义的标题中实现该接口。

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

这样你就可以在“是一种”关系中引用具有界面的步枪。您还需要定义从两个类访问的任何其他方法,然后(必须)在类中实现。你可以使用的类型是IWeapon来引用这两个类。

答案 1 :(得分:0)

您可以使用反射来做您想做的事情:

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

例如

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

请注意,IWeapon并不特别需要。您可以轻松地直接加载特定实例:

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