Simulating Update() call on MonoBehaviour - c#

How can I call Update() or Start() or any other MonoBehaviour method directly?
I disabled most of my MonoBehaviour auto Update() calls by setting enabled = false; on each of them, because I need to time Update() at a very specific time for those scripts.
I am thinking about doing it like this:
List<MonoBehaviour> disabledScripts;
foreach (MonoBehaviour m in disabledScripts)
m.Update();
But i'm not sure if it is the correct way to do it since not all MonoBehaviour in disabledScripts actually implement Update().

Start is called automatically on object start and Update is called automatically on each frame by the engine.
If you want to control the order in which the scripts's Start() or Update() method is called take a look at this http://docs.unity3d.com/Manual/class-ScriptExecution.html
If you need to execute certain code in a controlled timing or need on certain conditions, better create an specific method for each object and create a controller to call this method on each object at the desired time.
For example you can leave Update() method empty for every object and create a method called MyUpdate (with parameters if you wish) and call it when needed from the controller based on your game's workflow.
Unity's base flow must be kept unaltered, because it can lead to strange behaviors. I can't think about a thing that can't be done with Unity's natural flow.
Edit:
Ok, I understand that you don't want to create a complex functionality just to try something.
As you say, disabling the behaviour forces the engine to avoid calling Update on each frame for the given MonoBehaviour, but I don't think you can call Update as you propose because in MonoBehaviour, Update has no method modifiers (see method without access modifier)
Anyway, I would create a "MyMonoBehaviour" extending MonoBehaviour with a MyUpdate() function that you will override on each object extending MyMonoBehaviour. You can call the MyUpdate function doing something like this (very similar to the code you proposed):
List<MyMonoBehaviour> disabledScripts;
foreach (MyMonoBehaviour m in disabledScripts)
m.MyUpdate();

Alright I figured it out:
script.Update();
compiles an error, the correct way to do it is:
script.SendMessage("Update");
I also found out that setting enabled = false; also disables some other methods such as Start(), so I think I'll just extend MonoBehaviour and move all Update() code to MyUpdate() as antonio said.

Related

What methods are called by which scene's objects on start?

