What is the difference between GetComponent<Image> ().enabled and .SetActive (false); in unity - unity3d

I have been trying to use SetActive () to turn on and off GameObjects.
I couldn't figure it out and ended up using:
GameObject.Find ("ObjectName").GetComponent<Image> ().enabled = false;
to turn off an image.
I am not trying to use the same script to turn off a GameObject that has multiple animations nested inside it.
GameObject.Find ("ObjectName").GetComponent<???> ().enabled = false;
GameObject.Find ("ObjectName").SetActive (false);
I am not sure what goes in the <>, but I have read I can do it with SetActive (), but that doesn't seem to work and gives me an "Object Reference not set to object" error.
So what is the difference between these two and how would I use them properly?

Using GetComponent allows you to enable/disable and interact with specific components on a GameObject.
For example, you may need to disable a GameObject's rigidbody at some point, but you still want that object, and everything else on it to be active. So you could simply say:
GameObject.Find("MyObject").GetComponent<Rigidbody>().enabled = false;
Note that what goes inside the "<>" is the class name of the component you want to interact with.
For example, if you had a script you have written yourself on a gameobject called MyScript, you could grab hold of it like so:
MyScript script = GamesObject.Find("MyObject").GetComponent<MyScript>().enabled = true;
Additionally, another good use of GetComponent is reading information from a script on an object.
For example, if you had a script called Health with a public variable HitPoints on an object, another script could gain access to that information using GetComponent.
if( enemyGameObject.GetComponent<Health>().HitPoints < 0 )
{
enemyGameObject.SetActive(false);
}
Using SetActive will enable and disable a GameObject entirely. This is less expensive than deleting / making a new object, and is thus often used in techniques like Object Pooling.
For example, if you had a GameObject that you needed disabled, but you knew you were going to need it again soon, it is far less expensive to just call
MyGameObject.SetActive(false);
...
MyGameObject.SetActive(true);
Than it is to delete that object entirely, and then make a new one when you are ready for it again.

