• 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
Question by ADiSiN · Jan 20, 2018 at 05:31 AM · c#nullreferenceexceptionforeach

C# - foreach problem

The problem is that I'm creating here an array of Colliders, to get acces to script "Enemy" attached to them and execute function which slow object. After I save all colliders in class variable resetCol. Then I wait for 1.2f and want to reset speed of each object inside this array. So problem is, that when some object is destroyed before executing last part of this code (under "yield return new WaitForSeconds(1.2f);") - unity show me an error. As - there is no reference "NullReferenceException" and it's ok, because in array appears empty space. So Idk how to fix it, because inside foreach I'm checking for "collider != null", so it shouldn't take empty space inside array, isn't it?

So, basically, the problem is - am I checking empty statement inside array wrongly?

I probably misspoke something (have not good enough English knowledge), so ask - I'll try to explain.

 Collider[] resetCol;
 public float duration;
 public float slowerSlow;

 IEnumerator GrowingSphere()
     {
         float r = 0;
         float distance = 0;
         while (r < duration)
         {
             Collider[] colliders = Physics.OverlapSphere(transform.position, distance);
             r++;
             distance += .074f;
             foreach (Collider collider in colliders)
             {
                 if (collider.tag == "Enemy")
                 {
                     collider.GetComponent<Enemy>().Slow(slowerSlow);
                 }
             }
             yield return new WaitForFixedUpdate();
             resetCol = colliders;
         }
         yield return new WaitForSeconds(1.2f);
         foreach (Collider collider in resetCol)
         {
             if (collider != null)
             {
                 collider.GetComponent<Enemy>().speed = collider.GetComponent<Enemy>().startSpeed;
             }
         }
     }
Comment

People who like this

0 Show 4
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 PizzaPie · Jan 20, 2018 at 07:31 AM 3
Share

Probably you need on 2nd foreach to check if it has the Enemy component and then access it as you do in first one.

 if (collider != null && collider.GetComponent<Enemy>() /*!= null*/)
avatar image Lysander PizzaPie · Jan 20, 2018 at 07:56 AM 2
Share

Agreed, and you might think about making a class-scope List and adding the slowed objects to that instead of using the original array. As long as its cached and you just call Clear on it instead of re-making the list, it's not a real performance hit.

You might consider making .Slow on the Enemy component just create a new coroutine locally and handle its own reset. This way seems convoluted to me.

avatar image pako Lysander · Jan 20, 2018 at 01:44 PM 1
Share

That's a very good idea. Having, say, a List<Collider> EnemyColliders and adding in it all colliders that were found to be tagged "Enemy" in the first foreach loop, would make things simpler, since in the second foreach loop he would iterate though the EnemyColliders instead of the resetCol array.

So, the there would be no need check in the second foreach collider.GetComponent<Enemy>() != null, and also if there is a significant amount of non-Enemy colliders returned from the OverlapSphere call, there would be some performance increase, since the second foreach would iterate through a smaller number of elements.

avatar image ADiSiN PizzaPie · Jan 20, 2018 at 02:03 PM 0
Share

Thank you, that solve the problem x)

3 Replies

· Add your reply
  • Sort: 
avatar image
Best Answer

Answer by MaxGuernseyIII · Jan 20, 2018 at 08:50 AM

You need to decouple when the decision to do something is made from when it actually happens. That's a command pattern type problem.

I would use something like Invoke to make the speed be reset after 1.2 seconds. I believe that scheduled invoke's aren't executed if an object was destroyed in the intervening time. For instance, you could modify Enemy to have a method like SetSpeedAfterDelay that uses invoke to defer setting.

That assumes that you have access to the Enemy script. If not, you'd have to do a little more work.

In any event, I would get rid of the second foreach altogether and just schedule a command in the initial foreach.

Comment
ADiSiN
pako

People who like this

2 Show 7 · 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 ADiSiN · Jan 20, 2018 at 02:00 PM 2
Share

That's brilliant, that's really much more easier and clear in my opinion than those a mess of codes that I've created. I've tried it out and it's works good! x) Thank you!

