【问题标题】:Set array size inside a method?在方法中设置数组大小?
【发布时间】:2015-05-17 05:02:56
【问题描述】:

我对 Unity 和 C# 还很陌生,所以请耐心等待。

我想创建一个方法,它采用 vector3 数组的一个参数来获取我的游戏中目标对象的位置,但数组大小不会更改为我放入方法中的数组 (targetPos)

private Vector3[] targetPos;
public int targetCount;
void Awake()
{
    SetTargetPos (targetPos);
}
private void SetTargetPos(Vector3[] targets){

    targetCount = GameObject.Find ("Targets").transform.childCount;
    targets = new Vector3[targetCount];
    for (int i = 0; i<targetCount; i++) {
        targets[i] = GameObject.Find("Targets").transform.FindChild("Target " + i.ToString()).position;
    }
}

我确实在 SetTargetPos 方法中设置了目标数组大小

targets = new Vector3[targetCount];

但是,当我开始游戏时,targetPos 数组的大小没有改变,这是为什么,我该如何解决这个问题?

【问题讨论】:

    标签: c# arrays unity3d


    【解决方案1】:

    这里可能存在一些误解,即您更改了数组的大小,但也可能只是您表述问题的方式。

    反正这里的问题和参数传递有关。

    这一行:

    SetTargetPos (targetPos);
    

    reference 的副本传递给方法。这个reference指的是内存中的数组对象。

    在方法内部,这一行:

    targets = new Vector3[targetCount];
    

    创建一个具有新所需大小的新数组,并将该新数组对象引用分配给该方法的局部参数变量。

    外部变量保持不变。

    在这里,让我告诉你我的意思。

    在方法调用之前,内存中有这些东西(示例数组包含 2 个元素):

    targetPos --> [V1, V2]
    

    然后,当您的程序正在执行并且对该方法的调用正在进行时,就在方法内部,在我们将任何内容分配给 targets 之前,我们会遇到这种情况:

    targetPos ------+
                    +--> [V1, V2]
    targets --------+
    

    我们现在有 2 个变量引用同一个数组,一个是本地的,一个是外部的。 targets 因此包含引用的副本,它与外部变量没有关系。

    因此,当您将一个新数组分配给本地参数变量时,您会遇到这种情况(假设我们为其分配一个包含 3 个元素的数组):

    targetPos --> [V1, V2]
    targets ----> [V1, V2, V3]
    

    您得到一个新数组,并更改targets 中的引用以引用这个新数组。外部变量保持原样,仍然引用前一个数组。您在方法中所做的任何事情都不会改变这一点。

    如果您更改方法以通过引用传递变量

    private void SetTargetPos(ref Vector3[] targets){
    

    你还需要改变你的称呼:

    SetTargetPos (ref targetPos);
    

    现在这将正确地重新分配外部变量。

    有关参数传递的更多信息,您应该阅读Jon Skeets blog article on parameter passing

    【讨论】:

    • 所以..添加“ref”将使用方法内部的实际变量而不是副本?
    • 正确。在幕后,将传递指向原始变量的指针,所有变量访问实际上都将使用原始变量。
    • 虽然您也不应该在这里忽略其他答案,但实际使用列表对您来说可能会更好,但您需要自己确定。
    • 谢谢,虽然我对列表还不是很熟悉,但我会试试的
    【解决方案2】:

    只需使用List 而不是数组。它会动态调整大小

    private List<Vector3> targetPos = new List<Vector3>();
    public int targetCount;
    void Awake()
    {
        SetTargetPos (targetPos);
    }
    private void SetTargetPos(Vector3[] targets){
    
        targetCount = GameObject.Find ("Targets").transform.childCount;
        targets = new Vector3[targetCount];
        for (int i = 0; i<targetCount; i++) {
            targets[i] = GameObject.Find("Targets").transform.FindChild("Target " + i.ToString()).position;
        }
    }
    

    【讨论】:

      【解决方案3】:

      正如 Ivan 所建议的,您可能希望使用列表而不是数组。

      我认为您遇到的问题是由于这一行:

      targets = new Vector3[targetCount];
      

      当您为targets 参数赋值时,它会在本地更新targets 的值,但不会更新targetPos(即使它是通过引用传递的)。使用 List 可以解决这个问题,因为您可以重复使用同一个实例而不是分配一个新实例。

      private List<Vector3> targetPos = new List<Vector3>();
      public int targetCount;
      
      void Awake()
      {
          SetTargetPos(targetPos);
      }
      
      private void SetTargetPos(List<Vector3> targets)
      {
          targetCount = GameObject.Find ("Targets").transform.childCount;
          targets.Clear();
          for (int i = 0; i<targetCount; i++)
          {
              targets.Add(GameObject.Find("Targets").transform.FindChild("Target " + i.ToString()).position);
          }
      }
      

      【讨论】:

      • 它不是通过引用传递的,这就是这里的问题。代码正在传递 a 引用,但它正在通过 value 传递引用。
      • 对,我想你的解释在技术上更正确 - 它通过引用传递 array,但 reference 仍然按值传递。
      • 我们只传递引用,按值传递,数组根本没有传递,它只被引用引用。我明白你的意思,但如果你想在谷歌上搜索更多信息,正确使用条款很重要:) 但是,这是吹毛求疵。但是,我确实认为使用列表不是正确的答案,否则我会放手。这个问题是根据 Unity 提出的,这意味着游戏,并且通常有强烈的愿望/要求知道在这种情况下何时完成内存分配。一个列表可以消除这些知识。
      • 我不是说列表是错误的,他还说他是统一的新手,他并没有说他在做什么。如果性能受到影响,我也肯定会先列出一个列表并摆弄一个数组。我只是想我可以发布一个关于他的代码实际问题的答案。
      猜你喜欢
      • 2015-12-20
      • 1970-01-01
      • 2012-12-27
      • 1970-01-01
      • 1970-01-01
      • 2014-09-23
      • 2010-12-12
      • 2014-04-29
      • 1970-01-01
      相关资源
      最近更新 更多