Reagieren, wenn der SceneManager ein Level nicht lädt
Wenn man in Unity versucht, eine nicht-existente Szene über den SceneManager zu laden, dann erscheint zwar eine Fehler-Meldung im Log-File bzw. der Editor-Konsole, aber es gibt scheinbar keinen direkten weg, um per Code darauf zu reagieren. Das Abfangen von Exceptions, sofern solche überhaupt auftauchen, wirkt in Unity generell etwas unzuverlässig, da das Log-System bereits viel abfängt und verarbeitet. Unklar erscheint mir zudem, wieso die Methode SceneManager.LoadScene
nicht einfach einen Rückgabewert liefert, der über den Erfolg der Methode Auskunft gibt. Möglicherweise hängt es damit zusammen, dass Ladevorgänge auch asynchron ablaufen können und daher Fehler unter Umständen nicht sofort ermittelbar sind.
Durch Systemüberwachung Rückschlüsse auf den SceneManager ziehen
Nun ist es zwar so, dass der Level-Ladefehler meistens beim Testen im Editor auffallen dürfte und schlicht durch Inklusion der fehlenden Szenen-Assets zu beheben ist. Dennoch hat mich die Frage beschäftigt, wie man auf den Fehler reagieren kann. Die gefundene Lösung besteht darin, dass man das Log-System während des Ladevorgangs überwacht. Bei jeglichem Protokollierungsvorgang (also Debug.Log...
) werden hier eingeschriebene Funktionen benachrichtigt, so dass man kurzum prüfen kann, ob während des Ladens ein Fehler auftrat. Wenn dem so ist, ist in Schlussfolgerung das Fehlschlagen des Ladevorgangs zu vermuten.
Folgender Abschnitt skizziert das Prinzip:
... bool errors=false; ... Application.logMessageReceivedThreaded += Application_logMessageReceived; SceneManager.LoadScene("nonexisting"); Application.logMessageReceivedThreaded -= Application_logMessageReceived; if (errors) { ... scene could not be loaded } ... private void Application_logMessageReceived(string condition, string stackTrace, LogType type) { if (type==LogType.Error) errors=true; }
Schnelle und einfache Lösung mit WatchForError-Klasse
Ich habe dem GameDev-Profi-Toolkit eine Klasse namens WatchForError
hinzugefügt, die nach dem oben beschriebenen Prinzip Log-Fehler zählt. Sie lässt sich für fehlerhaftes Szenen-Laden als auch ähnliche Situationen anwenden.
using GameDevProfi.Utils; //https://github.com/renebuehling/GDP-Toolkit ... WatchForError watch = WatchForError.startNew(); SceneManager.LoadScene("NonExistingLevel"); if (watch.stop().errors>0) Debug.Log("Scene could not be loaded.");
Eine Exception werfen, wenn die Szene fehlt
Möglicherweise willst Du bei Auftreten unterschiedlichster Umstände oder Fehler in die selbe Fehlerbehandlung springen. Dann eignet sich ein Try-Catch
-Block, der sich mit WatchForError
ebenfalls bedienen lässt:
try { WatchForError watch = WatchForError.startNew(); SceneManager.LoadScene("doesnotexists"); if (watch.stop().errors>0) throw new Exception("Scene not loadable."); //... do things if scene loading was ok ... } catch (System.Exception e) { Debug.Log("Scene not loadable! Return to levelmap."); //... do something when any error occurred above ... }