To add up to the other answers, when a component is disabled it means the MonoBehaviour callbacks are not called anymore. So no Update, FixedUpdate, OnCollisionXXX and so on.
Awake is called when the object is created so it is obviously enabled by default at that stage. Start is called on the first run after Awake. So if you set the component off in Awake, Start will wait until you set it back on from elsewhere.
OnEnable/OnDisable are called when you modify the enabled property.
SetActive works on the GO and is pretty much a shortcut to disable all components at once.
gameObject.SetActive(false);
foreach(var comp in GetComponentsInChildren<MonoBehaviour>()){
comp.enabled = false;
}
those are fairly similar in result (maybe not in efficiency). Actually, when you set a game object on/off, the OnEnable/OnDisable of each component is called. All MonoBehaviour callbacks are not called anymore if you set the object off.
So, the choice is dependent on what you are after, if you wish to disable movement but still see the object and other actions:
GetComponent<Movement>().enabled = false;
if you wish to kill an enemy:
enemy.gameObject.SetActive(false);
Note that even though a component is disable, does not mean you cannot interact with it. You can still manually call any method on it. Consider this:
AnyComponent ac = gameObject.GetComponent<AnyComponent>();
ac.enabled = false;
ac.AnyMethod();
Valid and will do what it is meant to do considering it does not require an Update or a FixedUpdate (Physics action).
A deactivated component cannot be found with GetComponent, you can get it with GetComponentInChildren(true) since it also searches the game object and its children. I am not sure whether it returns the first found or the first active found.
myGameObject.SetActive(false);
AnyComponent ac = myGameObject.GetComponent();
AnyComponent acic = myGameObject.GetComponentInChildren(true);
even though the GO has a AnyComponent attached, ac is null, acic is not (seems to be a 5.3 feature though).
http://docs.unity3d.com/ScriptReference/Component.GetComponentInChildren.html
Finally, for a component to expose the tick, it needs to have a Start method in the script (don't ask why...).

Setting .enabled turns one component on a GameObject on or off, e.g. an Image. Using SetActive() turns the whole GameObject on or off.
Choosing which to use should correspond with what you want to disable.

Related

Use the collider of multiple objects as one collider

In my fps level (Unity), targets spawn at a random position. I want to make sure targets can't spawn behind objects or inside objects.
To make sure they don't spawn behind an object, I've made a raycast going from the player to the target. If it's obstructed I recalculate the spawn point. This works fine, but, since the targets are spheres the raycast won't be obstructed when a target is 50% inside an object, for example the floor. I don't want that, obviously.
To determine whether or not the target is in the bounds of another object, I tried using OnCollisionEnter and OnCollisionExit. While this works when simply moving a target inside another object, it seems to be unreliable when one script's Update cycle is recalculating the spawn position while the target's Update cycle is keeping track of the Collision.
So I looked for a different approach. Here's what I came up with (from the Unity docs):
m_Collider2 = spawnpoints[i].GetComponent<Collider>();
m_Collider = world.GetComponentInChildren<Collider>();
if (m_Collider.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
}
The Game Object world is the parent in which I put all the objects of my gaming world.
The problem is that he only takes into account the collider of the first object. I basically want to use one big collider, which is composed by all the level objects.
Is this possible? Or does anyone know a different approach on how I can achieve this?
You should use the GetComponentsInChildren method instead of GetComponentInChildren, so that you can get from it an array of colliders on which you can execute a foreach to check if the bounds are intersecting.
I.E.:
m_Collider2 = spawnpoints [i].GetComponent<Collider>();
m_Collider = world.GetComponentsInChildren<Collider>();
foreach(Collider objCollider in m_Collider) {
if (objCollider.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
break;
}
}
But, this way of doing things is very heavy for the CPU, since GetComponent methods are really slow, so their use should be limited inside Awake and Start methods if possible.
Another approach to the problem would be to create a List<Collider> at the start, and add to it the starting children of your World game object. If another one is instantiated, just Add it to your list, if it's destroyed, just Remove it.
Then, just before instantiation, you can check the bounds by looping inside the List with a foreach, the check will be a lot more faster.
==================================
EDIT:
Ok, here's the deal. First of all, add these lines to your World game object script (I guess you called the class World):
using UnityEngine;
using System.Collections.Generic; //Namespace needed to use the List type
public class World : MonoBehaviour {
//The list which will hold references to the children game objects colliders
public List<Collider> childrenColliders;
private void Start() {
//Code used to populate the list at start
childrenColliders = new List<Collider>(GetComponentsInChildren<Collider>());
}
Now, since in the script which spawns a new object has already a world variable which holds a reference to the World class:
foreach(Collider coll in world.childrenColliders) {
if (coll.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
break;
}
}
And, of course, as I said before remember to add a newly spawned game object's collider to the list with:
void AddNewGameObject() {
// spawnPoint is the transform.position Vector3 you'll use for the new game object
var newGameObject = Instantiate(yourObjectPrefab, spawnPoint, Quaternion.identity, world.transform);
world.childrenColliders.Add(newGameObject.GetComponent<Collider>());
}
That's pretty much it. ;)

Unity3D - Disabled GameObject scripts losing state

I have a script component on a GameObject (simplified here) which is disabled upon creation, using testObject.setActive(false).
using UnityEngine;
public TestObject : MonoBehaviour {
public int testValue = 5;
void Start() {
testValue = 0;
}
public int GetTestValue() {
return testValue;
}
}
Before disabling, the return of GetTestValue is 0. Once I re-enable the object, the return is 5.
The Unity docs say:
Making a GameObject inactive will disable every component ... Any scripts that you have attached to the GameObject will no longer have Update() called ...
However the behaviour of the Component suggests to me that the MonoBehaviour made by the script is not really 'disabled', but rather is destroyed. If it were only Update() that stopped being called, how does that explain the loss of state?
The underlying question here is: what is the intended way to temporarily disable a script without destroying it?
Well what actually happens is that the Start() function is only called once in the lifetime of an object. So at the beginning its called and sets the value to 0. But when you disable it and reactivate it, it isn't called.
This doesn't change the fact that even after deactivating and reactivating the script your value should still be the same (as we figured out in the comments section).
One way you could make this work is by using OnEnable() which will be called each time the Script is setActive. More info on OnEnable:
This function is called when the object becomes enabled and active.
So in your script you would have :
private void OnEnable()
{
testValue = 0;
}
If you know this object will be Activated and deactivated many times and that you absolutely need to do something each time this happens.
Which brings me to my second point and my advice:
Dont keep important values on scripts that will get deactivated and reactivated.
Keep important information on a script that will never be deactivated so in that way you're always sure the value is always the correct one. So that way you don't always need to regenerate that correct value and check each time if it's actually the good value you got.
The problem, it turns out, was a race condition. TestObject was being deactivated before Start() could complete, and this prevented the object from being initialized properly. By moving the initialization code to Awake(), the object correctly set its state before deactivating.
I have the opposite situation..I tried to set an animator parameter in Awake() and deactivate immediately. the parameter value did not changed. But if i put it in Start(), the value is set.

Talking to GameObject and components, what is the logic?

I am trying to attain the legendary skill of mastering how to make my scripts talk with any GameObject and their components wherever they are. To do that, i watched a couple of tutorials like https://www.youtube.com/watch?v=LrkfSqxz4jU, but my brain still seem to resist to smartness :(.
So far, i have understood than in order to do that i first need my
script to find the right gameobject in my scene (if the script is not
attached directly to it), and assign it to a variable, with for
example:
myVariable = GameObject.Find ("MyGameObjectName");
Then, when i have found this gameobject (and eventually summoned it if it was not in my scene), i find myself at loss to figure out how to call the right component (and inherently, how to call the right sub-element.
For example, i have at the moment a game object for my UI with :
RectTransform, CanvasRenderer,UI Controller (Script),Grid Layout Group (Script)
In order to modify the RectTransform 's Pivot X for example, my logic tells me to add to my script:
myVariable.GetComponent<RectTransform> ();
myVariable.RectTransform.Pivot.x = 0.75;
...Which get all red and bad, and i don't understand why. I am also not knowing how i am supposed to call the component GridLayoutGroup. I suppose there is a even dirtier trick in the sense that it is written (script)...
To give you another example that i find confusing, if i would type myVariable.transform.position.x , is it changing the RectTransform, or another hidden transform that i don't know of ?
It is confusing because i would think that logically, this should be called instead myVariable.RectTransform.position.x or something.
So the point of all that is: What's the big idea ? What is the core concept that i am missing ?
I am confused ! :D
Because having public fields is bad practice (accessible from everywhere) you should use serialized fields.
I'll just use the example Vancete made up, but with a serialized field instead of a public field.
[SerializeField] GameObject myGo; // a space to drop a GameObject will appear in the inspector too,
// with the benefit of not having a public field
// (not specifying public, private, protected etc. makes the field private in C#)
void Start() {
Image myImg = myGo.GetComponent<Image>();
myImg.sprite = // WHATEVER
myImg.color = // YOUR PREFERRED COLOR
}
At the bottom of this page, you'll find a nice table, comparing these modifiers.
These people here are all proving my concept. As the user, who wrote the last answer on the linked page, points out, even Unity is using [SerializeField] in their example project.
You'll find another proof in this article.
The fastest and best way to access a GameObject is declaring it as public and drag&dropping in the inspector.
GameObject.Find is slow (since it requires a tree search) and impractical (you will have problems if you rename the GameObject or change its hierarchy), things that can be avoided linking it in the mentioned way above.
For example, using GameObject.Find inside the Update is a real performance killer.
Also, if you are going to access to a GameObject component more than once, it's recommended to reference it before using it.
public GameObject myGo; // a space to drop a GameObject will appear in the inspector
void Start(){
Image myImg = myGo.GetComponent<Image>();
myImg.sprite = // WHATEVER
myImg.color = // YOUR PREFERRED COLOR
}

Is there any way to use AddComponent with a script in Unity if there is no instance of that script in the game yet?

I need a way to add a script to an object that I just Instantiated. Ideally I could just set the script to add in the inspector. The problem is that I can't use
public Component scriptToAdd;
because then I would need to already have an empty object or something with the script on it. While that would work it feels kind of dirty or hackish to make an empty that just stores references to something. Also the point of doing it like this for me is to make it more efficient to swap out different scripts. If I had to swap out a script on an empty and then drag the new one in I'd lose on some of that efficiency I'm after. Thanks for any help.
After you instantiate, you should use the GameObject.AddComponent() Class, to add any component Type you want.
for example, if you want to add a camera to the scene.
void Start () {
GameObject myNewCamera = new GameObject();
//creates an empty game object, you can already attach components to it.
myNewCamera.AddComponent<Camera>();
//adds a component of type Camera
}
You can also use the overloaded constructor
GameObject myNewCamera = new GameObject("my object name", typeof(ScriptToAdd));
GameObject myNewCamera = new GameObject("my object name", typeof(ScriptToAdd), typeof(MoreComponentsToAdd));
Also, you should never be afraid of using an empty GameObject on your scene, for keeping information, references, variable values, saves, or anything really. It doesn't really affect the performance of your game, and you can make your life easy just by having an easy to find tag, such as "Engine".
Then you can access anything just by adding:
GameObject.FindGameObjectWithTag("Engine");
I hope I was able to help you :)
-Noe

Awake() and Start()

I see that we can initialize Variable in Awake() or Start() and Awake() will be called before Start().
When should we initialize in Awake and Start to have the best performance?
Usually Awake() is used to initialize if certain values or script are dependent on each other and would cause errors if one of them is initialized too late (awake runs before the game starts).
Awake is also called only once for every script instance.
Let me quote the Documentation:
[...] Awake is called after all objects are initialized so you can safely speak to other objects or query them using eg. GameObject.FindWithTag. Each GameObject's Awake is called in a random order between objects. Because of this, you should use Awake to set up references between scripts, and use Start() to pass any information back and forth. Awake is always called before any Start functions. This allows you to order initialization of scripts. Awake can not act as a coroutine.
and about Start():
Start is called on the frame when a script is enabled just before any
of the Update methods is called the first time.
Like the Awake function, Start is called exactly once in the lifetime
of the script. However, Awake is called when the script object is
initialised, regardless of whether or not the script is enabled. Start
may not be called on the same frame as Awake if the script is not
enabled at initialisation time.
Where the last part makes one big difference
To get to your question:
If the script is NOT enabled at the beginning of your game, and you don't need the variables to be initialized, start would be saving performance as awake() would be called regardless...
every variable would be initialized at the very beginning. At least that's the logical assumption I make.
This topic is well described in the official docmentation (Awake and Start).
This section describes why you might need two functions:
The Awake function is called on all objects in the scene before any
object's Start function is called. This fact is useful in cases where
object A's initialisation code needs to rely on object B's already
being initialised; B's initialisation should be done in Awake while
A's should be done in Start.
The difference between Awake and Start is that Start is called only when a script is enabled.
These two functions are called before the first Update method and there is no performance difference between them. I would say that Awake is used to initialize all objects (like a constructor), and Start is used to link the objects or do something before a game starts.
Awake is the equivalent of the ctor. It is called when a MonoBehaviour is created, before any other method if the object is active.
Start is run the first time the MonoBehaviour is activated. This can be right after Awake or long after. This allows to perform actions that are related to the current state of the app or objects.
For instance, you create an enemy, in Awake, you place everything that is basic initialisation. Then, the enemy is deactivated at the end of Awake. Later on, the enemy is about to be activated but you want to make it red if player is having some specific weapon, then you do it in Start.
IMPORTANT: If a prefab is created and the game object is off by default in the prefab, the Awake is not called until set on. In the case of a pool creation where prefab may be off, the awake is happening first time the pooled object is activated.
OnEnable is similar to Start but happens on every SetActive(true) and on start if enabled. This can be a candidate for your enemy willing to change color over the level based on the player magna for instance.
There's not much difference in the performance. But I can tell you a difference between them.
Take a simple example. Say if you want to print "HELLO" in console even if you have not activated the script in inspector, using Awake() function, you can print it in the console. But if you had written the same thing in Start() function and the script wasn't activated, you don't get any output in the console. That's the difference.
Codes in Start() function get executed only if the script is activated while, codes in Awake() function get executed even if the script is not activated. Try it !
I'd claim there is no real performance difference at all.
What Minzkraut stated
If the script is NOT enabled at the beginning of your game, and you don't need the variables to be initialized, start would be saving performance as awake() would be called regardless...
every variable would be initialized at the very beginning. At least that's the logical assumption I make.
is only semi true. If you do everything only in Start the UX might be even worse since instead of one bigger lag when starting the app - which in my eyes is totally acceptable - it might lead to smaller but more lags during game play which I personally would avoid as much as possible.
In general it was already often explained in the other answers how and when Awake and Start are called and that basically it is "just" a timing difference.
For details refer to Execution Order of Events
Leaving disabled components and inactive GameObjects aside my personal thumb rule is
Use Awake for everything where you don't rely on any other component and references.
E.g. set default field values, populate things using GetComponent etc
Use Start for everything where you do rely on other components such as accessing the results of GetComponent
This way these other components supposedly did already receive their Awake call so they themselves are already linked up and ready to be used by others.
This solves timing and dependency issues in the most cases.
Where this is not enough you would start to tweak the Script execution order or use events.
And then there is another quite important difference in the use case of using Instantiate or AddComponent
Awake (and OnEnable except using Instantiate and the component is disabled) will be called right away during the instantiation and any code line after Instantiate will be executed after it is finished.
Start however will be delayed until the end of that frame (or until enabling if the component was disabled in Awake).
This allows you to have enough time to use Instantiate and modify some field values before Start is called and can now base its behavior on the modified field values.
For example this
public class Example : MonoBehaviour
{
private class X : MonoBehaviour
{
public int x = -1;
private void Awake()
{
Debug.Log($"Awake {x}");
x = 12;
}
private void OnEnable()
{
Debug.Log($"OnEnable {x}");
}
private void Start()
{
Debug.Log($"Start {x}");
}
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("Instantiate");
var x = gameObject.AddComponent<X>();
Debug.Log("After instantiate");
x.x = 42;
}
}
}
will produce the output
Instantiate
Awake -1
OnEnable 12
After Instantiate
Start 42