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

Tranform Find on inactive Panel

Discussion in '2D' started by piggybank1974, Dec 17, 2016.

  1. piggybank1974

    piggybank1974

    Joined:
    Dec 15, 2015
    Posts:
    621
    Does this sound like a bug to you all?

    Now we all know that if your GameObject is inactive you cannot use GameObject.Find, to err!! find it, but you can use transform.Find, this does work.

    I tried the same idea with a Panel and it does not work surely this must be a bug of some sort??

    Edited
    I forgot that it's a RectTransform, not a Transform, although there is NO Find on a RectTransform how you supossed to find a inactive Panel then??
     
    Last edited: Dec 17, 2016
  2. PGJ

    PGJ

    Joined:
    Jan 21, 2014
    Posts:
    899
    RectTransform inherits from Transform, so there is a Find method in it.
     
  3. piggybank1974

    piggybank1974

    Joined:
    Dec 15, 2015
    Posts:
    621
    Yes, it does inherit but no find is available, you try it, RectTransform find not there, I think they expect panel etc to be visible when the scene loads, e.g. you don't turn them off in the inspector and then run your scene. And on the gameobject you setactive to false.
     
  4. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807

    Attached Files:

  5. piggybank1974

    piggybank1974

    Joined:
    Dec 15, 2015
    Posts:
    621
    what I'm trying to do is find an inactive HUD(Head Up Display) which is a series of UI Elements, get the GameObject from it and later on make it active using SetActive, you can do this easily with transform.Find, I'm using myself for a gameobject but it's the recttransforms are the problem.

    What I have that works is this, but I cannot with the following make it inactive

    Code (CSharp):
    1.  
    2. mHUDComponent = GameObject.Find("HUD").GetComponent<HUDComponent>();
    3. mHUDComponent.gameObject.SetActive(false);
    4.  
    What I've tried so far

    I've tried to unbox the transform into a RectTransform, not a great lover of as casting but in this instance, it feels better, than the usual way.

    Code (CSharp):
    1.  
    2. RectTransform mTemp = ((RectTransform)this.transform).Find("HUD") as RectTransform;
    3.  
    what I get from the follow is this:

    InvalidCastException: Cannot cast from source type to destination type.
    Scenes.LevelSceneComponent.Awake () (at Assets/Scripts/Components/Scenes/LevelSceneComponent.cs:73)

    So that does not work, there is no this.recttransform, so I'm a little unsure how to retrieve the UI element in this instance

    got any pointers.
     
    Last edited: Dec 19, 2016
  6. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Try this:
    Code (CSharp):
    1. RectTransform hudTransform;
    2.  
    3. Transform hudObject = transform.Find("HUD");
    4.  
    5. if(hudObject != null)
    6. {
    7.     hudTransform = hudObject.GetComponent<RectTransform>();
    8.  
    9.     // or
    10.     hudTransform  = (RectTransform)hudObject; // will error on failure
    11.  
    12.     // or
    13.     if(hudObject is RectTransform)
    14.     {
    15.         // will assign null on failure (but won't fail because we check first)
    16.         hudTransform = hudObject as RectTransform;
    17.     }
    18. }
    There's lots of ways to cast or get the correct type, just make sure you're checking the results of anything that is potentially returning null.
     
    Last edited: Dec 19, 2016
  7. piggybank1974

    piggybank1974

    Joined:
    Dec 15, 2015
    Posts:
    621
    On a RectTransform object what you subjected does not work, I've tried it you would think it does but it does not, for some reason if the UI Element is inactive you cannot retrieve it.

    if it's a GameObject which has a transform you can, try it, if I'm wrong I apologise unreservedly, I'm sure this is a bug??
     
  8. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    I just created a new scene with a Canvas with a Button underneath it. I set the Button GameObject to inactive, and ran this script on the Canvas:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class NewBehaviourScript : MonoBehaviour {
    6.  
    7.     // Use this for initialization
    8.     void Start () {
    9.         Transform child = transform.Find("Button");
    10.         if(child != null) {
    11.             print("ok");
    12.  
    13.             RectTransform rect = child.GetComponent<RectTransform>();
    14.             if(rect != null) {
    15.                 print("ok");
    16.             } else {
    17.                 print("not ok");
    18.             }
    19.  
    20.         } else {
    21.             print("not ok");
    22.         }
    23.     }
    24. }
    I've attached a screenshot of the setup and console output. This appears to be working fine.
     

    Attached Files:

  9. piggybank1974

    piggybank1974

    Joined:
    Dec 15, 2015
    Posts:
    621
    Interesting I've not attached my script to the canvas it's on a separate GameObject in the scene have you tried that??

    What version are you using I'm on 5.4.1f1, with a plus account, not that, that should make a difference.
     
  10. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    If your script is on a separate gameobject, using "transform.Find" will not find anything other than children of that transform as you may know.

    I see above you're using "GameObject.Find" which is likely the issue, GameObject.Find will not find inactive objects. Sorry for any misunderstanding there, I thought your main question was about the behavior of transform.Find with RectTransforms.

    One solution would be to give your HUD a parent object which is never disabled, then find that object instead. Another solution would be to create a variable reference to your HUD and assign it in the inspector beforehand.
     
  11. piggybank1974

    piggybank1974

    Joined:
    Dec 15, 2015
    Posts:
    621
    Like I said, at the moment it's NOT inactive that's why I'm using GameObject, I was lead to believe that GameObject/Transform.Find, looks for ALL gameobjects/tranforms with that Name, it's not particular if it's in this hierarchy not, I say this because I had two GameObjects with the same name and it picked up the wrong one, so I used forward slashes e.g. "parent/child" etc etc.

    Edited:

    Are I forgot the thing I just mentioned was the reason it found more than a single object of that name was because the script was in the parent so it would, well that explains everything,

    the more experience I get in unity the less I know :)
     
    Last edited: Dec 19, 2016
  12. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    GameObject.Find will find the first object of that name that it comes across in the entire scene.

    transform.Find (note the lowercase transform) will find the next child object of the given name or path name within that transform's hierarchy.

    As far as I know GameObject.Find doesn't work with the slash notation to traverse hierarchies, but transform.Find does.

    There is no static method Transform.Find. Thru the Transform class you will only find Object level functions as with any class inheriting from Object.

    I'm a little unclear on what the remaining question is at this point. I've given you a few solutions here, your original post said that you were having trouble using transform.Find to get an inactive Panel object, but now you're starting it active and trying to use GameObject.Find with a path?

    Hopefully my explanations of those methods clear up any confusion you might be having with how they work.

    Ideally you can avoid using Find altogether by storing variable references to important GameObjects in the editor. The main problem with those methods is that you're searching based on GameObject name, which may have many duplicates, or typos, and are subject to change at any time.
     
    Last edited: Dec 19, 2016
  13. piggybank1974

    piggybank1974

    Joined:
    Dec 15, 2015
    Posts:
    621
    I've just been fiddling (thanks for your great idea by the way). GameObject.Find will work with Slashes I'm using them, I did find that if you do have more than one GameObject with the same name it will fail if you use Find. for example I now have a parent object called Dialogs then Background, but in the scene I already have a GameObject called Background so it failed by using GameObject.Find("Dialogs/Background"), it found the dialog background.

    Because I have 4 Dialogs (ability/abilities/level/complete) + the background for the dialogs which is just a black panel with transparency as long as I put the script on the Dialogs gameobject which will NOT be inactive I should be able to find the inactive dialogs plus the background, I'll try this tomorrow.

    I'm not a fan of using the editor for drag and drop it looks messy and if your not going to change anything why bother in the first place, I'm a coder, I'll decide what I want not the unity developers, things like this are for inexperienced developers, and if your using your own map editor, you cannot use things like this anyways or at least fully.

    thanks again @jeffreyschoch good to talk with you again.

    Edited:

    Having the code on a single object will not work for me as it inherits from my abstract base DialogComponent, I'm getting tired need some shut eye, I'll sleep on it and work it out tomorrow.
     
    Last edited: Dec 19, 2016
  14. RockyWallbanger

    RockyWallbanger

    Joined:
    Mar 16, 2014
    Posts:
    85
    Not that this is necessarily the place, but I have to disagree with your statement...
    It may not be your preferred method, but it's a big part of the Unity toolset. To call a person inexperienced for using the tools available in the prescribed way isn't constructive. Plenty of other Unity developers would argue that GameObject.Find is for "noobs" and not to use it for example. The great thing about Unity is that there are a number of ways to get the exact behavior you're looking for, but outright dismissing one perfectly acceptable solution as "for inexperienced developers" won't ingratiate you to getting more help.
     
  15. piggybank1974

    piggybank1974

    Joined:
    Dec 15, 2015
    Posts:
    621
    First I was not having a go as you like to believe, I've worked on many systems over the years, and I've always found that, having tools will only go so far(why do we build custom controls?), or the developers of that system have only allowed you to go so far, if you want to go a little off that track that they have laid down, it becomes more difficult to use the tools or impossible, I'm a supporter of their technology because I willingly pay a monthly subscription too the cause.

    A drag and drop system is only good if things on that system are not changing for example(say health at that you will know is there) if your creating a level with monsters etc this will not work to many developers thinking public for everything, this is not always the answer, only make it public if you need access to that object somewhere else(you should hide as much implementation as possible) although in most situations you could use an event that will fire to inform another class or classes I have something for you(if you want feedback that is), I'm what they call an old style programmer.

    You say GameObject.Find is for noobs, I'm only aware in scripting that you can only use GameObject.Find/transform.Find to find the objects you want if that's not the case, why have you not said so, I can see you joined in 2014, now have 14 posts to your credit, I'm not here just to take and run, I want to help users on this forum, just as I've done on others forums with other languages, it's one of the things I enjoy very much, I don't just reply I post code snippets, even whole projects if I have the time, if I feel it will help others gain knowledge, I gladly will do so.

    What I'm trying to say is the tools are good but don't over use them, alternatives are there and might be a better solution, does that variable really need to be public even if you as the developer are only the person that's going to see it?

    Yes GameObject.Find/transform.find is slower but if it's used in the correct manor say in an awake method the time is negotiable, and it might be the only solution you have.

    nice to talk to you anyways.
     
  16. RockyWallbanger

    RockyWallbanger

    Joined:
    Mar 16, 2014
    Posts:
    85
    I wasn't trying to "have a go" with you, I just don't want other less experienced developers to read what you wrote about the toolset Unity provides and get the idea that the inspector is bad and is to be avoided. I also wasn't condemning GameObject.Find, merely pointing out that what you said about drag and drop in the inspector, plenty of others have said about GameObject.Find. The real trouble with GameObject.Find isn't the speed of the method, but more importantly it's violation of SOLID principles. That's not to say that it should never ever be used.

    If your sticking point on using the inspector is that the field is public, just make the field private and use the [SerializeField] tag. I don't follow what you mean by "a drag and drop system is only good if things on that system are not changing." As for replacing GameObject.Find, there's really nothing in .NET that you can't use. IoC containers, a messaging system (as you mentioned), a manager class, etc... Whatever object referencing methods you're used to in .NET will generally work in Unity. But if you're relying on the Unity editor to create and compose your objects, why not just use the inspector for your references also? Personally, I

    I'm sorry if my post came off as abrasive, it's not what I was going for. Also, I'm not here to take and run either. Regardless of how many posts I have, every single one of them have been me trying to help someone else with the lessons I've learned from my experience and this community.
     
  17. piggybank1974

    piggybank1974

    Joined:
    Dec 15, 2015
    Posts:
    621
    fair enough point taken, I agree about the inspector, Unity is a system what you would call 4G, clarion years ago was very similar but did not catch on much, I'm assuming using the inspector/GameObject.Find is the same result.

    I'm assuming you mean by solid principles, it's the way that unity thinks you should use it(although if you look at the tutorials they can contradict themselves), the inspector is great for lets say a player that will not change, e.g. my game(I should say the original game), has 4 distinct players, some share parts some don't, do you think it would be wise to create 4 prefabs, or create one, and use XML/json or binary for that matter set there characteristics, It gets worse when again you have 7 monsters all similar but slightly different, even all the bonus items are all different in someway that's why what I meant in not using the inspector, my joystick for example I use the inspector.

    In the new game I have a load of UI Elements, I'm referencing the UI elements in code not the inspector, you could argue that the inspector is the correct solution, and you might be correct, it's hard to teach an old dog new tricks, may be I'm just comfortable in my fluffy slippers and granny jumper, I say let a coder be a coder.
     
  18. RockyWallbanger

    RockyWallbanger

    Joined:
    Mar 16, 2014
    Posts:
    85
    When talking about SOLID I'm referring to the rules to strive for to keep your code maintainable and extensible. Specifically the O part (Open-Close Principle). If for some reason the name of your gameobject that you're trying to find in GameObject.Find changes, you'd need to change it everywhere. For the multiple monsters and players you could use ScriptableObjects. Even if you used a single prefab, you could still set the reference in the inspector and change the characteristics via XML etc... If you're instantiating them via code then you already have the reference.

    I'm not trying to change you, by all means, code away.
     
  19. piggybank1974

    piggybank1974

    Joined:
    Dec 15, 2015
    Posts:
    621
    My game is already released, I didn't use ScriptableObjects, as they need to be connected to gameObjects, actually I use a base class system, I proffer that over an Interface for this as they are all deriving from the same structure EntityBase

    I only use a single prefab(for monsters), probably could of used an empty gameobject and added all I needed but, I was new at unity so a followed what I understood.

    I manually add the script, again I probably should of added this into the inspector, but as I needed a reference to the object so I could set other fields I thought, what's the point, is it faster slower I'm not sure.

    it also uses an events system, because I come from pure .NET(winforms etc), I've been around multi threading and events for years so I understand them, so basically all monsters for example call a single method if they hit the player, even the player for bullets uses the same system as some monsters if the fire bullets, I just use typeof to return their component(object script) type and go from there.

    I was making an effort to keep the APK file as small as possible, I think it's 24mb at the moment with about 20 sprite sheets, plus animations, sound etc, and 60+ levels that's not bad, in this version the levels are XML I know really bad, but I had not upgraded the map editor for binary at that time, now it can do both.

    I did notice something, if you have an upgraded account, when you compile for release it shaved about 1.5mb of the APK compared to the personal version.

    I come from the old school like I said where size mattered, so I make effort to decrease the end file result as much as I can, using Tinypng or Tinyjpg, can shave off huge amounts of image size, with zero reduced quality.

    I've enjoyed this conversation hope others have too, It just goes to show, how flexible unity is, and how different people use it.