avatar image pako ADiSiN · Jan 20, 2018 at 02:19 PM 1
Share

@ADiSiN since you tried this and it works well,I think it's more fair and helpful to other that I unaccept my answer (that you've marked best) and accept this one.

avatar image ADiSiN pako · Jan 20, 2018 at 02:32 PM 1
Share

Well, both your answers is very helpful, your answer show why there was a problem in my certain situation and how to solve it, and this answer gave another view on whole construction and how to solve the problem by changing the way of thinking. However, I've chosen yours as the best, because if other people will search for same problem as mine, then your answer will be more common for them, cos it's much more often happens that people forget to check statements. Anyway, both your answers very helpful, so ok ;)

avatar image MaxGuernseyIII ADiSiN · Jan 20, 2018 at 08:56 PM 1
Share

I'm glad you found the advice helpful. It's an application of patterns thinking.

Encapsulate that which varies.

In this case the delay and ultimate execution of the command.

avatar image pako · Jan 20, 2018 at 02:15 PM 1
Share

This IMHO is probably the best answer (I'm saying this even after the OP accepted my answer as best), especially if it had included some example code. In fact, I think that not-having example code is what prevents this answer from standing out!

So, I'll add some explanatory example code:

Enemy script:

 public class Enemy {
 
 public float speed;
 public float startSpeed;

 float slowerSlow;
 
 public void Slow(float newspeed)
 
 //existing code e.g. speed = newSpeed;
 
 //additional code
 if (newspeed = slowerSlow){
 Invoke("ResetSpeed", 1.2f);
 }

 }
 
 void ResetSpeed(){
 
 speed = startSpeed;
 
 }

If you do this you can remove the code line 24-31 form GrowingSphere.

avatar image MaxGuernseyIII pako · Jan 20, 2018 at 09:00 PM 0
Share

Enough methods like that on Enemy and speed would not need to be a public variable at all.

avatar image pako MaxGuernseyIII · Jan 20, 2018 at 10:04 PM 1
Share

Quite right! I just did a quick copy/paste for the example... didn't give any thought to that.

avatar image

Answer by pako · Jan 20, 2018 at 01:30 PM

@ADiSiN in your first foreach statement you selectively call collider.GetComponent<Enemy>().Slow(slowerSlow); to those colliders tagged "Enemy". If you have found the need to do that, it means that you suspect, or may have found, that the the OverlapSphere method returns some other colliders that are not tagged "Enemy".

And apparently, this is why your getting the NullReferenceException, not because the code inside the second foreach tries to execute a statement when there's no collider, but because a collider instance does not have an Enemy Component. So, collider.GetComponent<Enemy>() returns null, and your are trying to set the speed of null to the startSpeed of null.

So, the solution is what @PizzaPie suggested, i.e. to check if the collider has an Enemy component:

 if (collider != null && collider.GetComponent<Enemy>() != null)
Comment
Bunny83
ADiSiN
MaxGuernseyIII

People who like this

3 Show 6 · 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 · Jan 20, 2018 at 01:49 PM 2
Share

Yep, i guess that's the problem. Though a better layout of the second foreach loop would be:

 foreach (Collider collider in resetCol)
 {
      if (collider == null)
         continue;
     Enemy enemy = collider.GetComponent<Enemy>();
     if (enemy == null)
         continue;
     enemy.speed = enemy.startSpeed;
 }

Also code like the last line should be generally avoided, especially since there is already a "Slow" method on the Enemy it would be better to have a method "ResetSpeed()" in the enemy which you call inplace of enemy.speed = enemy.startSpeed;. If various different components can directly change the state of other components you quickly will loose track of who is changing what and when. That's the main point of using encapsulation. You don't have to stick to the OOP principles like they are absolute laws but more like good practises. The execution flow of methods can be followed more easily when debugging.

avatar image ransomink Bunny83 · Jan 20, 2018 at 02:08 PM 0
Share

Question: If the collider is picked up by OverlapSphere, why check if it's null? I understand the Enemy component being the culprit but it has to have a Collider on it to be in the array in the first place, right?

avatar image pako ransomink · Jan 20, 2018 at 02:25 PM 1
Share

Yes, I thought about that too. However, the 1.2s delay may be enough time for some of the colliders picked up originally by OverlapSphere to have been destroyed, and will now by null inside the array.

avatar image ADiSiN · Jan 20, 2018 at 01:56 PM 2
Share

Oh, yeah! Thank you so much, there was the problem, I wasn't pay attention that I'm creating an array of all colliders and not only colliders with certain tag. Your suggestion, as well as @PizzaPie suggestion solved it. Funny thing, that I thought about that but instead of 2 checkings I made only 1 "collider.GetComponent() != null" and it still showed me an error because I can't check for component if there is no object. Thank you x) I see your comment, so make as suggested @MaxGuernseyIII will be more efficient?

avatar image ransomink ADiSiN · Jan 20, 2018 at 02:12 PM 0
Share

If you're searching for the enemy tag then those game objects are expected to have an Enemy component on them, like @Bunny83 mentioned. I think the issue is making sure the game objects tagged "enemy" have the Enemy component attached from the inspector. So check that they do...


I think checking if the collider is null will not help because the collider was already found, hence, why it's in the Collider array...

avatar image ADiSiN ransomink · Jan 20, 2018 at 02:23 PM 1
Share

Checking if the collider is null is neccessary only in my certain situation, when I assign class array to loop array and then I wait 1.2f to make changes in it. So, there is problem - if within these 1.2f my object will be destroyed, then in my array will be hole with an empty object (I may not use correct words, sorry for that, but hope you understand). So, if not check if collider is null, then it'll throw an error, that I don't have reference, but still trying to acces to component. However, I found @MaxGuernseyIII great solution and removed second array, so now all works great. But the problem was that I didn't check for an object and an component on him as well.

avatar image

Answer by ransomink · Jan 20, 2018 at 10:48 AM

On which line is the null reference exception? That'll tell us what variable to look for. It seems resetCol could be null because you say the array is empty. This is because resetCol must have the same length as colliders, if it doesn't, then not all or any of the collided game objects will copy to the array. You have to set the length of the array first then copy it over

 resetCol = new Collider[ colliders.Length ];
 resetCol = colliders;


Also, use if (collider.CompareTag( "Enemy" ) ) instead of .tag. It is much more efficient...

Comment
Bunny83
ADiSiN

People who like this

0 Show 4 · 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 · Jan 20, 2018 at 01:38 PM 2
Share

Your first part is nonsense. An array is a reference type. Assigning one array to another variables just makes both variables reference the same array. Your code would create a new empty array, assign it to resetCol and then you overwrite the the reference with the reference to the array stored in colliders. This will cause your newly created array to be garbage collected.

avatar image ransomink Bunny83 · Jan 20, 2018 at 02:04 PM 0
Share

Yeesh, you could have easily said, "This will not work as your method only creates an empty array and overwrites it causing the new array to create garbage." or something. Sounds a bit harsh to someone trying to help. I'm used to OverlapSphereNonAlloc where you have to initialize the array with a set number to make sure you grab all possible colliders. Guess I shouldn't help people at 5 am and sleep instead....

avatar image MaxGuernseyIII ransomink · Jan 20, 2018 at 09:05 PM 0
Share

I think @Bunny83 didn't mean "gibberish" I think @Bunny83 meant "could safely be optimized to a no-op". Maybe.

avatar image ADiSiN · Jan 20, 2018 at 01:57 PM 0
Share

Thank you for answer, but no, as said @Bunny83 there isn't problem with my lenght, however, thank you for information about CompareTag. I didn't know it ;)

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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

436 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 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 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 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 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 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

Multiple Cars not working 1 Answer

Distribute terrain in zones 3 Answers

Unable to delete object from a list using foreach loop 1 Answer

null reference exception when I already checked if this was null 1 Answer

NullReferenceException yet Debug.Log shows nothing is null? 1 Answer


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