Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

program can't detect collision in the main script

Discussion in 'Scripting' started by imposter_syndrom_incarnated, Sep 25, 2020.

  1. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    Hello,
    In my program the order of execution is wrong:

    What I want:
    1. the card is added to the array
    2. boolean inside the OnTriggerEnter2D, a method that exists for each card prefab is updated
    3. updated boolean value is imported in my main script where the cards are being generated

    What is happening
    1. the card is added to the array
    2. not upated boolean value is imported in my main script where the cards are being generated
    upload_2020-9-25_17-4-17.png

    3. boolean inside the OnTriggerEnter2D, a method that exists for each card prefab is updated
    upload_2020-9-25_17-5-27.png


    During the running of the program as you can see, the OnTriggerEnter2d is the last to be updated:
    upload_2020-9-25_17-7-51.png

    How do I change the order of this behaviour?

    There is a method inside my main class, which generates the cards on the screen one by one in random order, called Overlap. The method that concerns us:
    Code (CSharp):
    1. public IEnumerator Coroutine()
    2.     {
    3.         //coroutine
    4.         WaitForSeconds wait = new WaitForSeconds(1f);
    5.  
    6.         int randomItemFromListIndex;
    7.         GameObject randomItemFromList;
    8.  
    9.         for (int i = 0; i < numToGenerate; i++)
    10.         {
    11.             //where to generate
    12.             xRandomPos = Random.Range(borders.bounds.min.x, borders.bounds.max.x);
    13.             yRandomPos = Random.Range(borders.bounds.min.y, borders.bounds.max.y);
    14.             finalRandomPos = new Vector3(xRandomPos, yRandomPos, 0f);
    15.          
    16.             //what to generate
    17.             randomItemFromListIndex = Random.Range(0, listOfObjects.Count);
    18.             randomItemFromList = listOfObjects[randomItemFromListIndex];
    19.          
    20.             var gameObject = Instantiate(randomItemFromList, finalRandomPos, Quaternion.identity);
    21.          
    22.             //to detect collision
    23.             NewlistOfObjects.Add(gameObject);
    24.          
    25.             var hit = gameObject.GetComponent<CollisionCards>().collided;
    26.          
    27.             print("not updating inside the Overlap class: " + hit);
    28.             yield return wait;
    29.         }
    30.      
    31.     }
    The problem is that hit is not referring to the the script that is attached to every card prefab, which is simply:
    Code (CSharp):
    1. public class CollisionCards : MonoBehaviour
    2. {
    3.     public bool collided;
    4.     void OnTriggerEnter2D()
    5.     {
    6.         collided = true;
    7.         print("updating inside the Card: " + collided);
    8.  
    9.     }
    10. }
    I have a NewlistOfObjects in my Overlap class because I wanted to add in it only the cards that do not collide with each other. I noticed however that my Overlap class does not ever detect the collision as it seems unable to reference the script attached to the cards even though I use GetComponent in this manner:
    Code (CSharp):
    1.             var hit = gameObject.GetComponent<CollisionCards>().collided;
    2.  
    How can I make my main class detect the collision?
    Any suggestion would be very much appreciated :)
     

    Attached Files:

    Last edited: Sep 25, 2020
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,888
    Can you back up a bit and explain what's going on here? I feel like I just started watching a movie halfway through and don't know any of the characters or the story so far.

    Currently, I'm really confused by your explanation. Missing a huge amount of context. Where is this code? Is it on CollisionCards? Some other script? Inside of which function? Update()? OnCollisionEnter2D()?
     
  3. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    Thank you for getting back :) I have updated my main question as well.
    There is a method inside my main class, which generates the cards on the screen one by one in random order, called Overlap. The method that concerns us:
    Code (CSharp):
    1. public IEnumerator Coroutine()
    2.     {
    3.         //coroutine
    4.         WaitForSeconds wait = new WaitForSeconds(1f);
    5.  
    6.         int randomItemFromListIndex;
    7.         GameObject randomItemFromList;
    8.  
    9.         for (int i = 0; i < numToGenerate; i++)
    10.         {
    11.             //where to generate
    12.             xRandomPos = Random.Range(borders.bounds.min.x, borders.bounds.max.x);
    13.             yRandomPos = Random.Range(borders.bounds.min.y, borders.bounds.max.y);
    14.             finalRandomPos = new Vector3(xRandomPos, yRandomPos, 0f);
    15.          
    16.             //what to generate
    17.             randomItemFromListIndex = Random.Range(0, listOfObjects.Count);
    18.             randomItemFromList = listOfObjects[randomItemFromListIndex];
    19.          
    20.             var gameObject = Instantiate(randomItemFromList, finalRandomPos, Quaternion.identity);
    21.          
    22.             //to detect collision
    23.             NewlistOfObjects.Add(gameObject);
    24.          
    25.             var hit = gameObject.GetComponent<CollisionCards>().collided;
    26.          
    27.             print("not updating inside the Overlap class: " + hit);
    28.             yield return wait;
    29.         }
    30.      
    31.     }
    The problem is that hit is not referring to the the script that is attached to every card prefab, which is simply:
    Code (CSharp):
    1. public class CollisionCards : MonoBehaviour
    2. {
    3.     public bool collided;
    4.     void OnTriggerEnter2D()
    5.     {
    6.         collided = true;
    7.         print("updating inside the Card: " + collided);
    8.  
    9.     }
    10. }
    I have a NewlistOfObjects in my Overlap class because I wanted to add in it only the cards that do not collide with each other. I noticed however that my Overlap class does not ever detect the collision as it seems unable to reference the script attached to the cards even though I use GetComponent in this manner:
    Code (CSharp):
    1.             var hit = gameObject.GetComponent<CollisionCards>().collided;
    2.  
    How can I make my main class detect the collision?
     
  4. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,888
    One really confusing thing is you have a variable called
    gameObject
    which hides the
    gameObject
    property that is normally present on MonoBehaviours. That's quite confusing because it looks like you're calling GetComponent on your main script object instead of the spawned card. I would rename that variable to avoid confusion.

    I'm not sure collisions will be detected immediately when you spawn the object... It might have to wait for the next FixedUpdate. Out of curiosity, if you add this, does it work?

    Code (CSharp):
    1.             NewlistOfObjects.Add(gameObject);
    2.  
    3.             yield return new WaitForFixedUpdate();
    4.             var hit = gameObject.GetComponent<CollisionCards>().collided;
     
  5. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    hey, thanks, I tried to change the name of the gameObject but it doesn't seem to have changed the situation.
    Shall I remove
    Code (CSharp):
    1. yield return wait;
    and substitute it with
    Code (CSharp):
    1. yield return new WaitForFixedUpdate();
    ?

    I don't have a FixedUpdate() or Update() in my code :(
     
  6. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,888
    No. I was suggesting adding the new yield statement right after the instantiate call before checking for the collision.
     
  7. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    I think it detected it! I can't thank you enough! :D
    Could you kindly explain why the addition of that line changed the situation?
     
  8. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,888
    If you look at this diagram you will see: https://docs.unity3d.com/Manual/ExecutionOrder.html

    OnCollisionXXX methods don't happen until the physics part of that loop. So when you instantiate your object, the collisions won't be detected until the game loop gets to that physics update section. So you need to yield WaitForFixedUpdate, which happens at the end of the physics update (also shown in the diagram).
     
  9. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    thank you :)
    I have an important related question, if I try to hide the object, does it not detect future collisions anymore? It doesn't seem to detect it when I run the program. Could you please recommend another way to hide the object when instantiated in a manner that it still detects the collision?
    upload_2020-9-25_21-48-18.png
     
  10. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,888
    if you deactivate the GameObject, it disables ALL components on that object, including the collider. So yes, it will no longer detect collisions. Instead, you should disable only the renderer component to make it invisible but leave the object activated:
    Code (CSharp):
    1. gameObject.GetComponent<Renderer>().enabled = false;
     
  11. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    Thank you so much! :oops::oops::oops: I really wish to learn scripting on unity better. I have practice on C# but I noticed that scripting on Unity with C# is a bit different, for example I didn't happen to use properties with getters and setters or any constructors yet. Do you have any recommendations with any books, or playlist that I could go through to learn scripting on Unity better?
    Thank you again!
     
  12. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,888
    Sorry I don't have any recommendations for you. I usually just learn by doing.

    I think it's a good idea to learn C# on its own outside of the context of Unity. Otherwise you will fall into some bad habits. The language itself is not any different. The difference just comes from Unity's data model (GameObjects/Components/Scenes) and the way your code gets invoked from the engine through callback methods (Start, Update, etc..).
     
  13. imposter_syndrom_incarnated

    imposter_syndrom_incarnated

    Joined:
    May 1, 2020
    Posts:
    51
    Thank you for everything :)