Search Unity

Getting Collider Reference On Non-Active GameObject

Discussion in 'Getting Started' started by Bill_Martini, Sep 20, 2016.

  1. Bill_Martini

    Bill_Martini

    Joined:
    Apr 19, 2016
    Posts:
    445
    I'm working on a 3D first person shooter. The player has a force shield that can be activated by user key press. Enemies shoot at player and if force shield is active, bullets are destroyed. There are also super enemies that shoot super bullets that are able to pierce the force shield.

    This is a perfect opportunity to use Physics.IgnoreCollider (from an early post). I instantiate my bullet prefab and I need to set it to ignore a particular collider. IgnoreCollider requires two collider references. Obviously I can get the reference to the bullet, but the other is the force shield, that is not active, or may not be active.

    How can I get a reference to the force shield collider when it is not active? I'm getting a null reference error.
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    How are you trying to get the reference to the force shield collider? You're probably using something like transform.Find, which yeah, doesn't work with inactive objects.

    But if you give your script a public Collider property, and just drag your force shield object into that slot in the editor, then it's got the reference whether the collider is active or not.
     
    Kiwasi likes this.
  3. Bill_Martini

    Bill_Martini

    Joined:
    Apr 19, 2016
    Posts:
    445
    Hey thanks Joe,

    Well, yes I've tried using transform.Find and that doesn't work as you point out. But I have also tried making a public Collider property and dragging object into the slot as you suggest. I've also tried a public GameObject. I can't seem to drag the object from the hierarchy into the slot on the script. It does not want to accept it. Clicking on the target widget just shows None in the inspector window. And this is why I posted the question. I assumed there was a different approach, but your suggestion of making a public property seemed the way to go for me too.

    I'm thinking this is a scope issue, but I don't understand why or how items in the inspector can be out of scope with each other. How do I fix this?
     
  4. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    The only time i see that sort of behavior is if you are trying to attach something in the scene to a prefab in the project tab.

    Can you post a screenshot of what you're trying to drag where?
     
  5. Bill_Martini

    Bill_Martini

    Joined:
    Apr 19, 2016
    Posts:
    445
    Ok, this gets more bazaar... Since I'm struggling to attach a reference to a game object component into a slot on the script of my bullet prefab, I decided to bring the prefab into the hierarchy, break the prefab, and add the shield game object into my script slot. That worked. I save Scene and Project and drag the bullet game object back into the Project, the slot on the new prefab script where the shield object reference was now shows None. Creating the prefab broke the reference. I guess I could make a whole new bullet object, add the components, and create a new prefab from that, but I don't have faith that the shield reference will be retained as breaking the prefab should be an equivalent and that didn't work. This is not making sense.

    I'm wondering if I need to leave the shield object active and turn off and on the collider and meshrenderer, that way I can use Find from my original attempt.
     
  6. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    OK, let me make it simple: you can't take something from the scene (Hierarchy tab), and assign it to a slot on a prefab (Project tab).

    This is because prefabs don't live in the scene. They live in the project. They might be used in dozens of other scenes, which don't have the scene object you're thinking of. So such an assignment would not make sense, and is not allowed. You can't do it.

    Now, what you can do is take a prefab, and drag it into your scene, making an instance of that prefab in your scene. And then you can assign another scene object to a slot on that instance. That's because they're both in the scene.

    You can also assign a prefab to the slot of another prefab. That's because they're both in the project.

    And finally, you can assign a prefab to a slot of an object in the scene. That's because prefabs, in the project, are available to all scenes. So there's no problem.

    But trying to assign a scene object to a slot in a prefab? No can do!
     
    Kiwasi likes this.
  7. Bill_Martini

    Bill_Martini

    Joined:
    Apr 19, 2016
    Posts:
    445
    Thanks Joe,

    I have painfully discovered thru trial and error that what you described in you last reply is true. This is also why I started this post. I'm back to asking the original question.

    How do I get a reference to a collider of an inactive game object? Once the bullet is instantiated, it is part of scene, but the object I need to get is most likely not active.
     
  8. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Because the bullet is a prefab, it can't have a reference (as a prefab) to the game object. But whatever's spawning that bullet is part of the scene, isn't it? So that can have a reference to that inactive collider thingy. And when it spawns the bullet, it can assign that reference to the appropriate slot on the bullet at that time.

    In short: put this collider-ignoring logic in the gun, not in the bullet.
     
    Kiwasi likes this.
  9. Bill_Martini

    Bill_Martini

    Joined:
    Apr 19, 2016
    Posts:
    445
    Thanks Joe, I appreciate your tenacity,

    My enemy player does not have a gun object and I'm instantiating the bullet from a script on the enemy object itself. Sadly the enemy is also a prefab. I had thought of this a while back before I understood what I can do and what I can't.

    I've even gone farther... I created a public var for the shield game object in my game manager script. In that script I create a static public collider var that I store the shield collider component. My bullet script looks up the game manager script and gets the collider. Mondo convoluted but does not cause any errors and also does not work! Not sure why again. Maybe what I'm doing is creating a copy and not referencing the real item.

    I know I've said this before, this seems like a common scenario, why isn't there an elegant solution for this? At this point I think I have tried all possible solutions available to me in this vein. I'm going to have to establish a complex layering methodology and set the Collision Matrix to not allow a collision.
     
  10. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    No you're not. You're right, needing to find a reference to another object is a common problem, and there's always a reasonable solution.

    In this case, going through the game manager seems like a reasonable solution. And it should work (and shouldn't be too convoluted, either). I recommend pursuing that approach more deeply.
     
  11. Bill_Martini

    Bill_Martini

    Joined:
    Apr 19, 2016
    Posts:
    445
    Many thanks again, Joe.

    After more testing I found I can get this to work using a lookup from my game manager script that I described above. But, there's always a but... it only works if the shield object is active at spawn of a bullet. I've verified I'm getting a valid collider even with the game object not active. Somehow when setting the Ignore statement, it knows if the game object or collider is active or not. I'm using SetActive(true/false) to enable and disable the shield.

    This has been a tedious up-hill slog and each failed attempt is increasing the slope. I'm pretty sure I'm getting pretty close to a vertical wall real soon. Any suggestions.
     
  12. Bill_Martini

    Bill_Martini

    Joined:
    Apr 19, 2016
    Posts:
    445
    Ok I think I have this working. It's a mega hack and I need to more testing to be sure all works. There is an edge case that fails but it can happen so seldom I'm not going to worry about it. If a bullet is inside the shield perimeter when the shield is activated, it will be destroyed and not counted as a hit.

    On my bullet script I created a private bool var DoesIgnoreShield. On my game manager script I created a public bool var ShieldIsActive that is set to true when the shield is active and false is not. Back on the bullet script I test if DoesIgnoreShield is false and ShieldIsActive is true and I set the Physics.IgnoreCollider and also set the flag DoesIgnoreShield to true to prevent multiple setting.

    So if a bullet is instantiated while the shield is active it is set and if a bullet has been instantiated prior to the shield being active it will set itself once the shield is activated.
     
  13. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    So the first thing that jumps to mind is using layer based collisions. Simply have a shield layer, a bullet layer, and a super bullet layer. Shield and bullet collide. Shield and super bullet do not collide. This will work well enough if you only have to manage a dozen or so layers.

    The second idea that comes to mind is to use triggers. A trigger lets you perform more complex collision behaviour, as it can detect the collision without the physics system taking over. That way bullet and super bullet can detect the presence of the shield and behave appropriately.

    Long story short, I really wouldn't use IgnoreCollision for this job.
     
  14. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I'm quite surprised to hear that IgnoreCollision doesn't work with an inactive collider.

    But I suspect that your project is a bit complex, so there's a chance that something else is going on that doesn't quite match your mental model of what's going on.

    Would you be willing to take a few minutes to reproduce this in a simple project? Maybe just two objects, one falling onto the other, with the other starting out inactive while you call IgnoreCollision, and then becoming active shortly thereafter?

    This would prove your claim... and if true, I think it may be worthy of a bug report. I can't imagine why IgnoreCollision shouldn't work even when one of the colliders is inactive.
     
  15. Bill_Martini

    Bill_Martini

    Joined:
    Apr 19, 2016
    Posts:
    445
    @BoredMormon,

    While plowing thru a solution using IgnoreCollider, I've always had setting up layers for this in the corner of my eye. I would need a lot more layers to include all collider possibilities. I've also thought about using triggers, I thought I'd just be swapping a different set of problems, but maybe it would have been simpler, I don't know. Kind of moot now.

    @JoeStrout,

    After a pretty thorough testing session it gets worse... When initially testing I did not include a flag on the bullet to avoid multiple setting. When that worked, I added in the flag, but never tested. Thinking I solved the problem I reported my findings above. Now, I find when setting ignore and setting a flag to not set again, FAILS!!!!

    If IgnoreCollider is set and the shield is deactivated and reactivated the ignore is cleared and will collide with the shield. My only solution now is continually set IgnoreCollider, by dropping the flag I was using.

    Joe, you're thinking this is a possible bug, I'm thinking this is an intentional behavior, either rightly or wrongly put in by someone at Unity. But as you said there is a solution to be found, it's the digging that's the bitch.

    I've lost about four days work on this issue alone. Forward progress stopped by one issue. While testing all the various attempts to get this right, I've added to my to-do list and to-fix list has grown way larger than I thought possible. I really need to start whittling those lists down and try to get back on track. So, Joe, my question to you is; do you still feel this is a bug? There is no documentation on this behavior, which does not clarify either way. I guess my point is, do I stop my project to make a proof of behavior example only to find that behavior was intentional? I'm tired of being mired and I'm not too inclined to go off on a tangent that is questionable. You are far more experienced with Unity than am, so I'm relying on your opinion on this. Thanks.
     
  16. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    It's listed in the documentation as a limitation of IgnoreCollision. So it's not technically a bug. But it might be a good feedback suggestion.
     
  17. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I'll be dipped; so it is. I'd swear this wasn't there when I looked for it yesterday.

    OK, so not a bug, just a goofy design (or a bug they decided to document rather than fix!). Don't bother with that proof project (and I apologize for suggesting it).

    So, that means you just have to take this behavior into account — either abandon IgnoreCollision, as @BoredMormon suggests, or just be sure you re-IgnoreCollision whenever you activate the shield (which it sounds like your code was doing successfully).
     
    Kiwasi likes this.
  18. Bill_Martini

    Bill_Martini

    Joined:
    Apr 19, 2016
    Posts:
    445
    Joe, thank you so much. I didn't remember that either when I looked before I originally posted. I feel a lot better that it slipped by you too.

    All that being said, I partially blame information overload, and mostly blame insanity. My council has advised me to take the fifth (he prefers Jack Daniels, but I'm allowed to pick my own poison).

    And don't think the irony of this has slipped by me. I wanted to continue on with my project and didn't want to go off on a tangent to do a proof of behavior example, but all the while my project was stalled so I could build a proof of behavior that matches the documentation. How do I find myself in this house of mirrors? Thanks everyone.
     
    JoeStrout likes this.
  19. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    If it's any consolation, we've all been there. Here's a rabbit hole I fell down just the other day, and lost a good chunk of my morning.

    As you get more experienced, you will tend to fall less often, and reach the bottom of the rabbit hole faster... but it does still happen. All part of the adventure, I guess!