• 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
0
Question by jhell · Apr 14, 2015 at 10:33 PM · c#gameobjecttransformsingleton

this.transform.FindChild(x) and GameObject.Find(x) returning (apparently?) different results

Hi everyone,

So I'm a long time lurker (my first post!), and these forums are a great resource, but this problem is puzzling me. Let me put you in context:

  • I have 2 scenes (Game and Upgrade)

  • Between these 2 scenes, the Player gameObject travels as a singleton, carrying with him a bunch of children, among which weapons. It goes like: Player/WeaponFamily/WeaponName

  • In the Upgrade scene, I have a button that sets a Weapon to an "equipped" status. Upon re-entering the Game scene, I check which weapon has the "equipped" status true and assign it to the Player's weapon variable.

Here is the code in the Game scene that checks which weapon is equipped and assigns it to the player:

 // Find which weapon is equipped and actually equip it
 Weapon[] weapons = transform.GetComponentsInChildren<Weapon> ();    
 foreach (Weapon w in weapons)
 {
     if (w.IsEquipped()) {weapon = w; break;}
 }

This finds that all weapons have the "equipped" flag set to False. However, the editor clearly shows me that I do have a weapon with an "equipped" status to true:

Weapon has equipped to true!

This is what I see in the editor upon exit of the Upgrade scene: it means my changes there were saved to that specific Weapon's script.

However, and this is what I don't get, if I use this code:

 Weapon[] weapons = GameObject.Find ("Gun").transform.GetComponentsInChildren<Weapon> ();
 foreach (Weapon w in weapons)
 {
     if (w.IsEquipped()) {weapon = w; break;}
 }

It works!

I have thought that maybe I wasn't removing properly the Children for the singleton Player gameObject, but I tried to specifically remove them all and still the same error happens (that "weapon" is null).

Obviously I could go on using the working code, but I can't see the difference between the 2 and I don't get why one works and the other no, so if anyone knows what I'm doing wrong, he'd be very welcome :)

Thanks for reading and sorry for the long post!

Edit: for list formatting and title

capture.png (79.0 kB)
Comment
Add comment · Show 9
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 NoseKills · Apr 14, 2015 at 10:51 PM 2
Share

You could try to debug this further by printing out the `InstanceID` of the components you are referencing to verify which objects are found with which calls. If you Log the InstanceIDs also in the Awake() of the gun scripts, you might get a better idea of what's happening.

To make this easier, you can make the instanceID visible in the inspector by going into debug mode (top right options above inspector tab)

Once or twice I've had similar(ish) problems where Find methods are returning objects that seem to linger in some limbo after scene change/Destroy() call because I'm still referencing them from somewhere or I'm calling Find too quickly after Destroy() (it's not instant).

Whatever the case, since transform.Find() only loops the children of a certain object ins$$anonymous$$d of everything in the whole scene, it's definitely the better, more performant method to use.

avatar image jhell · Apr 15, 2015 at 07:49 AM 0
Share

Thanks for your answer, I didn't know about InstanceID! Going to give it a go and keep you posted.

avatar image Baste · Apr 15, 2015 at 08:17 AM 1
Share

Is the script you posted attached to the Player object or the Gun object?

If it's on the Gun object, you can do this sanity check:

 Transform myTransform = transform;
 Transform gunTransform = GameObject.Find ("Gun").transform;

 Debug.Log("GameObject.Find finds me: " + (myTransform == gunTransform));

Since you're using GetComponentInChildren in both instances, and you're getting different results, I'm assuming that the above check will print false. If I were to guess, I'd assume that there's a bug in the singleton-code, which results in the script not being on the object you assume it's on.

Actually, search for all the instances of the script you posted in the game. Write "t:ScriptName" in the search bar above your hireachy, where ScriptName is the name of your script. You might end up finding two instances, in which case that's probably your issue.

avatar image jhell · Apr 15, 2015 at 08:56 AM 0
Share

Hi Baste, thanks for dropping by.

