Unity 3D's component-based design model and race conditions - c#

I'm having a bit of trouble with Unity 3D's Component-based design model.
Here's an example that demonstrates my problem:
class MyComponent : MonoBehaviour
{
MyType entity;
void Start()
{
entity = (MyType)FindObjectsOfType(typeof(MyType)).First();
}
void MyMethod()
{
var x = entity.SomeProperty; // <= NullReference exception
}
}
// ....
var clone = (GameObject)Instantiate(original);
clone.GetComponent<MyComponent>().MyMethod();
Sometimes, not always though, MyMethod executes before Start so what I end up doing is move all the initializations I usually have in Start to MyMethod which is quite an ugly workaround:
void Start() { }
void MyMethod()
{
entity = (MyType)FindObjectsOfType(typeof(MyType)).First();
var x = entity.SomeProperty; // <= now it's fine.
}
My question is, what is the correct way of working with this pattern (without a constructor)?

That probably happens when you call MyMethod from the Awake of another Component, because Awake is called before the game starts. The only solution I see is to make sure that you don't call methods on other components (in this case MyMethod) in the Awake() event, but rather in the Start() event.

The Unity documentation says "Awake is called before the game starts" but this is not precise. A component's Awake method is called when in a scene the gameobject becomes active which carries the component.
Some gameobjects will be active by default when a scene is loaded, but other gameobjects might be activated later. Then there is the possibility of dynamically adding components via AddComponent.
This aspect should be kept in mind when relying on dependencies between Awake and Start methods. Another example for a race condition is to enable a component from the Update method. While enabling a component implies that its Start method will be called, this will not happen in the running update cycle, so that other components cannot rely on the first component's ".enabled" property to determine wheter it has been started or not.

Related

What is "Messages" in Unity's MonoBehaviour class? (Start,Update,Awake...etc)

What is the "Messages" of this page? (Start,Update,Awake...etc)
Is is a something like virtual method or event?
Or "Messages" is one of the C# syntax?
https://docs.unity3d.com/ScriptReference/MonoBehaviour.html
The Unity engine basically calls these methods on MonoBehaviours if they are defined, depending on Engine events.
For example:
Awake is called when the script instance is being loaded.
Start is called in the first frame when the script is being enabled, before every Update method and after Awake
Update is being called in every frame
There are numerous messages as you can see it int the DOCs, and they are being called depending on engine events.
You can not call these events they are being handled by the engine!
Most commons are:
Update
Start
Awake
OnDestroy
OnEnable
But please note that using these methods(messages) while they are empty have a small overhead because the engine will call them, even if they are empty.
Another advanced thing is that some of these messages can be Coroutines. And you can give them some advanced functionality.
IEnumerator Start()
{
Debug.Log("First frame i'm being enabled! yeee");
// After 2 seconds i'm gonna blink
yield return new WaitForSeconds(2.0f);
Debug.Log("I'm going to blink");
Blink();
}
'Message' here is a synonymous for Function/Method, which are just Automatically called functions by unity engine, for any script inheriting from MonoBehaviour and attached to an ACTIVE gameobject in your scene.
Consider an animal script
public class Animal : MonoBehaviour
{
void Awake()
{
Debug.Log("Code here in awake is executed by unity the first time this object is activated, and never again in the lifetime of this object.");
}
void Start()
{
Debug.Log("Start is similar to awake but is executed after 'Awake' is executed on all game objects.");
}
void OnEnable()
{
Debug.Log("Code executed EVERYTIME your object is activated, including the first time you enter playmode, provided this object is active.");
}
void OnDisable()
{
Debug.Log("Code executed EVERYTIME your object is deactivated, does not include the first time you enter playmode if the object was disabled before playing.");
}
}
And so on, every Message/Function/Method has its use case and time, you'll get the hang of it when you start using them, they are the core of the engine.

Unity object initialization synchronization

