0
\$\begingroup\$

I try to understand what's the best way to handle error conditions in Unity. In a lot of places I've read that throwing exceptions is a bad thing. Unfortunately, I have not found any guidance on Unity website on this matter as well finding clear guidance on the wide Internet is also difficult.

What I use quite often is Debug.Assert statements to check that certain conditions for proper operation are met.

But what to do, if something unexpected happens? Some examples could be:

  • Network connection lost
  • File write operation failed (for some reason)

What is a good practice to handle these situations? Just do a Debug.LogError to log important info and then let the game crash?

Happy to hear your thoughts on this.

Thanks!

Update 12.08.2019 22:06

Based on the comments received, I have added the code example below with some comments / thoughts from my side.

Example: Load Level Data From JSON File

In this example, I load level data from a JSON file (SceneData.json). It could theoretically happen, that the level file is not available. I do not check the result of Resources.Load() yet, but if the file cannot be found, a NullReferenceException is thrown. I have not tested this yet, but I think a NullReferenceException will terminate the whole Unity game at runtime. So how to improve this situation in a way, that informs the player about this problem? What can be done to support the developer in fixing the issue?

Some thoughts from my side for improving code:

  • I should check the return value of Resources.Load(). If it is null, I also issue a Debug.Error log. That way, the problem gets logged to the console during testing/development but also to the Player.log on the target system (e.g: Windows).
  • If I want to inform the player about the problem, I could return null in the GetDragAndDropLevel method to inform the caller about the fact, that no level was loaded. I could the further propagate this information up the call stack to display an error message in the GUI at the end.

Does this sound reasonable in the Unity context? Or do you guys do this stuff completely different?

public static DragAndDropLevel GetDragAndDropLevel(GameLanguage language, GameScene scene, int level)
{
    Debug.Assert(level >= 1);

    // Generate filename
    var sceneDataFilename = "SceneData/" + scene + "/SceneData";

    // Read JSON structure into SceneDataDragAndDropLevel object
    var textAsset = Resources.Load<TextAsset>(sceneDataFilename);
    var jsonData = textAsset.text;
    Logger.LogDebug(jsonData);
    var sceneData = JsonConvert.DeserializeObject<SceneData>(jsonData);

    var numLevels = GetNumberOfLevels(sceneData, GameType.DragAndDrop, scene);
    Debug.Assert(level <= numLevels);

    // Generate level object
    var dragAndDropLevel = GetDragAndDropLevelFromSceneData(sceneData, level);
    return dragAndDropLevel;
}
\$\endgroup\$
  • \$\begingroup\$ This is a rather large, complicated subject. I recommend finding a particular place in your project where you need help and ask that as a more specific question. \$\endgroup\$ – Almo Aug 12 at 19:53
  • \$\begingroup\$ The best way to handle an error typically depends on the error. If it's an optional item — like connecting to a telemetry service — silently logging the error and letting the game continue uninterrupted might be best. If it's a required item, like loading the game map, then there might be no reasonable way to proceed with the game if the operation fails, and all you can do is clearly explain the failure and offer troubleshooting steps. As Almo says, can you edit this question to focus on one specific error type you need advice on handling? You can always ask about a different type separately. \$\endgroup\$ – DMGregory Aug 12 at 19:55
1
\$\begingroup\$

In most cases you should avoid exception handling, and make sure your code deals with all the edge cases. It adds extra processing that is very noticeable. This is very easy when you control all the end points your code touches.

It is not possible when working with uncontrolled sources, like services, networks, and files. At these points, you are right to wrap them in try catches. You have no choice, unless the application has safety calls. Similar to TryParse on Int or Float.

In cases where you need to try catch, try to keep it as isolated as possible. No reason to keep try hooks on things that don't need it. In many cases, like the file system, there are checks you can do about permissions or availability. The chances of a file becoming inaccessible during play beyond that are typically related to something they are doing, like running a hack app on save files, or their system is crashing anyway.

In regards to repairing issues down the road, turn on Analytics in Unity. You can get reports on all kinds of stats including crashes. Or you can get similar checkups through google or other analytic API's. I recommend Unity Analytics, simply because its designed specifically for it, including crash reporting.

In regards to notifying the player, when you have minor items, like a section of the game doesn't come up, because the level doesn't load, then yes, you want to capture those situations by catch or by logic, and announce it to the player nicely, that this section is failing to load. Perhaps apologies in the message and offer a bonus of coins or something. Additionally, something I have done in the past, is record crash or blocking errors and the users associated with it. After resolving it, send a message out, (or post it though your game, filtered to the users affected) that calls out the issue, that it has been repaired, and offer a reward/welcome.

\$\endgroup\$
  • \$\begingroup\$ That type of answer was exactly what I was looking for. Actually, I would like to see something like this in an official Unity guide / tutorial. But haven't found it yet. Therefore, thanks for this! \$\endgroup\$ – André Gasser Aug 13 at 5:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.