- Home /
OnGUI called after WaitForEndOfFrame on mouseDown events
When running this code:
public class TestScript : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
Debug.Log("----------------beginning of frame");
StartCoroutine("EndOfFrame");
}
private void OnGUI()
{
Debug.Log("------------OnGui" + Event.current.type);
}
IEnumerator EndOfFrame()
{
yield return new WaitForEndOfFrame();
Debug.Log("----------------end of frame");
}
}
We get this output:
----------------beginning of frame
------------OnGuiLayout
------------OnGuiRepaint
----------------end of frame
----------------beginning of frame
------------OnGuiLayout
------------OnGuiRepaint
----------------end of frame
------------OnGuiLayout
------------OnGuimouseDown
----------------beginning of frame
------------OnGuiLayout
------------OnGuiRepaint
----------------end of frame
To our knowledge, the "endOfFrame" text should happen after the "OnGuimouseDown" text but before the "beginning of frame" text, but instead it always appears after the "OnGuiRepaint" text. Is there something we are doing wrong with the yield WaitForEndOfFrame coroutine? It happens in a built engine and in the editor.
OnGUI is called in a FixedUpdate manner.... meaning several times between frames.
OnGUI is also being depreciated soon. I suggest a Prefab > Instantiate method to avoid problems with your project/updating Unity.
OnGUI isn't being deprecated. Why does everybody spread that information? The immediate mode GUI is still used by the Unity editor. The whole interface of the editor is using the immediate mode. Even the new GUI still uses parts of the Event class for keyboard input processing.
"I$$anonymous$$GUI is a code-driven GUI system, and is mainly intended as a tool for programmers."
http://docs.unity3d.com/$$anonymous$$anual/GUIScriptingGuide.html
I think by this comment they mean not intended for a UI solution in a project. Prolly a good idea to not tell people to implement for a final solution as a UI in a game.
Answer by Bunny83 · Jun 03, 2016 at 09:10 PM
You interpreted the result wrong. It's not called after the end of the current frame, but at the beginning of the next frame. The input processing happens before Update. Try printing Time.frameCount with each of your Debug.Logs to see to which frame the log belongs. See the event order. The diagram isn't complete but it should give a better overview. Note that the point "GUI rendering" really only includes the actual repaint event, not the input processing which is done at the beginning of the frame.
There is no reliable callback that is always called at the very beginning of a frame. The best option is to do frame initialization things at the very end of your "WaitForEndOfFrame" coroutine.
An alternative is to do initialization in a seperate method which you call before anything else in any of your functions. The method only executes it's body if the current frame count is greater than the last saved frame count.
int lastFrame = -1;
void Init()
{
if (Time.frameCount > lastFrame)
{
lastFrame = Time.frameCount;
// Do your frame initialization here.
}
}
You can savely call Init as often as you want before you do anything else. This method will only execute once per frame due to the frame count check.
This is a great answer, thanks for the insight! Indeed the frame count increases just before those last two GuiLayout and Gui$$anonymous$$ouseDown events. It looks like the documentation is incorrect like you said, in that OnGui input events are handled before the Update function is called, rather than in the Gui Rendering area (which makes sense from a standard game loop perspective).
I'll try out your Init() function idea. Thanks!
Your answer
Follow this Question
Related Questions
Increment variable over time 4 Answers
Blinking & resource consumption 1 Answer
StartCoroutine gets the arglist type wrong 1 Answer
Invoke isn't working for a function with yield? 2 Answers
Yielding in a loop only as needed? 0 Answers