如何使用动态索引更新对象数组?
Posted
技术标签:
【中文标题】如何使用动态索引更新对象数组?【英文标题】: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); elseDebug.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
- 如果您希望它不为空,则需要创建该类的实例
如果gearbox
是class
,那么您有一个对gearbox
实例的引用数组。这种引用的默认值为null
@Alberto 您不能在 c# 中调整数组的大小,只能用不同大小的新数组替换它。您或许应该考虑使用 List,因为这将提供添加/删除项目的能力。
@Alberto Array.Resize 不会调整数组的大小,它会以请求的大小创建一个新数组,并将旧数组中的元素复制到其中。这是一个技术点,但很重要,因为数组不再是同一个对象。
@Alberto,我认为问题出在 UnholySheep 解释的范围内,您正在创建一个大小正确的数组,但所有条目均为空,因为您从未将它们设置为任何内容。
【参考方案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); elseDebug.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以上是关于如何使用动态索引更新对象数组?的主要内容,如果未能解决你的问题,请参考以下文章