简体   繁体   English

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

[英]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. 我有一个名为Weapon的基类和一些派生类,例如Weapon_Rifle,Weapon_Pistol等。

In another class I need to reference whatever derived class of Weapon exists on the GameObject in question. 在另一类中,我需要引用有问题的GameObject上存在的任何武器衍生类。 In pseduocode what I'm trying to do is this: 在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();
     }
}

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(). 麻烦当然是我不能将像Object这样的伪类型用于SCRIPT_I_WANT_TO_REFERENCE,因为编译器抱怨我试图在何处访问该脚本方法(如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. 像IWeapon这样的东西,在其中定义了ShootWeapon。

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. 您可以使用的类型是IWeapon来引用这两个类。

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 . 还请注意,不需要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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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