The script I posted is attached to the Player object. "Gun" is an empty gameObject serving as a container for the Gun-type weapons (with the weird names), but I think I get what you were trying to tell me. I ran some tests using the InstanceID, this would achieve the same result as your method to check the multiple GOs, am I correct?

So the tests I ran confirmed I have two sets of GOs for my weapons:

  • One set that is the correct one, returned by the general GameObject.Find(), the one that appears in the hierarchy

  • The other "ghost" set

Here are the results with debug mode on and searching for t:Weapon in the hierarchy (red one is the correct one, yellow one is the "ghost" one):

results

I am afraid both of you might be right and my Player singleton/Destroy might have a problem, since I'm not too familiar using it. Here's a snippet in case you see something blatantly wrong (in Awake()):

 if (!hasBeenCreated)
 {
     Debug.Log("Creating player...");
     DontDestroyOnLoad(this.gameObject);
     hasBeenCreated = true;

     if (playthrough == 0) currentPlaythrough = "Gun";
 else if (playthrough == 1) currentPlaythrough = "Grenade";
 else if (playthrough == 2) currentPlaythrough = "$$anonymous$$elee";
 
     weapon = transform.FindChild(currentPlaythrough+"/I-1").GetComponent<Weapon>();
     weapon.SetEquipped(true);
 }
 else // this (supposedly) destroys the new Player object that is created when re-entering game scene
 {
     GameObject.Destroy (this.gameObject);
 }

Please note that the previous code snippets are also called in the Awake() function. I tried moving them in another function to see if this would give more time to Destroy() to complete but the problem remained the same.

I am not really sure on where to go now.

capture.png (112.7 kB)
avatar image Baste · Apr 15, 2015 at 09:00 AM 1
Share

might it be that hasBeenCreated isn't a static variable? In that case, each singleton would have it's own hasBeenCreated variable, and that wouldn't do you much good.

Also note that this.gameObject is redundant - unless you're created another variable in the Start() method that you have named "gameObject".

Show more comments

1 Reply

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Baste · Apr 15, 2015 at 10:33 AM

It should be fine, then. And the variable should be private - no other class should ever need to access it.

Aaaand, I think I found the issue. You're saying that you're assigning the weapon as equipped when you enter the scene, right? Are you doing this in Start()?

So, your singleton is set to DontDestroyOnLoad. This means that it stays alive between scenes. In particular, this also means that Start isn't called again when you change scenes.

So, what's happening is that the Start method being called is the Start method on your other Player object (the one being destroyed). That is where the equipment behaviour is being started. When you do this:

 if (!hasBeenCreated)
 {
     ...
 }
 else
 {
     GameObject.Destroy (this.gameObject);
 }

 //More Start Stuff!

GameObject.Destroy doesn't stop the control flow - so everything later in your Start() method ("More Start Stuff") is being executed by the to-be-destroyed script. This is why GameObject.Find makes your code work, as it finds the singleton instead of the local, to-be-destroyed object.

your singleton's Start should look like this:

 else {
     GameObject.Destroy(this.gameObject); // or just Destroy(gameObject)
     return; //STOP execution of Start!
 }

After you've fixed that, you'll have to take all the code that's supposed to be called every time a level is loaded, and move it to a method. This method needs to be called both on Start (AFTER destroying other singletons), AND in the special OnLevelWasLoaded method, which is called whenever a new level is loaded after that. The OnLevelWasLoaded method takes an int argument that specifies the level that was loaded, so you can avoid calling the level start stuff on the upgrade level.

Comment
Add comment · 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

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

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.



Follow this Question

Answers Answers and Comments

4 People are following this question.

avatar image avatar image avatar image avatar image

Related Questions

How to keep a Gameobject in the same position after a transform.Rotate? 2 Answers

How can i get ONLY the childrens of a GameOnbject with GetComponentsInChildren method? 5 Answers

Simultaneously moving GameObjects using C# script. 3 Answers

Shear transformation using GameObject transformations 2 Answers

Custom transform and gameObject 1 Answer

  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges