【问题标题】:How to update an array of object with a dynamic index?如何使用动态索引更新对象数组?
【发布时间】:2020-07-20 15:13:21
【问题描述】:

开始

ex "数组调整大小丢失的类或索引"

我正在构建一个对象来保存我的汽车的值。

基本逻辑是: 对于每个变速箱 > 保存每个悬架 > 保存每个车轮。

脚本逻辑:

  public class VehicleController : MonoBehaviour
  {
      public gearbox[] gearboxes = new gearbox[0]; //999 not change effect

      [System.Serializable] 
      public class gearbox
      {
        public Transform gearBoxTarget;

        public List<Transform> assets = new List<Transform>();

        public gearbox(Transform gearBoxTarget, List<Transform> assets  )
        {
            this.gearBoxTarget = gearBoxTarget;
            this.assets = assets;
        }
      }

      void Awake()
      {
        /// count all gBox into 3d model
        List<Transform> boxes = new List<Transform>();
        Transform[] elems = transform.GetComponentsInChildren<Transform>();
        int Index = 0;
        for (int c = 0; c < elems.Length; c++)
        {
          if (elems[c].name == "gearbox")
          {
            Index++;
            boxes.Add(elems[c].transform);
          }
        }

        /// set array length (1 for gBox finded)
        System.Array.Resize(ref gearboxes, Index);

        /// for all gearboxes finded (or boxes.Length... It's equal)
        for (int box = 0; box < gearboxes.Length; box++)
        {
          // get suspansions and wheels
          Transform[] inBox = boxes[box].GetComponentsInChildren<Transform>();
          List <Transform> Items = new List <Transform>();
          for (int e = 0; e < inBox.Length; e++)
          {
              var el = inBox[e];
              if (el.parent.name == "gearbox" || el.name == "wheel"){ Debug.Log(e+" => "+el); Items.Add(el); }else{Debug.Log(e);}
              if(e==inBox.Length) { Debug.Log("finder end"); }
          }

          /// add elements into the gearbox object
          Debug.Log(gearboxes[box]); // NULL!
          gearboxes[box].gearBoxTarget = boxes[box]; // NULL!
          gearboxes[box].assets.AddRange(Items); // NULL!
        }
      }
  }

我不明白为什么数组的长度发生了变化,尽管检查器已更新,但脚本似乎不再看到变速箱。

无论您尝试放入什么,变速箱...都是无效的


测试 02

新的简化测试。

我尝试在 Awake 中初始化列表。

它还会创建第二个列表,用于处理元素。

未能直接实例化对象我尝试将所有内容从新列表转移到旧列表。

  public class VehicleController : MonoBehaviour
  {

    public gearbox[] gearboxes;

    [System.Serializable]
    public class gearbox
    {

      public Transform boxtarget; 

        public gearbox( Transform boxtarget  )
        {
        this.boxtarget = boxtarget;
        }
    
    }

    void Awake()
    {

        // count all gBox and set it on inspector and add to list
        Transform[] elems = transform.GetComponentsInChildren<Transform>();
        List<Transform> targets = new List<Transform>();
        for (int c = 0; c < elems.Length; c++)
        {
          if (elems[c].name == "gearbox")
          {
            targets.Add(elems[c]);
          }
        }

        int Counter = targets.Count;

        // System.Array.Resize(ref gearboxes, Index);
        gearbox[] gboxes = new gearbox[Counter];
        gearboxes = new gearbox[Counter];

        for (int i = 0; i < Counter; ++i)
        { 

          Debug.Log(targets[i]); //ok exist
          gboxes[i].boxtarget = targets[i];
        }

        System.Array.Copy(gboxes, 0, gearboxes , 0, Counter);
         

    }

  }

又一次失败。 在检查器列表中更新为 3 个元素但为空并且调试写入 null。

齿轮箱(UnityEngine.Transform)(目标确定)

