I have a game that will have several massive levels that flow right into each other (it's a Metroidvania game), and so I need to unload levels when the character leaves those areas, so that it doesn't crash the game due to using too much memory.
I've already tried:
void OnTriggerExit2D(Collider2D coll)
{
SceneManager.UnloadScene(sceneIndex);
}
However, I read somewhere that you can't call UnloadScene from physics triggers for some reason. https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.UnloadScene.html
But they say to use UnloadSceneAsync, which doesn't exist. The link in the documentation is broken and my program won't compile when I try to use it.
How to go about this? How does one unload a scene after the character leaves it?
EDIT: I've also tried this, but it won't compile:
void OnTriggerExit2D(Collider2D coll)
{
SceneManager.UnloadSceneAsync(sceneIndex);
}
The UnloadSceneAsync was added in Unity 5.5 which is still in beta version. The only way to have function available to you is to download the beta version. This is the documentation and you can get the latest Unity 5.5 (v5.5.0b10 as of writing this) from here.
You can verify this by going to the Release Note here.
Press Ctrl+F then search 'UnloadSceneAsync'. It says:
SceneManager: Added UnloadSceneAsync API which can be called anytime unlike UnloadScene.
SceneManager: UnloadScene has now be marked deprecated and will throw an exception if called at illegal times. UnloadSceneAsync
should be used instead (762371)
Related
I am making a game where you must open or activate the UI with the space bar. Now, this works perfectly fine, but it is pretty annoying that every time you open the UI you must click on the inputfield to write in it. Is there any way around this? So is there a way to open or activate the UI without having to click on the field to be able to write in it?
I looked for YouTube videos and tried to find similar problems in other forums, but wasn't able to find a script, nor was I able to find some Unity settings to do so.
You could use e.g.
private class SelectOnEnable : MonoBehaviour
{
private void OnEnable()
{
EventSystem.current.SetSelectedGameObject(null);
EventSystem.current.SetSelectedGameObject(gameObject);
}
}
and attach it to whatever object that should become the selected one everytime it is enabled. See EventSystem.SetSelectedGameObject
Can't test it right now but it might still require the User to hit Enter in order to also actually set the Input field into edit mode. The upper line only sets it as selected UI element (similar to using TAB in a browser).
Otherwise I think you would go through
yourInputField.DeactivateInputField()
yourInputField.ActivateInputField();
to directly set it active. See InputField.ActivateInputField. Might have to do both in combination - again can't test right now ;)
Thank you very much, derHugo! Everything works like a charm now! You saved me a lot of time. Referring to your last comment, I used both of them, and it seems to work very well for me. Here is the code I used:
`private void OnEnable()
{
EventSystem.current.SetSelectedGameObject(gameObject);
GameManager.GetComponent().inputFieldInMainUi.ActivateInputField();
EventSystem.current.SetSelectedGameObject(null);
GameManager.GetComponent<InputFieldComparision>().inputFieldInMainUi.DeactivateInputField();
}`
I have my object in Unity and this object has a destructor as well as Awake method
...
private void Awake()
{
Debug.Log("AWAKE");
}
~UnityHumanObject()
{
Debug.Log("DESTRUCTOR");
if (stream != null)
{
stream_release(stream);
}
}
...
when I click on Run button according to the log I see that destructor prints his log message 3 times and just after that I see Awake log message... Next, if I click stop (Run button again), I don't see that destructor even get a call.
So, question is - why when I click on run button first of all I get 3 time call to destructor and secondly why if I stop Unity I don't actually get destructor call?
You may wish to implement a receiver for OnDestroy() instead.
See https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnDestroy.html
I don't know the full ins and outs of how Unity engine works, but I can tell you that things that derive from UnityEngine.Object (which includes MonoBehaviors) are a hybrid type that is part managed-code and part unmanaged-code. The Editor is also an arcane beast in that it runs your scene as you're editing it, but restricts certain Messages/calls until you're in "play" mode (or register with the ExecuteInEditor attribute).
With all of that, it becomes quite impossible to manage your code using low-level constructors and destructors if you're extending any of the Unity classes. Simply put, don't do it unless the Unity-specific functionality doesn't support what you need. In your case, closing a stream, using an OnDestroy() function should be perfectly sufficient.
We've created a small demo of Unity3D with AirConsole-plugin which is working in Unity debugger. (If I press play, the browser opens, sometimes it works, sometimes it doesn't. If it doesn't, one can restart Unity and then it works.)
If we create a release or a developer build, it does no longer work. It will load the image correctly, but the controllers (virtual+phone) stay 'loading' most of the time. Sometimes they reach the first correct HTML page, but then the message they send doesn't seem to arrive on the screen-side.
When I click the 'Open Exported Port' after the build, it doesn't work too, except for once.
One error message I got once:
"Uncaught TypeError: Cannot read property 'postQueue' of undefined"
This error message appears always:
"pre-main prep time: 176 ms UnityLoader.js:1
Module.printErr # UnityLoader.js:1"
Do you know what these error messages mean?
I've tried a lot, but this seems to solve the problem: Be sure to attach the event listeners in the Awake method, as they do in basic example application.
public class AirConsoleService : MonoBehaviour
{
void Awake()
{
// register events
AirConsole.instance.onReady += OnReady;
AirConsole.instance.onMessage += OnMessage;
AirConsole.instance.onConnect += OnConnect;
AirConsole.instance.onDisconnect += OnDisconnect;
// etc. ...
}
// etc. ...
}
My problem was that my AirConsoleService was static and not a MonoBehaviour to be sure that there is only one instance of AirConsoleService. It works perfectly for the debug 'play' mode, but in the release build, the AirConsole somehow does not know the deviceID which sent the message (this means, we get -1 from method ConvertDeviceIdToPlayerNumber. And this explains why the controllers don't get any signal from the screen.
My solution: I've attached it as a component to the AirConsole object.
Further notes:
Anti-Virus may block content.
Your PC/server has to be fast.
During development, log the deviceID and the playerID and the current active deviceIDs.
Often restart Unity or the integrated webserver of the plugin
I'm still pretty new to scripting in Unity3D, and I'm following along with a tutorial that uses GUI.Button() to draw a button on the screen.
I am intrigued by how this function works. Looking through the documentation, the proper use of GUI.Button is to invoke the function in an if statement and put the code to be called when the button is pushed within the if statement's block.
What I want to know is, how does Unity3D "magically" delay the code in the if statement until after the button is clicked? If it was being passed in as a callback function or something, then I could understand what was going on. Perhaps Unity is using continuations under the hood to delay the execution of the code, but then I feel like it would cause code after the if statement to be executed multiple times. I just like to understand how my code is working, and this particular function continues to remain "magical" to me.
I don't know if it's the right term, but I usually refer to such system as immediate mode GUI.
how does Unity3D "magically" delay the code in the if statement until
after the button is clicked?
GUI.Button simply returns true if a click event happened inside the button bounds during last frame. Basically calling that function you are polling: every frame for every button asking the engine if an event which regards that button (screen area) is happened.
If it was being passed in as a callback function or something, then I
could understand what was going on
You are probably used to an MVC like pattern, where you pass a controller delegate that's called when an UI event is raised from the view. This is something really different.
Perhaps Unity is using continuations under the hood to delay the
execution of the code, but then I feel like it would cause code after
the if statement to be executed multiple times.
No. The function simply returns immediately and return true only if an event happened. If returns false the code after the if won't be executed at all.
Side notes:
That kind of system is hard to maintain, especially for complex structured GUI.
It has really serious performance implications (memory allocation, 1 drawcall for UI element)
Unless you are writing an editor extension or custom inspector code, I'd stay away from it. If you want to build a menu implement your own system or use an external plugin (there are several good ones NGUI, EZGUI,..).
Unity has already announced a new integrated UI System, it should be released soon.
Good question. The unity3d gui goes through several event phases, or in the documentation
Events correspond to user input (key presses, mouse actions), or are UnityGUI layout or rendering events.
For each event OnGUI is called in the scripts; so OnGUI is potentially called multiple times per frame. Event.current corresponds to "current" event inside OnGUI call."
In OnGUI you can find out which event is currently happening with >Event.current
The following events are processed link:
Types of UnityGUI input and processing events.
-MouseDown
-MouseUp,mouse button was released
-MouseMove,Mouse was moved (editor views only)
-MouseDrag,Mouse was dragged
-KeyDown, A keyboard key was pressed
-KeyUp A keyboard key was released.
-ScrollWheel The scroll wheel was moved.
-Repaint A repaint event. One is sent every frame.
-Layout A layout event.
-DragUpdated Editor only: drag & drop operation updated.
-DragPerform Editor only: drag & drop operation performed.
-DragExited Editor only: drag & drop operation exited.
-Ignore Event should be ignored.
-Used Already processed event.
-ValidateCommand Validates a special command (e.g. copy & paste).
-ExecuteCommand Execute a special command (eg. copy & paste).
-ContextClick User has right-clicked (or control-clicked on the mac).
Unity GUI has much improved lately and is quite usefull if you want to handle things programmatically. If you want to handle things visually, i recommend looking at the plugins heisenbug refers to.
If you decide to use unity gui, i recommend using only one object with ongui, and let this object handle all your gui.
Currently I'm writing a script that automatically writes a file with all the scene names as variables. I would like to catch a certain event (if it exists) so that I could know when any scene was added or changed it's name. Currently I have to manually press a button whenever I add a scene or rename one. But since I'm not going to be the only one on my team using this, I'd like to automate this.
Some kind of update cycle would work too, I could then check if the current build list matches my list and if not, update it.
I've tried OnHierarchyChange / OnProjectChange, but those only seem to work on certain assets. Any idea to catch this event?
For future readers:
For Unity 5.3 and below use function OnLevelWasLoaded
http://docs.unity3d.com/530/Documentation/ScriptReference/MonoBehaviour.OnLevelWasLoaded.html
Unity 5.4 + use event: SceneManager.sceneLoaded
http://docs.unity3d.com/540/Documentation/ScriptReference/SceneManagement.SceneManager-sceneLoaded.html