Is there a way to check what methods exactly are called on scene's start? And which objects called them? I want to achieve something similar to adding Debug.Log(); to every single method but without doing it. I'd like to know what's going on in a project when I press play.
A scene consists only of game objects (there's nothing else in Unity).
GameObjects may have 1 or more Components attached.
When you click Play ...
It looks like you already know that, the calls such as
void Start()
(if they exist in the script) are called - automatically, by Unity - when each Component on each GameObject is launched with the scene.
It's quite common that inside each Start, you just add something like Debug.Log("starting, script name, on .. " + transform.name) which will simply let you know that that component on that game object has started.
Maybe that's what you need.
Obviously you will have added many functions to your own scripts
void SomeFunction() {
Are you saying you want to know when those functions run?
If so the only way to do that is simply manually add a Debug line, inside each function.
(Regarding functions which you add yourself, example SomeFunction, they are not in any way called automatically. They are only called if you call them (say from Start or similar). You can be sure they are only called if you call them.

How does the OnCollisionEnter function work "Fundamentally"?

I am very new to c# and Unity and I have a question. I am not able to understand how OnCollisionEnter works fundamentally.
Like, if I have a terrain and a sphere hovering above it which has the rigid body component and I write:-
void OnCollisionEnter(Collision other)
{
Debug.Log(other.gameObject.name);
}
and then run the code we on the console screen would get "Sphere" and not "Terrain". Why is Sphere being passed to "other" and not Terrain?
Secondly, I believe, OnCollisionEnter is a part of the MonoBehavior class and our class is already inheriting it from MonoBehavior.
Then, why do we have to define OnCollisionEnter() again?
These questions are really eating my head up. I will be very grateful if anyone could help me out.
Why is Sphere being passed to "other" and not Terrain?
what is passed in other depends on which object you attached that component to ... if you attach it to the Terrain then in other you should get Sphere and viceversa. So you see the name other actually kind of makes sense, right?
Then, why do we have to define OnCollisionEnter() again?
in MonoBehaviour you can find OnCollisionEnter among al the others like Awake, Update, Start etc under "Messages", not under "private/public/whatever Methods".
In very short: Messages are internally only called by the Unity process if present in a component and not called at all if not present.
I think they use something similar to Component.SendMessage in the background but not sure.
Calls the method named methodName on every MonoBehaviour in this game object.
How it works: "OnCollisionEnter is called when this collider/rigidbody has begun touching another rigidbody/collider" - https://docs.unity3d.com/ScriptReference/Collider.OnCollisionEnter.html
OnCollisionEnter is among other functions (update, fixed update, start, awake, etc.), if defined within a body of MonoBehavior derived class, called by the Engine itself, i.e. these are engine event functions.
Why is triggered on the Sphere: Because you have your method in the class attached to the sphere object, see above how the OnCollisionEnter works.

What is better: link to a GameObject or to a Class in Unity?

Example: GameObject A has a script attached to it called MakeItRain. Inside that script is a public void Drizzle();
GameObject B also has a script and wants to tell MakeItRain to do Drizzle();
Inside the script of GameObject B, I can do this:
public GameObject makeitrain;
and then I have to use GetComponent to reach Drizzle(); in my code.
In the inspector, I drop GameObject A into the slot of makeitrain and I'm done.
However, I could also do this in the script of GameObject B:
public MakeItRain makeitrain;
and then just call makeitrain.Drizzle(); in my code of GameObject B's script, without GetComponent.
In both cases, in the Inspector, I have to drag and drop GameObject A into the slot of GameObject B.
Is there a difference or reason why I should definitely not do the last option? I understand that the first method gives me more flexibility because I could call other components of GameObject A as well and not just the script's stuff. Just wondering if there is any other rationale for not doing the second method.
The answer depends if you need to call any function or use variable from the MakeItRain script.
If you don't need to to call any function in the MakeItRain script or access any variables from it then it is better to use GameObject as the reference. Also, if what you need to do is activate, de-active, rotate the GameObject then use the GameObject as reference.
On the other hand, if you need to be able to call a function such as Drizzle or access a variable from the MakeItRain script from multiple places, then you need to use the MakeItRain reference. At this time, it doesn't make sense to use the GameObject reference since by using it, it's required to use GetComponent every-time you need to call a function or access a variable from the MakeItRain script attached to it.
Finally, when using the MakeItRain script to reference your object, you can directly and easily access the GameObject it is attached to without using the makeitrain.gameObject. This doesn't require the use of the GetComponent function.
Just wondering if there is any other rationale for not doing the
second method.
Performance issue due to the required use of the GetComponent function is the reason. Using it once in the Start or Awake function and initializing your MakeItRain variable is better.
For example, this is better:
public MakeItRain makeitrain;
void Start()
{
makeitrain = GetComponent<MakeItRain>();
}
void Update()
{
makeitrain.Drizzle();
}
than this:
public GameObject makeitrain;
void Update()
{
makeitrain.GetComponent<MakeItRain>().Drizzle();
}
And should be used to avoid having to search for the component on the native side every frame.
Using MakeItRain and explicitly defining the type is better than using GameObject.
As #hacksalot commented, using MakeItRain offers strong typing. One of the benefits of this is related to your comment:
In both cases, in the Inspector, I have to drag and drop GameObject A
into the slot of GameObject B.
If you explicitly set the public variable type to MakeItRain rather than GameObject, it is not possible to drag and drop a GameObject A into the slot of GameObject B unless GameObject A is has a script of the correct type. This gives you a compile-time/editor-time check that you are linking to the correct GameObject in the Unity Editor inspector.
Also, while not necessarily so, using GameObject references often encourages messier code, whether because of unnecessary chaining of methods together (e.g. GetComponent) just because the type wasn't specified, or because it adds a bit of friction to writing & using helper methods. Consider even in a simple example which one reads better:
makeitrain.Drizzle()
makeitrain.GetComponent<MakeItRain>().Drizzle()
I understand that the first method gives me more flexibility because I
could call other components of GameObject A as well and not just the
script's stuff.
Note that you still have the flexibility to access GameObject, it's just a bit more verbose (which is one downside of this approach):
public MakeItRain makeitrain;
void Start()
{
makeitrain.gameObject.SetActive(false)
}
However, you'll likely be using helper methods anyway (for anything more than basic calls), or even wrapper methods (which are inconvenient to write but sometimes helpful for readability).
In most cases, the benefits of linking to the class rather than the GameObject outweigh the downsides.
If u don't want to use GetComponent(), you can simply use SendMeassage(), like this
public Gameobject makeItRain;
void Start(){
makeitrain.SendMeassage("Drizzle");
}
Another way to link a script is that use FindObjectOfType(), which do not need to drag and drop GameObject into the slot, here is the sample
void Start(){
MakeItRain makeitrain = FindObjectOfType("MakeItRain");
}
Also you can use Gameobject.Find() to link a GameObject instead of dragging into slot, but I don't recommand this way, it cost a lot performance since you need to find every single GameObject in scene.

Does GetComponent<>() impact performance

Just as title say does GetComponent() does impact a lot on performance.
I am asking this because I do not like doing it like this:
public class Player : MonoBehaviour
{
PlayerStats playerStats = this.GetComponent<PlayerStats>();
void Update()
{
var something = playerStats.Asd;
}
}
Instead of that i like using it like this:
public class Player : MonoBehaviour
{
void Update()
{
var something = this.GetComponent<PlayerStats>().Asd;
}
}
Reason for that is because i like breaking code in lot of scripts (it is easier for me to later change something if needed and also use one script for multiple objects) and so if i have a lot of scripts i need to see if i have already defined PlayerStats playerStats.... but not only this one but about a lot of them.
So is using second approach going to slow down my game a lot?
It's worth noting that your first script is invalid and won't compile. The correct way to do that is to make it a global variable but cache or initialize the script in the Start or Awake function. These functions run once and are used for initialization.
Something like this:
PlayerStats playerStats;
void Start()
{
playerStats = this.GetComponent<PlayerStats>();
}
To answer your question, the GetComponent function impacting performance is greatly over exaggerated. You read this everywhere on the internet but it depends on how often it is used. If it is used once in a while or just in few scripts then it's totally fine.
If you have hundreds instances of scripts using GetComponent in the Update function then that's when you will start noticing a little bit of performance hit because GetComponent is making call to the native side. So, it depends on how often it is called and how many instances of scripts are making this call each frame.
The main appeal of using the first approach is that you can set those variables to be public, and in turn access them directly from the Unity Editor, allowing you to drag and drop components as you feel like it.
The second instance of your GetComponent function call means that you aren't caching your variables, slowing down your code with potentially unnecessary checks. So my advice would be to stick with the first instance in which your variable is defined in memory and then altered, rather than being allocated memory each time and then altered.
And a side note. You do not need to call this.GetComponent if the script is attached to an object since the script derives from a MonoBehaviour; you can just call GetComponent<type>() and go about your merry day. :)
I don't think it really matters. I just did a check and using for loop that looped 1,000,000 times and found the exact same 0.02 time delay between both frames.
That being said, it would make your code cleaner because Player.Stats.Asd is cleaner than Player.GetComponent<PlayerStats>().Asd. It makes it more obvious what the intent is. I'm sure it is still a micro optimization to store it as a variable with a public PlayerStats Stats { get; set; }, but that's really if you're using it all the time.
You shouldn't use a variable for every Component it has, because if you do that for every script, the memory being used will start to add up.
Also, note that I'm calling it Stats not PlayerStats because Player.PlayerStats is needlessly redundant. The actual type of it should be called PlayerStats yes, to not confuse it with, say, EnemyStats, but when you go to use both, having Player.Stats and Enemy.Stats is cleaner.

Accessing a script from another script at runtime in Unity C#

Like in here, but the difference is that it's supposed to be done from an instantiated prefab, so I can not drag the GameObject, that has the script with the variable I want to access, into this script.
This was working
public ScriptA script;
void Update() {
if (script.varX < 0) {
// . . .
}
}
But now I'm getting "Object reference not set to an instance of an object" error, which I think comes from the fact that the script trying to access ScriptA, is attached to an instantiated prefab.
How do I attach scripts and/or GameObjects at runtime?
Looks like you need to find your script type first, if it already exists in the scene:
public ScriptA script;
void Start()
{
script = GameObject.FindObjectOfType<ScriptA>();
}
void Update()
{
if(script.variable...)
}
You want to use AddComponent, like:
ScriptA script = gameObject.AddComponent<ScriptA>() as ScriptA;
See the docs here:
https://docs.unity3d.com/ScriptReference/GameObject.AddComponent.html
Best way to satify the links is fill the fields in the very next lines after you instantiate, that way you can avoid ugly and expenstive Find* calls (I am assuming the script that does the instancing can be made aware of what the target objects are, after all it knows what and where to instantiate)
Its worth noting that newly instantiated scripts' Awake() method will be called before Instantiate() returns, while its Start() will be called at the start of following frame, this is a major difference between the two calls, so if your instantiated script needs the refectences in Awake() you should either refactor (move stuff to Start()) or use Find* as suggested earlier.

Categories

Resources