NullReferenceException:对象引用未设置为 object VehicleControllerManager.VehicleController.Awake()(在


测试 03

另一种方法...

现在的尝试是将一个类添加到列表中并检索拥有该类的对象。

这样我应该绕过这样一个事实,即单声道直接指向变速箱但将其视为附加对象。

public class VehicleController : MonoBehaviour
{
    [SerializeField]
    public List<gearbox> gearboxes = new List<gearbox>();

    [System.Serializable] 
    public class gearbox
    {
      public class box
      {
        public Transform boxTarget;
        public box(Transform boxTarget)
        {
          this.boxTarget = boxTarget;
        }
      }
    }

    void Awake()
    {


      /// count all gBox into 3d model
      List<Transform> boxes = new List<Transform>();
      Transform[] elms = transform.GetComponentsInChildren<Transform>();
      int Counted = 0;
      for (int c = 0; c < elms.Length; c++)
      {
        if (elms[c].name == "gearbox")
        { Counted++; boxes.Add(elms[c].transform); }
      }

      Debug.Log(boxes.Count); // yes, it's 3

      /// add class on link (1 for all gBox finded)
      for (int box = 0; box < boxes.Count; box++)
      {
        gearboxes.Add( new VehicleController.gearbox()); // ok, added it
      }

      /// for all gearboxes in list
      for (int i = 0; i < gearboxes.Count; i++)
      {
        /// into the gearboxes get object and set values of box
        //gearboxes[i].gearbox.box.boxTarget = boxes[i]; WTF? I can't navigate into the class!??
      }

    }
}

结果:检查器中出现 3 个元素,但它们内部似乎没有任何内容,或者无论如何..."gearboxes[i].gearbox.box.boxTarget = boxes[i];"我无法导航到类...

是否有可能恢复盒子并设置它们的内部值?


测试 03.b

根据各种建议和示例,我找到了一个“半解决方案”

这不是确定的,因为我不在检查器中显示内容,而只显示插入的类。

但是,如果我循环...数据存在并返回!

public class VehicleController : MonoBehaviour
{
    [SerializeField]        public List<gearbox> gearboxes = new List<gearbox>();
    [System.Serializable]   public class gearbox
                            {
                              public _box box = new _box();
                              [System.Serializable]
                              public class _box
                              {
                                public Transform boxTarget { get; set; }
                              }
                            }
  

    void Start()
    {


      /// count all gBox into 3d model
      List<Transform> boxes = new List<Transform>();
      Transform[] elms = transform.GetComponentsInChildren<Transform>();
      int Counted = 0;
      for (int c = 0; c < elms.Length; c++)
      {
        if (elms[c].name == "gearbox")
        { Counted++; boxes.Add(elms[c].transform); }
      }

      Debug.Log(boxes.Count);

      /// add class on link (1 for all gBox finded)
      for (int box = 0; box < boxes.Count; box++)
      {
        gearboxes.Add( new VehicleController.gearbox());
      }

      // for all gearboxes in list
      for (int i = 0; i < gearboxes.Count; i++)
      {
        /// add elements into the gearbox object
        gearboxes[i].box.boxTarget = boxes[i];
      }

      for (int i = 0; i < gearboxes.Count; i++)
      {
        Debug.Log("++ "+gearboxes[i].box.boxTarget);
      }

    }
}

测试 03.c - 解决方案

正如建议的那样,它是“实例化对象”,但是 这是直接实例化到列表的构造

如果没有这个,最大的问题是要理解“如果它是空的,就不可能实例化对象”,否则你会发现著名的“空错误”。

所以......让我们给它一个空! :D,这就是解决方案!

public class VehicleController : MonoBehaviour
{
    [SerializeField]        public List<boxvalues> gearboxes = new List<boxvalues>();
    [System.Serializable]   public class boxvalues
                            {
                              public Transform boxTarget;
                              public boxvalues(Transform boxTarget)
                              {
                                this.boxTarget = boxTarget;
                              }
                              // [SerializeField] public Transform boxTarget { get; set; } // This is a safer system but does not expose variables.
                            }
  

    void Awake()
    {


      /// count all gBox into 3d model
      List<Transform> boxes = new List<Transform>();                       // prepare a list of gameObject.
      Transform[] elms = transform.GetComponentsInChildren<Transform>();   // find all child into main gameObject.
      int Counted = 0;                                                     // Counter of gameObject
      for (int c = 0; c < elms.Length; c++)                                // Loop all finded gameObject into main
      {
        if (elms[c].name == "gearbox")                                     // if is my gameObject...
        { Counted++; boxes.Add(elms[c].transform); }                       // add it to list and count it...
      }

      Debug.Log(boxes.Count);                                              // yes, It's 3 gameObject.

      /// add class on link (1 for all gBox finded)
      for (int box = 0; box < boxes.Count; box++) 
      {
        gearboxes.Add( new VehicleController.boxvalues(null));            // now for all gameObject init a new data container... empty (yooo! new list of data!)
      }

      // for all gearboxes in list
      for (int i = 0; i < gearboxes.Count; i++)                           // now for all data container... put a new values. Win!
      {
        /// add elements into the box object
        gearboxes[i].boxTarget = boxes[i];
      }

      // test return the values
      for (int i = 0; i < gearboxes.Count; i++)
      {
        Debug.Log("++ "+gearboxes[i].boxTarget);
      }

    }
}

衷心感谢那些耐心给我一个有用的方向的人!

我希望这个方案对其他人有教育意义。

【问题讨论】:

  • 如果gearbox 是一个类,那么它的默认值为null - 如果您希望它不为空,则需要创建该类的实例
  • 如果gearboxclass,那么您有一个对gearbox 实例的引用数组。这种引用的默认值为null
  • @Alberto 您不能在 c# 中调整数组的大小,只能用不同大小的新数组替换它。您或许应该考虑使用 List,因为这将提供添加/删除项目的能力。
  • @Alberto Array.Resize 不会调整数组的大小,它会以请求的大小创建一个新数组,并将旧数组中的元素复制到其中。这是一个技术点,但很重要,因为数组不再是同一个对象。
  • @Alberto,我认为问题出在 UnholySheep 解释的范围内,您正在创建一个大小正确的数组,但所有条目均为空,因为您从未将它们设置为任何内容。

标签: c# arrays object unity3d


【解决方案1】:

你需要创建类的实例:

public class VehicleController : MonoBehaviour
  {
      public gearbox[] gearboxes = null;

      public VehicleController()
      {
        gearboxes = new gearbox[0];
      }

      [System.Serializable] 
      public class gearbox
      {
        public Transform gearBoxTarget;

        public List<Transform> assets = new List<Transform>();

        public gearbox(Transform gearBoxTarget, List<Transform> assets  )
        {
            this.gearBoxTarget = gearBoxTarget;
            this.assets = assets;
        }
      }

      void Awake()
      {
        /// count all gBox into 3d model
        List<Transform> boxes = new List<Transform>();
        Transform[] elems = transform.GetComponentsInChildren<Transform>();
        int Index = 0;
        for (int c = 0; c < elems.Length; c++)
        {
          if (elems[c].name == "gearbox")
          {
            Index++;
            boxes.Add(elems[c].transform);
          }
        }

        /// set array length (1 for gBox finded)
        System.Array.Resize(ref gearboxes, Index);

        /// for all gearboxes finded (or boxes.Length... It's equal)
        for (int box = 0; box < gearboxes.Length; box++)
        {
          // get suspansions and wheels
          Transform[] inBox = boxes[box].GetComponentsInChildren<Transform>();
          List <Transform> Items = new List <Transform>();
          for (int e = 0; e < inBox.Length; e++)
          {
              var el = inBox[e];
              if (el.parent.name == "gearbox" || el.name == "wheel"){ Debug.Log(e+" => "+el); Items.Add(el); }else{Debug.Log(e);}
              if(e==inBox.Length) { Debug.Log("finder end"); }
          }

          /// add elements into the gearbox object
          Debug.Log(gearboxes[box]);
          gearboxes[box].gearBoxTarget = boxes[box];
          gearboxes[box].assets.AddRange(Items);
        }
      }
  }

我猜你没加的函数应该是这样的:

public class Transform
    {

        public string name { get; set; }

        public Transform parent { get; set; }

        public Transform[] GetComponentsInChildren<T>()
        {
            return (new List<Transform>() {
                new Transform() { name = "gearbox" },
                new Transform() { parent = new Transform() { name = "gearbox" }, name = "wheel" }
            }).ToArray();
        }
    }

假设是这种情况,逻辑相同,你必须初始化变量,因为你初始化了类,否则它总是为空。

public class VehicleController
    {
        private gearbox[] gearboxes;
        private readonly Transform transform;

        public VehicleController(Transform _transform)
        {
            gearboxes = new gearbox[0];
            transform = _transform;
        }

        [System.Serializable]
        public class gearbox
        {
            public Transform gearBoxTarget;

            public List<Transform> assets = new List<Transform>();

            public gearbox(Transform gearBoxTarget, List<Transform> assets)
            {
                this.gearBoxTarget = gearBoxTarget;
                this.assets = assets;
            }
        }

        void Awake()
        {
            /// count all gBox into 3d model
            List<Transform> boxes = new List<Transform>();
            Transform[] elems = transform.GetComponentsInChildren<Transform>();
            int Index = 0;
            for (int c = 0; c < elems.Length; c++)
            {
                if (elems[c].name == "gearbox")
                {
                    Index++;
                    boxes.Add(elems[c].transform);
                }
            }

            /// set array length (1 for gBox finded)
            System.Array.Resize(ref gearboxes, Index);

            /// for all gearboxes finded (or boxes.Length... It's equal)
            for (int box = 0; box < gearboxes.Length; box++)
            {
                // get suspansions and wheels
                Transform[] inBox = boxes[box].GetComponentsInChildren<Transform>();
                List<Transform> Items = new List<Transform>();
                for (int e = 0; e < inBox.Length; e++)
                {
                    var el = inBox[e];
                    if (el.parent.name == "gearbox" || el.name == "wheel") { Debug.Log(e + " => " + el); Items.Add(el); } else { Debug.Log(e); }
                    if (e == inBox.Length) { Debug.Log("finder end"); }
                }

                /// add elements into the gearbox object
                Debug.Log(gearboxes[box]);
                gearboxes[box].gearBoxTarget = boxes[box];
                gearboxes[box].assets.AddRange(Items);
            }
        }
    }

【讨论】:

  • 不...它不起作用。一直说变速箱是空的
  • 函数“transform.GetComponentsInChildren()”有什么作用?
  • 恢复容器中的对象。然后他们扫描名称,如果它被称为对象,那么我保存并计算它。到每个对象 3d 将对应相对对象 c #
  • 无论如何等等......我发布了测试 3,我研究了你推荐的内容并回答了(我没有注意到你更新了答案,我也看到了 get / set)跨度>
  • 真的很感谢你,没有你的例子我就无法理解和采取正确的方式。
猜你喜欢
  • 1970-01-01
  • 2023-02-11
  • 1970-01-01
  • 2018-01-15
  • 1970-01-01
  • 1970-01-01
  • 2019-08-12
  • 2021-12-14
相关资源
最近更新 更多