Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Strange behavior before and after build from the same code

Discussion in 'Scripting' started by atestizad, May 14, 2020.

Thread Status:
Not open for further replies.
  1. atestizad

    atestizad

    Joined:
    Apr 16, 2020
    Posts:
    8
    using prefabs for these buildings and each building has a script that detects the collision and displays its label.

    On the editor works correctly but when I build it, it works like a toggle. building 1 collided but building 2 labels will display etc.

    I have no idea why unity should behave differently before and after the build.

    the video posted on reddit -> https://www.reddit.com/r/Unity3D/co..._the_build/?utm_source=share&utm_medium=web2x

    [EDIT]
    Another problem that I found and I guess it's highly related to the prefab that I created.
    When I drag the prefab directly to the scene more than once, the second shop scene's name will change to "shop (1)", this is the issue for my code in collision_detection.cs at Awake() because will return null from the "parent.GetComponent(parent.name);".

    When I'm using "prefab brush" this issue doesn't exist because of both of the added shop scenes labeled as "shop" "shop". But the problem here is on the editor (play mode) works perfectly and after build doesn't. (as is shown in the video)!

    [Prefab hierarchy]
    shop // shop.cs attached
    --sprite
    --door //collision_detection.cs attached
    --signboard //canvas

    [Snippet]

    Code (CSharp):
    1.    
    2. /*
    3.     shop.cs
    4.     attached to the shop object (the parent).
    5. */
    6. public class shop : MonoBehaviour {
    7.     signboard = GameObject.Find("signboard");
    8.     signboard.SetActive(false);
    9.    
    10.     public void collision_enter(string part, Collider2D collision) {
    11.         signboard.SetActive(true);
    12.     }
    13. }
    14.    
    15. /*
    16.     collision_detection.cs
    17.     attached to the "door" object under the shop prefab.
    18.     the shop scene assigned to the "public GameObject parent;".
    19. */
    20. public class collision_detection : MonoBehaviour {
    21.     public GameObject parent;
    22.     private Component parent_component;
    23.    
    24.     private void Awake() {
    25.         parent_component = parent.GetComponent(parent.name);
    26.     }
    27.     private void OnTriggerEnter2D(Collider2D collision) {
    28.         parent_component.GetType().GetMethod("collision_enter").Invoke(parent_component, <parameters>);
    29.     }
    30. }
    31.  
     
    Last edited: May 14, 2020
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,151
    Show your code. We can't really help you without seeing more information.
     
  3. atestizad

    atestizad

    Joined:
    Apr 16, 2020
    Posts:
    8
    i've updated my question, please check it again
     
  4. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,151
    So, I'll address why the behavior is different first. GameObject.Find runs and finds the FIRST active object with the name that matches and returns that always. In the case of the editor, you are getting lucky. The first shop just happens to run it's code first and finds it's own signboard and then it turns that signboard off. Thus the second shop skips over that signboard and happens to land on it's own.

    In the build, the second shop is running it's code first and finding the first shops signboard and then turns it off, so the first shop ends up finding the second shops signboard.

    Instead of using GameObject.Find, make the signboard variable public and set it up on your prefab by dragging the signboard into the slot. Thus when you instantiate the shop prefab, the signboard for that shop is already setup. You can then get rid of that GameObject.Find code.

    So to clarify, if you have 2 shop codes with code running in Awake or Start, you have no idea which shop code runs first, thus your mixed behavior.

    Now, the other issue. You should not use parent.GetComponent(parent.name). Let me rewrite this code for you...(note I'm typing this quickly in the forum, so might contain small typos)

    Code (CSharp):
    1.  
    2. private shop parent_component;
    3. private void Awake() {
    4.         parent_component = GetComponentInParent<shop>();
    5.     }
    6.     private void OnTriggerEnter2D(Collider2D collision) {
    7.         parent_component.collision_enter("someString", collision); //Not sure what you are passing values in to use.
    8.     }
    See how much cleaner that looks and it doesn't count on the parent name to be the script name. You now have compiler time error checking and it's less error prone to the parents name accidentally being changed.

    Also note you could just as easily make parent_component public and drag and drop the shop into it as well, but I'm just showing you a better way to do it the way you were trying to.
     
    Last edited: May 14, 2020
    nilsdr likes this.
  5. atestizad

    atestizad

    Joined:
    Apr 16, 2020
    Posts:
    8
    ok, this can be done and thanks for highlighting.

    Well, i can't do this way because the "collision_detection.cs" used for Car & Shop & some other things so it's not static to know it's either <shop> or <car> etc.

    Since the shop scene is a GameObject, I can't assign it as a Component type. but with the existing code(just change the private to public) I saw that the shop's script placed in the inspector. Let's talk about this later on...

    [Tried]
    I've tried to use "GetInstanceID()" and name the shop's name to the id as a string. it worked but when I used "parent_component = parent.GetComponent(parent.name);" I got an error like the name cannot be anything else than "shop", idk why...

    how can we get the GameObject / component by its unique ID in general? i only seen getting via type or sting(the name of it) nothing like getting by its instanced ID...
     
  6. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,151
    If you don't know if it's shop or car, I suggest you implement an interface instead or a base class. But with interfaces, you could just use

    Code (CSharp):
    1.  
    2. public ICollision parentCollision;
    3.  
    4. parentCollision = GetComponentInParent<ICollision>();
    Then it doesn't matter if it's a car, shop, donkey, mutant shark. If it implements the interface, it will work. Then your variable type is the interface instead.

    You can drag and drop a GameObject with a shop script on it into a shop variable and it works fine. Your shop may be a GameObject, but your components make up that GameObject. But instead use the interface setup.
     
    nilsdr likes this.
  7. atestizad

    atestizad

    Joined:
    Apr 16, 2020
    Posts:
    8
    can't get this to work. ICollision isn't valid on my side.

    however, after replacing "parent.GetComponent(parent.name);" from Awake to TriggerEnter function, works as expected both on the editor and built version. But again, I'm not sure this will create another issue or not.

    But now after adding the Car object to the scene by LoadScene, the static rigidbody2d collision totally gone(as if there is no rigid body and collision) again on the built version, not the editor.

    remember that the collidion_detection.cs used in the car object with exactly the same hierarchy as the shop.
     
  8. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,151
    It's because you didn't make the ICollision interface, did you? I didn't do all the work for you, I gave you an example of how to do it. I'm helping you along and not giving you all the answers straight up.

    I expected you to look up interfaces and how to make one and implement it.
     
Thread Status:
Not open for further replies.