从 Update 方法中移出比较:使用委托代替还是其他方法?

Moving comparisons out from the Update method: using delegates instead or another approach?

我们直接上例子。假设我们有:

Update(){
   if (value.Equals("circular")) moveGameObjectInACircularWay();
   else if (value.Equals("linear")) moveGameObjectInALinearWay();
}

我认为这不是很优雅的解决方案。 Unity需要每一帧都进行一次比较。这对我来说听起来不是很理想。我只是猜测它应该是其他实现方式,例如:

Start () {
   if (value.Equals("circular")) movement += moveGameObjectInACircularWay;
   else if (value.Equals("linear")) movement += moveGameObjectInALinearWay;
} 

Update () {
   movement();
}

我想解决方案与代表有关。这就是为什么我提出的解决方案看起来像代表。我还不明白什么代表还好。

来自 MSDN "C# 中的委托类似于 C 或 C++ 中的函数指针。使用委托允许程序员将对方法的引用封装在委托对象中。" (https://msdn.microsoft.com/en-us/library/aa288459(v=vs.71).aspx) 简而言之就是一个指向方法的指针。您要做的是:

using UnityEngine;
using System.Collections;

public delegate void MovementDelegate();

public class Movement : MonoBehaviour {

    MovementDelegate movementFunction=null;
    public string value = "linear";
    void Start () {
        if (value.Equals("circular")) movementFunction = moveGameObjectInACircularWay;
        else if (value.Equals("linear")) movementFunction =  moveGameObjectInALinearWay;
    }

    // Update is called once per frame
    void Update()
    {
        if (movementFunction != null)
        {
            movementFunction();
        }
    }

    void moveGameObjectInACircularWay()
    {
        Debug.Log("do circular movement here");
    }

    void moveGameObjectInALinearWay()
    {
        Debug.Log("do linear movement here");
    }
}

您声明的函数必须与委托签名具有相同的签名。如果你想给它添加参数,例如。一个 int,将你的委托标记为

public delegate void MovementDelegate(int speed);

并且您的实现功能为

void moveGameObjectInACircularWay(int speed)
void moveGameObjectInALinearWay(int speed)

并将调用更改为

movementFunction(yourIntHere)

已更新!:感谢 Joe Blow 的建议,这是另一个解决方案:

public class Movement : MonoBehaviour
{
    Action<int> movementFunction = null;

    public string value = "linear";
    void Start()
    {
        if (value.Equals("circular")) movementFunction = moveGameObjectInACircularWay;
        else if (value.Equals("linear")) movementFunction = moveGameObjectInALinearWay;
    }

    // Update is called once per frame
    void Update()
    {
        if (movementFunction != null)
        {
            movementFunction(2);
        }
    }

    void moveGameObjectInACircularWay(int speed)
    {
       Debug.Log("do circular movement here "+ speed);
    }

    void moveGameObjectInALinearWay(int speed)
    {
        Debug.Log("do linear movement here " + speed);
    }
}

我最喜欢的答案是 Joe Blow 在评论中写的:

Unity 是基于组件的。我们最好 switch to Component-Based Thinking 而不是与代表一起工作。

所以制作两个(或更多)不同的脚本,并将它们放在有问题的游戏对象上。然后,根据需要打开和关闭这些组件。

因此我们必须将脚本添加到我们的游戏对象中:MoveGameObjectInACircularWay.csMoveGameObjectInALinearWay.cs。然后一个MainGameObjectScript.cs也添加到我们的游戏对象中,代码如下:

void Start () {
   GetComponent()<MoveGameObjectInACircularWay>.active = true;
   GetComponent()<MoveGameObjectInALinearWay>.active = false;
}