Until now, I've been coding thinking that functions in monobehaviour would be executed in this order:
OnEnable > Start > Update > OnDisable
The problem is that I thought that this order would be absolute, meaning that until a function is not completely finished, there's no way that the next one would start being executed.
So first question is: Is that true? Would update NOT be executed until start ends?
Then my problem arises with synchronization between different monobehaviour classes.
I have a class that creates some objects (a Menu basically) in its start function. Then in a different class, I've a similar code, but it also depends on the object created by the first class to exist already. I'm getting an error because the object is not found yet.
NullReferenceException: Object reference not set to an instance of an object ShopHandler.Start () (at Assets/Scripts/Shops/ShopHandler.cs:60)
So now I'm stuck with this. Therefore my second question would be,
How can I synchronize my different classes when they depend on others like this?
Finally, a question mixed from these two also has to be asked:
Would update function be executed in any of these classes, while they're somehow "waiting" for their initialization part, be it in start function, OnEnable function or whatever?
Because of course, update function relies on objects being initialized already, and this could end in new problems.
Thanks in advance
Here is my approach:
Let's say you have two monobehaviours A and B. Assume that B has to initialised after A. Then;
1-) Create a function, i.e "Initialise" and use it in B instead of the Start function:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class B : MonoBehaviour
{
public void Initialise()
{
//Code you run on Start()
}
}
2-) Reference B obj in A obj, use bObj.Initialise after are ready to initialise it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class A : MonoBehaviour
{
public B bObj;
// Start is called before the first frame update
void Start()
{
//Things to do in Start()
//...
//...
//...
bObj.Initialise();
}
}
Lastly, if you want your Update function run whenever you want, I usually prefer to use something as a flag. So here's my second version of class B for controlling update() behavior:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class B : MonoBehaviour
{
public bool canUpdate;
public void Initialise()
{
//Code you run on Start()
canUpdate = true;
}
private void Update()
{
if (canUpdate)
{
//do the stuff
}
}
}
The problem is that I thought that this order would be absolute, meaning that until a function is not completely finished, there's no way that the next one would start being executed.
So first question is: Is that true? Would update NOT be executed until start ends?
Usually yes, but there is an exception.
If you implement Start as a coroutine, Update can be called before Start ends on the same monobehaviour.
For instance, this code:
IEnumerator Start()
{
Debug.Log("Start beginning");
yield return null;
Debug.Log("Start continuing");
yield return null;
Debug.Log("Start completing");
}
void Update()
{
Debug.Log("Update running");
}
Could produce this output:
Start beginning
Start continuing
Update running
Start completing
Update running
Update running
Update running
...
It is hard to say where your problem is actually coming from, because you have not posted any code. However, I believe your problem might be solved by implementing solution noted at 2
Yes, All Start Functions (and Awake) are called before the update function, if the gameobjects/ monobehaviours are enabled/active! Start/Awake/Update are not called on inactive gameobjects
You should look into Script Execution Order. Here you can make sure that the start/ awake/ update functions of classes are called in a certain order. It should be listed under project settings.
When initializing a scene, update will be called after all awake/ start functions have finished (unless they are defined as Coroutines, but this is probably not your issue).

Unity StateMachineBehaviour : Start function called once?

i'm making my first enemy AI in unity. I'm trying to make a finished state machine with the animator controller to do it.
I just discovered the StateMachineBehaviour script which is called when the AI is in a state. It has multiple methods, including the OnStateEnter. It is called everytime the AI enter the state.
My problem is only about optimization, my AI need to get the GameObject "Player" in order to attack it. So i'm getting it in my OnStateEnter method for the moment, which i feel is bad, because i'm getting it every time the animation is called, i would like to get it only once, at the start.
I basicly need a start function but it's not working, i have made research and found nothing. I tried to watch video about people making a finished state machine but they are just getting the same GameObject multiple time ( example here : https://youtu.be/dYi-i83sq5g?t=409 ).
So, is there a way to have a start function or to get an element only once ?
I could make a bool that is called only the first time and that get the GameObject, but again that would be an "useless" if running in my function.
Any suggestions ? Thanks
No, unlike a MonoBehaviour a StateMachineBehaviour has no Start message only OnStateEnter, OnStateExit, OnStateIK, OnStateMove and OnStateUpdate.
There are also Awake and OnEnable but I'm pretty sure they are not used in the StateMachine and might not behave as expected.
You can however either use
OnStateMachineEnter
Called on the first Update frame when making a transition to a StateMachine. This is not called when making a transition into a StateMachine sub-state.
Or use a simple bool flag like
bool alreadyExecuted = false;
OnStateEnter()
{
if(alreadyExecuted) return;
// Do your stuff
alreadyExecuted = true;
}
(Just a guess)
In the Inspector you actually can enable and disable StateMachineBehaviours like components. So it might be able to do this also in script maybe the same way using
enabled = false;
but I didn't find anything about it in the API and since I'm currently on my Smartphone I can't test it.

if (!this) { return; } makes sense in C#?

I'm coding in Unity and I've found that sometimes a method can be called by an Invoke function even if the game object has been destroyed.
That's why I've added this check, and it seems to work correctly, but it's quite weird.
Let's say I have an object that I want to self destroy in one second.
I add an Invoke at the Awake to self destroy it.
But also, I want to destroy the game object instantly if the game is over. The object is subscribed to a Gameover event.
void Awake ()
{
Invoke ("_destroy", 1);
GameMachine.Gameover += _destroy;
}
The _destroy method is like this:
void _destroy()
{
if (!this) {
return;
}
GameMachine.Gameover -= _destroy;
Destroy (this.gameObject);
}
I've added that if (!this) check because I've found that the Invoke could reach the _destroy method, even if the object was already destroyed by the game over event.
This makes any sense, is it possible to happen?
Thanks
As far as I can tell, It will work, BUT, it's not a great idea to do so.
Unity's MonoBehaviour overrides the bool operator. Therefore, when you check
!this
you ARE checking whether the Object (and thereby the script) exists.
As a side note, if you want to unsubscribe events, use the OnDisable function instead. Code example
void OnDisable () {
GameMachine.Gameover -= _destroy;
}

XNA: Preventing a method from returning

I want a method in a DrawableGameComponent class to not return until a particular condition is met
Say I have this class (snippet from a DrawableGameComponent class):
public override void Update(GameTime gameTime)
{
if (moving && pixFromLastMove <= distanceToMove)
{
position += velocity;
pixFromLastMove += velocity.Length();
}
else
{
moving = false;
}
if (rotating)
{
rotation += 0.1f;
var cRotation = MathHelper.Clamp(rotation, -MathHelper.PiOver2, angleBeforeRotation + degToRotate);
if (cRotation != rotation)
{
rotation = cRotation;
angleBeforeRotation = rotation;
rotating = false;
}
}
base.Update(gameTime);
}
public void Ahead(int pix)
{
moving = true;
distanceToMove = pix;
pixFromLastMove = 0;
velocity = new Vector2((float) Math.Cos(rotation), (float) Math.Sin(rotation))*5.0f;
//DO NOT RETURN UNTIL THIS ROBOT HAS MOVED TO ITS DESTINATION
}
public void TurnLeft(int deg)
{
rotating = true;
degToRotate = MathHelper.ToRadians(deg);
angleBeforeRotation = rotation;
//DO NOT RETURN UNTIL THIS ROBOT HAS BEEN FULLY ROTATED
}
This class is being drawn (Draw())in the main thread (because this drawablegamecomponent is executing in seperate thread), and also in the main thread I have a list of commands that I want to be executed in order...but currently, since the Ahead method returns just after assigning a value to velocity, the methods will run almost concurrently, which in turn just executes all the animations at the same time.
So what do you think should I do to prevent methods that are commands (Ahead,TurnLeft etc..) from returning before a certain condition is met?
You need to create some kind of state machine for your Update() method. e.g.
public override void Update() {
if (movingRobot) {
OnlyUpdateRobotPosition();
}
else {
DoStuffPerhapsIncludingStartingRobotMove();
}
}
Or am I missing the question?
Ahh, two words: Cooperative multitasking. With the joy of Fibers (or your cooperative multitasking building block of choice) you could (after laying some ground work, such as this to enable fibers in C#) do something like this:
public void Ahead(int pix)
{
moving = true;
distanceToMove = pix;
pixFromLastMove = 0;
velocity = new Vector2((float) Math.Cos(rotation), (float) Math.Sin(rotation))*5.0f;
//DO NOT RETURN UNTIL THIS ROBOT HAS MOVED TO ITS DESTINATION
while(!HasReachedDestination())
{
Yield(); // let another fiber run
}
}
In order to make this work however you need to implement a simple round-robin scheduler. C# isn't really my boat, but what I'd do is to keep it simple and create some sort of base-class that I'd call Cooperative (or something). This class would have a static list of all created fibers as well as the static methods Create() and Yield(). Create() will create a new fiber (or whatever) and Yield() will simply schedule next fiber to execute (round-robin style), in fiber-world that would include a call to SwitchToFiber(). It will also have a virtual method called Start() (or whatever) that is where the fiber will start to run.
To make it more fancy-smancy you could later keep separate lists of fibers that are either runnable or not runnable (i.e. waiting for something to happen). In that case you might be able to simplify the loop in Ahead to:
WaitFor(HasReachedDestination);
But I suggest getting your feet wet with the concept of cooperative multitasking first.
Finally some thoughts on what should be made fibers, typically your main update loop is one fiber, updating and drawing all objects and then calls Yield(). The all game objects would also be fibers (this may not be feasible if you have a lot of game objects). For your game objects you'd do something like:
public override Start()
{
do
{
if(EnemyToTheLeft())
{
TurnLeft(90); // this will call Yield and return when we have finished turning
Shoot();
}
Yield(); // always yield
}while(!dead);
}
I agree with Pop Catalin: it is probably best not to block in those command functions. I think you could improve your game by thinking about the design a bit more. Let me provide some thoughts for you on how you could possibly improve your design.
First, it sounds like the problem you are describing is that you want to send a lot of move commands, in a certain order, to a game component and have it execute those commands in that certain order. As you have noticed, there is a difference in the time it takes the computer to perform the calculations (for the velocity or rotation) and the time it takes the component to actually perform the action (move or rotate).
The problem with blocking during the calculations (Ahead, TurnLeft, etc) is that the update loop that is calling that function cannot update any other components. That may work okay if there is only one component to worry about, but that's not usually the case in most games.
Now for the good part: how do we fix this problem? I think erikkallen has the right idea, but I would take it a bit further. It sounds like the game component is some kind of entity that will be moving around, so why not give it an action queue? A simple implementation would be to just have your calling function call something like:
gameComponent.queueAction( (MethodInvoker)delegate()
{ gameComponent.Ahead(10); });
Your queueAction function might look like this:
public void queueAction(MethodInvoker action)
{
queue.Enqueue(action);
}
At the top of your Update function you could add:
if(noCurrentAction && queue.Count > 0)
{
((MethodInvoker)queue.Dequeue()).Invoke();
noCurrentAction = false;
}
And you'd need to add a line at the end of the Update function like:
if(!moving && !rotating)
noCurrentAction = true;
Now, I definitely wouldn't call this the best solution, but it doesn't take much code to implement it. Of course if you need to move and rotate at the same time you'll have to tweak it a bit. It will also get messier when you add different types of actions.
For a more general solution, I would think about making a base Action class, and deriving specific action classes from it. Then you could just push actions to the queue, and your Update function could call the action's Update function, which would do the work the two sections of your game components Update function is doing now.
These are just some ideas to think about, I hope something here will get you started.
One last thing I wanted to mention was that I don't see you using gameTime variable that is passed to Update. The amount your component moves and rotates may need to be a function of the elapsed time since Update was last called. Meaning that the Update function would move and rotate your game component based on the amount of time that has passed, not just how many times the Update function was called. I'm not very good at explaining it, and it depends on how you'd like your game to function. Here are a couple different posts from Shawn Hargreaves (XNA expert). Also, an XNA Forum post discussing the point I was trying to make.
Although I find your design somewhat odd, best way to accomplish what you want is to use an EventWaitHandle and signal it from another thread.
Say you have an instance of the waithandle on your class
you can call waithadle.WaitOne() in your method, and signal the even from another thread using waithandle.Set() when the condition is met, at which point your method will resume from waiting.

Categories