Hello, I’m am pretty new to unity and am confused by the difference between
player = GetComponent(); and player = GameObject.Find(“Player”); .
I have heard that it is bad practice to use .Find() because it grabs only the first item from the hierarchy which may not be what you want. However, I’m going through the Create with Code unity course and in the 4th unit he uses, player = GameObject.Find(“Player”); and I am confused as to why.
The exact video I am talking about is in the create with code series under,
unit 4 >> lesson 4.2 - Follow the Player >> 3. Create enemy script to follow the player.
A GameObject is not a Component, so GetComponent<GameObject>() shouldn’t even return anything.
A Component is anything that is attached onto a GameObject, such as a Rigidbody, an AudioSource, a ParticleSystem, etc.
GetComponent searches through a GameObject for a component attached onto it, whereas GameObject.Find searches the scene for a GameObject by its name.
The main reasons why GameObject.Find is considered bad practice are:
It searches through every GameObject in the scene until it finds the one its looking for. This is generally a slow process compared to other methods.
The GameObject you search for must be active in the scene. GameObject.Find and its similar methods (FindWithTag, FindObjectOfType, etc.) will not return any inactive objects.
It can only find one GameObject. There is no way to find multiple GameObjects of the same name.
Having to search by name means that you have to ensure you never change the name of the GameObject you’re looking for, or if you do, you have to always remember to update the name passed into the method. Referencing resources by string comparisons often leads to these organizational issues.
Those aforementioned other methods of referencing GameObjects are pretty much always faster & easier to manage.
The most typical way of referencing a GameObject is by dragging and dropping its reference in a component’s inspector:
public class MyScript : MonoBehaviour {
//Drag/Drop the player GameObject here from the inspector.
public GameObject player;
}
No need to run any scene-searches or string name comparisons.
This is not to say that GameObject.Find should never be used. There might be some edge-cases where it comes in handy, but I’ve so far never needed to use it.
If you absolutely must get a reference by searching the scene, my first option would be to use GameObject.FindObjectOfType instead.
For instance, you could create a custom Player script component that has your player-related logic and attach it onto your player GameObject. Then to find the player in the scene, you’d just need to say: Player player = GameObject.FindObjectOfType<Player>();.
This way, you don’t need to care what the name of the GameObject is, only that it has a Player script attached onto it, which you can then reference and do whatever you want with.
Edit: So the script I used player = GameObject.Find(“Player”); in was for my enemy object. As I progressed through the course I noticed that when I made the enemy object a prefab it no longer allowed me to drag the player from the hierarchy to the player gameobject field in the inspector.
Even though this was a case I didn’t get an error saying, “There is no ‘GameObject’ attached to the “Enemy(Clone)” game object, but a script is trying to access it”. And I believe this is because I used, player = GameObject.Find(“Player”); which gets the object from the hierarchy without having to drag it into the inspector like you would have to do if you used, player = GetComponent(); .
So this is one instance where I believe .Find() would be better than using GetComponent<>(); if anyone has any other instances please share!
Thank you for your response! Although I still have a question regarding what you said about “The most typical way of referencing a GameObject is by dragging and dropping its reference in a component’s inspector”. There are times like the one I listed in my edit reply where I have made a prefab that has a script component that references a gameobject but will not allow me to drag the gameobject to the inspector.
Would this be one of those cases where it would be better to use GameObject.Find(); (for an object without a script) or even
Player player = GameObject.FindObjectOfType(); (if I have a script called Player attached to it)?
Sure, but if your game is only going to have one player, and every enemy needs to know about that player, then one thing you could do is make the player’s reference in the enemy class static, and only search for the player once:
public class Enemy : MonoBehavior {
private static GameObject player;
private void Start() {
if(player == null) {
player = GameObject.Find("Player");
}
}
}
This way, the player GameObject reference is shared amongst all Enemy instances, and once the reference has been found, it doesn’t need to be repeatedly searched for again any time a new Enemy is instantiated.