使用字符串 Unity 从游戏对象获取脚本

Posted

技术标签:

【中文标题】使用字符串 Unity 从游戏对象获取脚本【英文标题】:Getting a script from a gameobject using a string Unity 【发布时间】:2021-12-10 10:40:17 【问题描述】:

我正在为我的 FPS 游戏开发一个简单的武器控制器,但在尝试使其动态化时遇到了问题。当玩家拿起武器时,我希望将武器统计和效果设置为默认值。为此,每个武器都有一个脚本

weapon.name + "Stats"

但我在引用所述脚本时遇到问题。现在,这就是我的代码的样子:

string weaponScriptName = weapon.name + "Stats";
weapon.GetComponent<weaponScriptName>().UseWeapon();

其中weapon 代表当前装备武​​器的gameobject。显然,这不起作用,我在 Unity 帮助页面上找到的各种实现只会导致更多错误。我该怎么做才能解决这个问题?

谢谢。

【问题讨论】:

尽可能不要使用字符串...使用例如用于决定预定义类型的枚举开关.. 字符串总是容易出错且速度慢! @derHugo 抱歉,我对 Unity 很陌生。我将如何实现它? 【参考方案1】:

GetComponent 有多个重载。

有你指的generic版本——最常用的一个

T GetComponent<T>()

只能与编译时常量类型参数一起使用,例如

var renderer = GetComponent<Renderer>();

有一个使用动态Type

 Component GetComponent (Type type)

喜欢

 // Just an example, there are many ways of getting a type
 var type = typeof(Renderer);
 var renderer = (Renderer) GetComponent(type);

最后还有一个string

Component GetComponent (string typeName);

喜欢

// Again just an example, there are many ways of getting type names
// Especially when dealing with multiple assemblies you might even have to use the AssemblyQualifiedName
var renderer = (Renderer) GetComponent("Renderer");

请注意,对于任何动态版本,您要么必须键入 cast,要么如果仅具有通用 Component 引用就足够了,您当然可以使用它。


但是,如果可能的话,根本不要使用string 版本!

它总是很慢而且容易出错。而是使用例如一些常见的基类或interface,或使用枚举或Dictionary 来决定为哪个状态做什么。

所以我宁愿有例如

public interface IWeapon

    void UseWeapon();

然后你的每一个不同的武器都可以实现这个接口

public class WeaponA : MonoBehaviour, IWeapon

    public void UseWeapon ()
    
        Debug.Log("Used Weapon A");
    


public class WeaponB : MonoBehaviour, IWeapon

    public void UseWeapon ()
    
        Debug.Log("Used Weapon B");
    

你的代码就是

var weapon = someObject.GetComponent<IWeapon>(). UseWeapon();

或者如果你的武器都共享一些共同的实现,例如拾取等,而不是有一个共同的基类

public abstract class BaseWeapon : MonoBehaviour

    // Everything that all weapons share as behavior and properties

    // every subclass HAS TO implement and override this method
    public abstract void UseWeapon ();

    // Alternatively if there even is some common behavior
    // subclasses CAN but don't have to override this
    //public virtual void UseWeapon ()
    //
    //    // Implementation that is the default behavior
    //

然后

public class WeaponA : BaseWeapon

    public override void UseWeapon ()
    
        Debug.Log("Used Weapon A");

        // If using virtual before then this class IGNORES and fully overwrites the default implementation
    


public class WeaponB : BaseWeapon

    public override void UseWeapon ()
    
        // If using virtual and you WANT the default behavior then add
        //base.UseWeapon();

        Debug.Log("Used Weapon B");       
    

你的代码就是

var weapon = someObject.GetComponent<BaseWeapon>(). UseWeapon();

【讨论】:

【参考方案2】:

如果我猜对了,你想做类似GetComponent&lt;"Transform"&gt;() 的事情吗? 如果是这样,你应该改用GetComponent("Transform");

【讨论】:

不,我不是要获取转换组件,而是要从游戏对象“武器”获取脚本组件 我在举一个例子。确保您可以将字符串 "Transform" 更改为您拥有的任何其他组件名称!

以上是关于使用字符串 Unity 从游戏对象获取脚本的主要内容,如果未能解决你的问题,请参考以下文章

Unity优化篇 | Unity脚本代码优化策略,快速获取 游戏对象 和 组件 的方法文末送书

Unity小技巧 - 自动获取所有子节点,再也不用通过脚本手动链接每个transform了

Unity小技巧 - 自动获取所有子节点,再也不用通过脚本手动链接每个transform了

Unity中获取游戏对象的几种方式

unity c#

unity获取游戏物体