首页 > 解决方案 > Unity 2D - 访问 GetComponent 的变量作为参数发送

问题描述

我有这个脚本来保存我的角色。我有很多 NPC,每个 NPC 都有自己的脚本。我想使用方法SaveCharacter来保存每个 NPC。如何g.GetComponent<Warrior_Movement>()作为参数发送并访问其变量?当我使用 时<T>,我无法获取游戏对象脚本的变量。谢谢

void SaveCharacter(Character character, string gameObjectName)
{
    GameObject g = GameObject.Find(gameObjectName);

    character.position = new float[] { g.transform.position.x, g.transform.position.y, g.transform.position.z };
    character.selectedScheme = g.GetComponent<Warrior_Movement>().selectedScheme;
    character.currentWaypointIndex = g.GetComponent<Warrior_Movement>().currentWaypointIndex;
    character.nextWaypointIndex = g.GetComponent<Warrior_Movement>().nextWaypointIndex;
    character.loopSide = g.GetComponent<Warrior_Movement>().loopSide;
}

标签: c#unity3dmethodstypes

解决方案


问题

不能使用变量将其传递给GetComponemtlike的通用版本

public void DoSomething(Type componemtType)
{
    var component = GetComponent<componentType>();
}

因为用于实现泛型的类型必须是编译时常量,因此不能是变量(或只有一个是编译时常量)!

GetComponent您可以使用like的非通用版本

public void DoSomething(Type componentType)
{
    var component = GetComponent(componentType);
}

您必须解析它才能访问特定于该组件的任何字段或方法:

var parsedComponent = component as componentType;

所以你不能这样做,因为用于的类型as也必须是编译时常量,因此不能是变量。


解决方案1:共享基类

如果你所有不同的类都有你想要保存的公共字段,它们都应该从一个公共的基本类型继承,比如

// By making a class abstract it can not be instanced itself but only be implemented by subclasses
public abstract class BaseMovement : MonoBehaviour
{
    // fields that will be inherited by subclasses
    public int currentWaypointIndex;
    public int nextWaypointIndex;
    //...

    // You could also have some generic methods that are implemented
    // only in the subclasses like e.g. Getters for the values
    // you want to access
    public abstract string SaySomething();
}

而不是继承你的类,比如

public class Warrior_Movement : BaseMovement
{
    // Inherits all fields of BaseMovement

    //... additional type specific stuff

    // If you have abstract methods in the base class
    // every subclass has to implement all of them
    public override string SaySomething()
    {
        return "Harr harr, I'm a warrior!";
    }
}

public class Other_Movement : BaseMovement
{
    // Inherits all fields of BaseMovement

    // Additional type specific stuff

    // If you have abstract methods in the base class
    // every subclass has to implement all of them
    public override string SaySomething ()
    {
        return "Harr harr, I'm ... something else :'D ";
    }
}

比你可以使用类似的东西

void SaveCharacter(Character character, BaseMovent bMovement)
{
    character.position = new float[] { bMovement.transform.position.x, bMovement.transform.position.y, bMovement.transform.position.z };
    character.currentWaypointIndex = bMovement.currentWaypointIndex;
    character.nextWaypointIndex = bMovement.nextWaypointIndex;
}

并称它为

GameObject g = GameObject.Find(gameObjectName);
var movement = g.GetComponemt<BaseMovement>();

SaveCharacter(someCharacter, movement);

解决方案 2:重载

或者,如果您对不同的组件使用不同的值,而不是使用共享基类,而是创建SaveCharacter类似的重载

public void SaveCharacter(Character character, Warrior_Movement wMovement)
{
    // Do stuff with wMovement
    // ...
}

public void SaveCharacter (Character character, Other_Movement oMovement)
{
    // Do stuff with oMovement
    // ...
}

因此,无论何时使用SaveCharacter传入的类型都会决定SaveCharacter应该使用哪个实现。


当我使用 时,我无法获取游戏对象脚本的变量。

我不知道你到底是什么意思,但你可以使用例如访问GameObject组件所附加的gameObject

bMovement.gameObject.SetActive(true);

注意
如果可能的话,你应该避免使用Find,因为它的性能非常强。尝试尽快获取引用,例如通过使用public GameObject字段在检查器中引用它,或者如果它已实例化,则将其保存到变量中

var warrior = Instantiate (/*...*/);

并传递它。


推荐阅读