Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Cornhelius · Jul 21, 2017 at 09:07 PM · arrayjointsfor loop

Filled array becomes an empty one when I access it in another class

(Edit: I posted more info and all the code in question in post #3 then updated this post to reflect it)

Problem: Once I create and populate the array in class A, I try to use it in Class B but returns "NullReferenceException: Object reference not set to an instance of an object" when I try to see the length of the array. It seems to be empty by that point and I have no clue why.

Class A:

 public class spawnMembrane : MonoBehaviour
 {
     public membraneVars membrane;
     public int numObjects = 36;
     public int size = 5; // constant coeff
     public float colliderRadius = 7;
     private CircleCollider2D cellCL;
     [HideInInspector]
     public List<membraneVars> membraneList;
     [System.NonSerialized]
     public membraneVars[] membraneArray;
     private Rigidbody2D cellRB;
     public Transform membraneCount;
 
     // Use this for initialization
     void Start()
     {
         cellCL = GetComponent<CircleCollider2D>();
         cellCL.radius = colliderRadius;
         cellRB = GetComponent<Rigidbody2D>();
         membraneArray = new membraneVars[numObjects];
         for (int i = 0; i < numObjects; i++) 
         {
             membraneArray[i] = (membraneVars)GameObject.Instantiate(membrane);
             membraneArray[i].transform.SetParent(membraneCount);
             membraneArray[i].transform.localScale *= size * cellCL.radius / numObjects;
             membraneArray[i].transform.position = PositionCircle(cellCL.offset, cellCL.radius, i*360/numObjects);
             membraneArray[i].centerJoint.connectedBody = cellRB;
             Debug.Log(membraneArray[i].GetInstanceID()); // up until this point its fine, the array is full

Class B:

 public class membraneVars : MonoBehaviour {
 
     public GameObject cell;
 public membraneVars[] membraneObj;
 
    void Start()
     {
         membraneObj = cell.GetComponent<spawnMembrane>().membraneArray; // the array exists when I access it here
     Debug.Log(membraneObj.Length); // but this line doesn't work, nullreferenceexception, Object reference not set to an instance of an object
 
 
 void OnJointBreak2D(Joint2D sideJointA)
     {
         for (int i = 0; i < membraneObj.Length; i++) // it explodes here as well if I remove the trace above
         {
             membraneVars temp = membraneObj[i];
             Vector3 membranePos = temp.transform.position;
             float distance = Vector3.Distance(transform.position, membranePos);
             distanceBetweenList.Add(distance);
         }





Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bunny83 · Jul 21, 2017 at 11:34 PM 0
Share

A few things that are strange about your code:

  • You have abstracted your classnames into "Class A" and "Class B". However based on those "names" your two script fragments don't seem to be related at all. I guess your Class A is actually called "spawn$$anonymous$$embrane", right? It would be great when this information would be more clear.

  • Is there a reason why "distanceBetweenList" is a class variable? $$anonymous$$aybe just to avoid recreation each time?

  • Since "distanceBetweenList" is a member variable you probably want to "Clear()" it before you fill it with the distance values. Otherwise each time OnJointBreak2D is called you add more and more distances to the list.

  • The Linq method "$$anonymous$$in" will throw an "InvalidOperationException" in case the collection is empty since it can't return any value.

  • If you just want to get the $$anonymous$$-distance you wouldn't need that list at all. Just do the $$anonymous$$Distance filtering in that for loop.

Something like this:

     float $$anonymous$$imumDistance = float.PositiveInfinity;
     var array = membraneObj.membraneArray;
     for (int i = 0; i < array.Length; i++)
     {
         float distance = Vector3.Distance(transform.position, array[i].transform.position);
         if (distance < $$anonymous$$imumDistance)
             $$anonymous$$imumDistance = distance;
     }

3 Replies

· Add your reply
  • Sort: 
avatar image
2

Answer by FlaSh-G · Jul 21, 2017 at 11:07 PM

Edit: Mind @Bunny83's (better) answer. I'll leave this here because it's not wrong per se, even though not the right answer to your problem.

In the case of collections, this exception means that the collection is being modified while it is being iterated over. For example, it will happen here:

 foreach(var element in collection)
 {
   if(IsEvil(element))
   {
     collection.Remove(element);
   }
 }

The iterator that manages the loop will be in a broken state because it maybe points at the wrong element after the collection changed.

Now, in your situation, you have a Linq statement that also uses an iterator internally. So the exception is probably stating that either the Linq statement itself or some other code is changing the list.

My problem is that I don't see where that cn happen. The Linq statement itself shouldn't be a problem since it's read only on the list. And OnJointBreak2D is called from a single thread, so there shouldn't be any other code involved here. I just hope this answer gets you in some starting direction for further research.

In terms of the array apparently being empty all the time... are you sure you are refernencing the right object in membraneObj? I could imagine you having two objects, one with a filled array and the other being referenced in the other object.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bunny83 · Jul 21, 2017 at 11:47 PM 0
Share

An "InvalidOperationException" is not only thrown when the collection has changed during iteration. "$$anonymous$$in" will throw an InvalidOperationException when the collection is empty. It's not possible to return any value if the collection is empty.

He could use "DefaultIfEmpty", however using a list just to find the $$anonymous$$imum distance seems to be overkill.

 float $$anonymous$$imumDistance = distanceBetweenList.DefaultIfEmpty(0f).$$anonymous$$in();
avatar image FlaSh-G · Jul 22, 2017 at 09:26 AM 0
Share

@Bunny83 Learned something new today! Since your comment is a way better answer than $$anonymous$$e, do you $$anonymous$$d putting it in the form of an answer as well?

avatar image
2

Answer by Bunny83 · Jul 22, 2017 at 09:53 AM

Yesterday i didn't had enough time to actually write an answer, especially in the beginning the cause wasn't clear -.-

Like i said in my comment above: The Linq method "Min" will throw an "InvalidOperationException" in case the collection is empty since it can't return any value.

One easy fix is to use "DefaultIfEmpty" to ensure at least one value in the collection, even when it's empty:

 float minimumDistance = distanceBetweenList.DefaultIfEmpty(0f).Min();

Though it's not clear if you use the "distanceBetweenList" somewhere else. If not you shouldn't use a list at all. If you just want to find the shortest distance you can use this:

 float minimumDistance = float.PositiveInfinity;
 var array = membraneObj.membraneArray;
 for (int i = 0; i < array.Length; i++)
 {
     float distance = Vector3.Distance(transform.position, array[i].transform.position);
     if (distance < minimumDistance)
         minimumDistance = distance;
 }

If your "membraneArray" is empty you should make sure that your "membraneObj" variable is actually referencing the correct object. Maybe there are multiple "spawnMembrane " objects in the scene and you're referencing the wrong one?

I would also recommend to move the creation of your array from Awake to Start. It's just a potential error source. Since the "membraneArray" should not be initialized from the inspector and therefore it doesn't need to be serialized it would also make sense to mark the array as NonSerialized

 [System.NonSerialized]
 public membraneVars[] membraneArray;
 
 void Start()
 {
     membraneArray = new membraneVars[numObjects];
     for (int i = 0; i < numObjects; i++)
     {
         // ...
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by Cornhelius · Jul 22, 2017 at 07:48 PM

Thank you both for the replies. The Cell object is the only object of it's kind in the scene. Here's the full code, sorry for not explaining myself properly. Up until the commented Debug.Log line in class A the array I need in class B is full of stuff. When I try to access its elements in Class B in the second line of the OnJointBreak function unity returns the error I posted earlier. I can't figure out why the array is empty in Class B.

Class A:

 public class spawnMembrane : MonoBehaviour
 {
     public membraneVars membrane;
     public int numObjects = 36;
     public int size = 5; // constant coeff
     public float colliderRadius = 7;
     private CircleCollider2D cellCL;
     [HideInInspector]
     public List<membraneVars> membraneList;
     [System.NonSerialized]
     public membraneVars[] membraneArray;
     private Rigidbody2D cellRB;
     public Transform membraneCount;
 
     // Use this for initialization
     void Start()
     {
         cellCL = GetComponent<CircleCollider2D>();
         cellCL.radius = colliderRadius;
         cellRB = GetComponent<Rigidbody2D>();
         membraneArray = new membraneVars[numObjects];
         for (int i = 0; i < numObjects; i++) //problems: double the joints
         {
             membraneArray[i] = (membraneVars)GameObject.Instantiate(membrane); 
             membraneArray[i].transform.SetParent(membraneCount);
             membraneArray[i].transform.localScale *= size * cellCL.radius / numObjects;
             membraneArray[i].transform.position = PositionCircle(cellCL.offset, cellCL.radius, i*360/numObjects);
             membraneArray[i].centerJoint.connectedBody = cellRB;
             if (i != 0)
             {
                 membraneArray[i].sideJointA.connectedBody = membraneArray[i - 1].GetComponent<Rigidbody2D>();
                 if (i - 1 != 0)
                 {
                     membraneArray[i - 1].sideJointB.connectedBody = membraneArray[i].GetComponent<Rigidbody2D>();
                 }
             }
             if (i == numObjects)
             {
                 membraneArray[i].sideJointB.connectedBody = membraneArray[i-1].GetComponent<Rigidbody2D>();
                 membraneArray[0].sideJointA.connectedBody = membraneArray[numObjects].GetComponent<Rigidbody2D>();
             }
             if (i - 1 == 0)
             {
                 membraneArray[0].sideJointB.connectedBody = membraneArray[i].GetComponent<Rigidbody2D>();
             }
             Debug.Log(membraneArray[i].GetInstanceID()); // at this point I do get all the IDs of the objects I'm creating and putting into the array.
         }
     }
     // Update is called once per frame
     void Update()
     {
         
     }
     Vector2 PositionCircle(Vector2 center, float radius, int angle)
     {
         float ang = angle;
         Vector2 pos;
         pos.x = center.x + radius * Mathf.Sin(ang * Mathf.Deg2Rad);
         pos.y = center.y + radius * Mathf.Cos(ang * Mathf.Deg2Rad);
         return pos;
     }

 }


Class B:

 public class membraneVars : MonoBehaviour {
 
     public SpringJoint2D sideJointA;
     public SpringJoint2D sideJointB;
     public SpringJoint2D centerJoint;
 
     public GameObject cell; // Prefab dragged into prefab's component slot
 
     public float membraneRadius = 4.5f;
 
     private List<float> distanceBetweenList;
     public spawnMembrane membraneObj;
     // Use this for initialization
     void Awake()
     {
         sideJointA = gameObject.AddComponent<SpringJoint2D>();
         sideJointA.breakForce = 10;
         sideJointB = gameObject.AddComponent<SpringJoint2D>();
         sideJointB.breakForce = 10;
         centerJoint = gameObject.AddComponent<SpringJoint2D>();
     }
     void Start()
     {
         membraneObj = cell.GetComponent<spawnMembrane>(); // this doesn't give error
         distanceBetweenList = new List<float>();
     }
     // Update is called once per frame
     void Update ()
     {
 
     }
     void OnJointBreak2D(Joint2D sideJointA)
     {
         for (int i = 0; i < membraneObj.membraneArray.Length; i++) // Error when accesing any array index.
         {
             membraneVars temp = membraneObj.membraneArray[i]; 
             Vector3 membranePos = temp.transform.position;
             float distance = Vector3.Distance(transform.position, membranePos);
             distanceBetweenList.Add(distance);
         }
         float minimumDistance = distanceBetweenList.Min();
         distanceBetweenList.Remove(minimumDistance);
         float newMinimumDistance = distanceBetweenList.Min();
         for (int i = 0; i < membraneObj.membraneArray.Length; i++)
         {
             if (Vector3.Distance(transform.position, membraneObj.membraneArray[i].transform.position) == newMinimumDistance)
             {
                 sideJointA = gameObject.AddComponent(typeof(SpringJoint2D)) as SpringJoint2D;
                 sideJointA.breakForce = 11;
                 sideJointA.connectedBody = membraneObj.membraneArray[i].GetComponent<Rigidbody2D>();
             }
         }
     }
 }

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

78 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Problem with raycasts in a for loop 2 Answers

Method to loop through an unknown number of variable combinations in C# 1 Answer

Order or Sort list of files using DirectoryInfo 1 Answer

Loop through array until certain value is found. 2 Answers

Add object on trigger to array, then cast a ray at all objects in the array 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges