Unity StateMachineBehaviour : Start function called once? - c#

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.

Related

Calling function more than once causes gameplay issues in Unity

I am currently working on translating a VR game to the Oculus Quest 2 from a PC standalone version. In this game, the game menu cannot be accessed by the player wearing the headset, as it is not visible to the player; it is instead accessed by another party at the computer itself. When the person at the computer clicks, start game, a number of processes begin, including a coroutine to spawn multiple instances of a game object in a non-player enemy's hands.
Part of the translation process includes allowing the player to start the game from the Oculus Touch controllers, I am attempting to implement a feature where either of the four face buttons will start the game.
if (OVRInput.GetDown(OVRInput.Button.One) || OVRInput.GetDown(OVRInput.Button.Two) || OVRInput.GetDown(OVRInput.Button.Three) || OVRInput.GetDown(OVRInput.Button.Four))
{
startGameClick();
}
However, it seems like calling startGameClick(); more than once, whether in the same script or otherwise, causes the game to not run certain processes, chief among them the ball spawn coroutine. This causes the NPC enemies to activate their throwing animations without having a ball to throw, and they do not return to their idle animations afterwards. I am unsure why this is, however it has been a major roadblock in attempting the platform translation.
Additionally, this is the startGameClick(); function:
// If the start game button is clicked
public void startGameClick() {
StandaloneServer.startgame = true;
if (Master.usingMM && ServerController.IsServerReady())
Master.ready = true;
else if (!Master.usingMM)
Master.ready = true;
roundController.startInput();
beginGameButton.GetComponentInChildren<Text>().text = "In Progress";
beginGameButton.interactable = false;
}
My assumption is that one of the references in this function is the source of the issue, but I cannot pinpoint which one.
Base Information
Unfortunately, to answer your question, we would need to see all of the related scripts for this function which just isn't feasible as that would also require us to be kind enough to sift through your code to find your error.
A Cheap Solution
However, there is a cheap solution to your issue. You can simply reload the scene (or reset the script if it's DNDOL) and it should work again.
It seems I've found a solution at long last.
Instead of calling the startGame() function again, I decided to invoke onClick() to simulate the effect of clicking the button with a mouse, although the player is actually touching the button in the VR space. This worked, and the game is running as it should.

Stopping the character from moving

So I'm using the unity standard assets pack and I was trying to figure a way to freeze the players location, at first I tried to freeze the players location using the rigidbody but the character was still able to walk. Next I tried to disable the script that allows the player to move but I cannot see the script is other scripts (when I use public script name variable name it doesn't show up as a script name.
Since I can’t see the script, I don’t have much to go off of, but I’m assuming you’re using some either Input.Horizontal and Input.Vertical, or Input.getKey() to do your things.
If you want to freeze the movement, you can simply wrap the function for movement that you are using in an if statement with some kind of bool that contains whether or not the player should be frozen.
Example:
If(!frozen){
Player.Position.x += 5;
}
Or something like that.
If you need to get the variable in another script you could do something like this (this is a rough example to try to explain it, syntax may not be perfect):
GameObject player;
Player.MoveScript.frozen = false;
Something like that.

Why not finish all the functions within Update() function in unity

void Update() can perform the functions per 1 frame . So in script , e.x like
void OnTriggerEnter(){} . why don't put it in update() function .I know there's some misunderstanding here but I just can't explain it to myself .Besides , is that only void Update() , void Start(){} that functio in unity .Including some functions like void OnTriggerEnter can function as well in unity since it is built-in functions .How about those functions that written by us like public void SwitchAvatar() .Can it function if it is not referred inside void Update(){} .I know the questions above may sound stupid , but dunno why I can't tell the answers .All of your help is greatly appreciated . Thanks !
Alright, let's open pandoras box about magic methods in Unity.
First, there are two types of classes that you can inherit from, to access magic methods: MonoBehaviour and ScriptableObject. Both of them offer different things and the latter is mainly used to serialize data outside of scenes. Also, ScriptableObject has way less magic methods, compared to MonoBehaviour.
Second: A MonoBehaviour has a lifecycle. Where you are in this lifecycle determines what methods are called by the engine.
The following graphic shows you the whole lifecycle of a MonoBehaviour:
(Source: Unity - Manual: Order of Executions for Event Functions)
As you can see, the object gets instantiated and Awake is called. Before the first time Update is called, the engine calls the Start method. There is a difference between Awake and Start: Awake is comparable to a constructor. It is called without anything external being guaranteed to exist (like other components on your GameObject). When Start is called, all the other components on the object are initialized and can be accessed by a GetComponent call.
Now to Update, FixedUpdate and all the other events:
Unity has two separate cycles it iterates over. One for physics and one for everything else. Because calculating physics is expensive and needs precision, it is called in fixed, distinct time steps. You can actually set them in the project settings in the "Time" tab.
Now if you want to modify anything related to physics (like the velocity of a rigidbody), you should do that in FixedUpdate, because it runs in the same time step as the physics engine (PhysX or Box2D, depending on your usage of colliders).
Update on the other hand runs as often as possible. The current time distance between two Update calls can be observed by calling Time.deltaTime, which is the time that is passed between two Update calls. Note that Time.fixedDeltaTime is always the same, as it is the time between two physics calls.
The other event methods are called as responses to either the editor internal update loop, the rendering loop or the physics loop. Whenever an object collides in the physics calculation, OnCollisionEnter is called. Note that this can't happen out of Update, because, as we know, Update is not used to calculate physics.
Okay, a tl;dr:
Start and Update are not the only methods that exist in the MonoBehaviour lifecycle, there are plenty and each has its purpose. Physics are calculated in a different timescale as the Update method is called and thus cannot be part of Update.
And one thing to take away: You should really read the manual of the game engine you are using. There is plenty of stuff that you should know when you are writing code for a real time application and if you build onto an existing game engine, you should check the docs of that regularly. Especially the documentation of Unity is a very good read for both code and editor usage.

Call a function in Unity Editor

I need a script, which takes a big amount of monobehaviors in children and arranges them to lists in parent script in a specific way to save parent as prefab. It would take a eternity doing in by hand. And i dont wanna do this in Start() on runtime, because these prefabs could be instanciated a bunch times per frame and causing mini lag spikes when searching for scripts in children. So how do i do this once in a editor to save all references to prefab? Never done something like that, but seen buttons in custom inspector that call functions for plugins. I tried [ExecuteInEditMode] which gives good result but it also continue to execute in runtime So asking what way would be simplest to just call a function in editor and make it not work in runtime?
Try something like this:
[ExecuteInEditMode]
public class YourClass : MonoBehaviour
{
void Update()
{
if (!Application.isPlaying)
{
Debug.Log("This should only run in edit mode.");
// More code
}
}
}
Depending on what you're trying to do exactly, there might be a better way to trigger this than ExecuteInEditMode, but this is the simplest way of getting the effect you requested. This won't run as long as Application.isPlaying returns true. So it will never run in playmode and never run in any builds.

DontDestroyOnLoad is not Working on Scene?

I Need to apply DontDestroyOnLoad on Scene.is it possible?
I Need to Do not disturb the scene when going in to another scenes also.here i'm sending mail,when ever clicking send button its going to authentication in mail server in this time my scene idle means not responding anything until come back to the response from mail server,so on that time i show one loading bar in my scene.this is not do process.the entire scene is hang until came response from mail server,so how to solve this?
void Awake()
{
DontDestroyOnLoad(this.gameObject);
}
After reading so many non-answers I finally found the answer in a Unity forum. DontDestroyOnLoad ONLY works if the game object in question is at a "root level" meaning right under the scene, not nested under any other object. This is not mentioned anywhere in the documentation.
When loading a new level, scene, all Game Objects of the previous scene are destroyed by Unity.
If you want to protect a Game Object you can use the function.
DontDestroyOnLoad(gameObject);
It is important to note that when you say: this.gameObject you are pointing to pretty much the same thing, it just happens that this points directly to the script attached to that gameObject. So you don't need the this part, just gameObject will do.
Ideally you could protect that gameObject inside void Awake()
void Awake()
{
DontDestroyOnLoad(gameObject);
}
The above code will prevent Unity from destroying that gameObject unless your game closes completely or at a later point you call Destroy() on it. That means you can change from scene to scene and the gameObject will survive. However, if you make it back to the scene that creates that gameObject you are protecting you may run into problems if you do not have the logic implemented that prevents you from protecting a second, third, or many of that gameObject.
Your second question, if I understand it correctly:
You want to send mail when you change scenes, but your progress bar wont progress while changing scenes, it just stays there, static.
If that is the case then your problem is in Application.LoadLevel(sceneName); If you have the free version of Unity, then you need to come up with your own creative way of showing that progress bar, because Application.LoadLevel() will halt everything until it takes you to the new scene.
I don't completely understand what you are saying.
But because in your context, this in represents most probably a Monobehaviour, try the following:
void Awake() {
DontDestroyOnLoad(this.gameObject);
}
or
void Awake() {
DontDestroyOnLoad(gameObject);
}
See http://docs.unity3d.com/Documentation/ScriptReference/Object.DontDestroyOnLoad.html
I recommend you use a coroutine, with the 'yield' statement
check out this documentation of the WWW class, which likewise involves writing code to cope with waiting for a response from the web, without hanging your Unity3d program
coroutines are pretty powerful if you're working with tasks that take more than a frame or two. Richard Fine (AltDevBlog) has posted a really detailed description of what they are and how to use them, which I thoroughly recommend.

Categories