A Story of NullReferenceException [Part 1]

Once upon a time there was a little boy living with his mother alone between the mountains. They lived a peaceful life. One day the boy’s mother got very sick. The boy called for a doctor, the best in the valley. When the doctor finally came, he examined the woman. Unfortunately, there was only one medicine for her illness and this medicine was very hard to get. The only known location was far away from there, on very dangerous lands, full of traps and monsters. Without thinking too much, the boy took his wooden sword, backpack and he went on a trip where… NullReferenceException.

NullReferenceException

If there’s one thing that is common for most of Unity games, this thing is NullReferenceException. This little fella can be quite a nuisance, especially on mobile platform, where you most probably want to have a script call optimization set to Fast But No Exceptions. That’s because any exception will cause your application crash immediately. Is this worth the risk? It depends on the time your game requires to execute all the scripts in each frame.  The more time it needs, the more you will benefit from enabling the optimization.

What NullReferenceException is?

Before killing the dragon, we must fight the dragon. Before fighting the dragon, I would say that we have to get to know the dragon. NullReferenceException is so common issue, that is has its own Unity documentation page! But let’s compare it with official .NET documentation definition.

Official:

In this article we will talk about techniques that will help you minimize NullReferenceException occurrence possibility.

Unity:

A NullReferenceException happens when you try to access a reference variable that isn’t referencing any object. If a reference variable isn’t referencing an object, then it’ll be treated as null.

So this means that if you have a reference (field or variable) that is not pointing to any object (is null) and you try to access it (access parameter, field, or execute a method of this non-existing object), then you will receive a NullReferenceException.

But… there’s one subtle, yet important, difference with NullReferenceException when working with Unity objects. Normally, you may do a check if an object is null before trying to do anything with it:

But Unity objects are a bit different. Unity objects can report themselves as null even if they are still referencing an object!

No, that’s not a bug! Some referenced objects are scene objects. Imagine what happens if a scene is being replaced by another scene – all regular scene objects have to be destroyed. Since Unity cannot update your valid references inside your code (they still will be valid after destroying the scene), it is faking a null check for those that you are still referring to, so it will (should) stop you from use these any longer. In case you do try to use any of these objects, you may receive a message like this one:

reference object destroyed

It is also an exception that will crash your app, so be warned!

Fail Fast

The worst and yet the most common case of NullReferenceException is when your component expects some other objects to be passed into it through the inspector, but for some reason somebody didn’t do it.

The example above is a simplified situation when you want to display a label when player touches the star. Collider other is guaranteed to be a valid reference (based on documentation), but what we cannot be sure about, is the scoreText field that should be visible in the inspector. What if somebody forgets to assign it? You will know about it only after trying to touch the star. That’s definitely too late!

We can handle these kind of situation using Asserts (we talked about asserts before). Asserts will tell us if something is wrong, and it’s a wise choice if all the checks can be done right after the scene is launched. Let’s try to add an assert like this:

This code will yield an error right after the scene is started. We no longer have to wait for the player to touch the star. That way we can check if everything is OK with the scene just by launching it!

Do I have to add an assert for each inspector object? Yes! You cannot trust that someone  doesn’t break your scene references.

Public field is not bulletproof

Have you noticed that public fields can be accessed from any place? Yep, this can be bad. This means that any other script may get to it and set it to whatever it wants to. Assert won’t help us if other script will decide to replace our reference in the middle of playing the game.

To make it a little more bulletproof, we can make it private. Private fields can be displayed and assigned within the inspector, but a field like that needs a [SerializeField] annotation:

Now, the field cannot be accessed outside the current object what makes the risk of unexpected NullReferenceException significantly lower.

To be continued…

You can read the second part of this article here.

Wrong Import Settings are Killing Your Unity Game [Part 2]

There are many things that may go wrong with your game development. Your models may have too many triangles for your target platform to handle, your algorithms may be too expensive for your CPU, and also you may be using too many materials so batching won’t work efficiently. These are difficult issues, and you as a game developer should always remember to keep good balance between visuals and performance. Yet, there are some things so simple that we often forget about their existence, but these can have a serious impact on your game performance.

Last time, in Part 1, we talked about how texture import settings can kill your game performance. This time we will talk about sound import settings and why it matters.

Audio Clip Import Settings

When working with Unity many things can keep their default settings set and everything will be working just fine. Of course, defaults are not optimal in most cases, but your game should be working OK. This rule unfortunately does not apply to Audio Clip Import Settings.

Audio Clip (sound files) importing is working very similar to texture importing. Unity supports many different audio formats, but in the end it converts them all to preferred (by the engine) format. Currently, in Unity 5.2.1 this can be PCM, ADPCM, Vorbis/MP3 and HEVAG. Note that not each platform can handle all of these compression formats, and some platforms have only one format available (e.g. WebGL can work only with AAC audio clips).

Memory matters

All Audio Clips are imported by default with “Decompress On Load” Load Type and “Vorbis” Compression Format.

These are default import settings.

These are default import settings.

You should be very careful with this setting, because using it on all your audio clips (Unity does it by default!) may consume large amount of your game’s memory! Do you see the info box on the screenshot? Original file size is computed to 35.9 MB and the imported size to 10.7 MB. This means that this Audio Clip will increase your game (archive) size by 10 megabytes, but playing it will require nearly 36 megabytes of RAM! This does not sound too scary if you’re building a game for PC where it is quite common to have 8 gigabytes of RAM, but mobile devices are still very limited on that manner.

When I should use specific Load Type?

Let’s get this straight. Each Load Type and Compression Format combination can be used and you’re the one who knows best which one should be chosen. There are three Load Types:

  • Compressed In Memory – Audio Clip will be stored in RAM and will be uncompressed when played. Does not require additional memory for playing.
  • Streaming – Audio Clip will be stored on a device persistent memory (hard drive, flash drive etc) and streamed when played. Does not require RAM for storing and playing (at least this value is not significant).
  • Decompress On Load – Audio Clip will be stored in RAM uncompressed. This option requires the most memory but playing it won’t require so much CPU power as the rest.

So, which one to use? It depends…

Music and/or Ambient Sounds

Music is stored in long Audio Clips so it can consume a lot of memory. For sure, we don’t want music to be decompressed into the memory then played. You have two options here:

  1. Use Load Type “Streaming” and Compression Format “Vorbis”. This combination will use the least amount of memory but will require some CPU power and disk I/O throughput.
  2. Use Load Type “Compressed In Memory” and Compression Format “Vorbis”. The only difference from the first solution is that it will exchange the disk I/O with some memory requirement. Note that you can adjust the Quality slider to decrease compressed clip size in exchange of sound quality. Usually 100 percent is a way too high. I would recommend something around 70 percent.

Note that if you have more than 2 music/ambient sounds clips playing like this, it can consume a serious amount of CPU power.

Sound Effects

Sounds effects are usually short or medium Audio Clips. Also these can be played frequently or rarely. Here are some rules:

  1. For frequently played and short Audio Clips use Decompress On Load and PCM or ADPCM Compression Format. When PCM is chosen, no decompression is needed and if audio clip is short it will load very quickly. You can also use ADPCM. It requires decompression, but it is much lighter to decompress than Vorbis.
  2. For frequently played but medium Audio Clips use Compressed In Memory and ADPCM Compression Format. ADPCM is around 3.5 times smaller than raw PCM and decompression algorithm will not consume as much CPU as Vorbis.
  3. For rarely played and short Audio Clips use Compressed In Memory and ADPCM. For the same reason as described in point 2.
  4. For rarely played and medium Audio Clips use Compressed In Memory  and Vorbis Compression Format. This SFX might be too long to be stored using ADPCM and played too rarely, therefore additional CPU power required to decompress wouldn’t be a such pain.

Summary

Always remember to check your Audio Clip Import Settings. These are silent performance killers of your game. Set these right, and you will get additional CPU power for things that matters.

Also please take a look at the manual for technical information about import settings.

Wrong Import Settings are Killing Your Unity Game [Part 1]

There are many things that may go wrong with your game development. Your models may have too much triangles than your target platform can handle, your algorithms may be too expensive for your CPU, and also you may be using too many materials so batching won’t work efficiently. These are difficult issues, and you as a game developer should always remember to keep a good balance between visuals and performance. Yet, there are some things so simple that we often forget about their existence, but these can have a serious impact on your game performance.

Texture Import Settings

When you’re adding a texture into your project, the Unity works magic with it – the texture is converted to a suitable format based on current texture import settings. For most cases default settings will be good enough, but the Unity cannot tell if something looks good enough for the player so it cannot change it without your knowledge. It’s where you step in.

To access Texture Import Settings just select one or more textures that you want to change. Your inspector will look more or less like this:

texture import settings basicThere are 3 main things that you should keep an eye out.

Texture Type

texture type

Texture Type is a way to tell Unity what this texture will be used for. All this options besides Advanced will adjust your texture internal settings to be optimal as possible for the selected purpose. Note that texture of type Texture is a simple diffuse texture used in 3D space and for 3D game should be used the most. Types descriptions can be found in the official manual.

The risk: Setting the wrong texture type may be not noticeable at first and you will get a performance loss. Some types are required for shaders to work correctly (like Normal map type must be set for a texture that will be used for bump mapping).

Size

texture size and compression

This is where you can decide how big your texture should be and how it should be stored in the device memory. Noticed that there’s a Max Size instead of Size? This is simply because you can reduce all the textures resolution for your game in Quality Settings.

quality settings texture quality

Also setting the 2048 as Max Size won’t guarantee that this texture will be of that size even if Quality Settings are set to the highest. The texture resolution will be lower if your original texture file is not big enough. Knowing that, it is a good practice to prepare textures bigger than you need them to be, because you can always scale them down.

The Risk: Some models may be small on screen and those models’ textures can have large resolutions. You can identify these objects by setting your Scene shading to Mipmaps:

scene shading

Format

The texture Format is another thing that may be something confusing.

texture format

When your Texture Type is set to anything else than Advanced you will have 4 options.

  • Compressed – It trades a little of GPU power for a much lower texture size. Compressed option will use the most suitable compressing algorithm for your target platforms.
  • 16 bits – Saves the texture without a compression but it is using 16 bit color palette. Good for textures with small amount of colors.
  • Truecolor – Saves the texture using uncompressed 32 bit color palette. Looks great, but large 2048×2048 texture will require almost 17 megs of memory.
  • Crunched – Compressed using compression format suitable for the GPU and then compressed again using compression format that can be handled only by the CPU.  Good for downloadable asset bundles.

As you can see, you’re trading here texture size for texture quality. My advice is to always set the format as Compressed until you will see that something is not right with the textures in your game.

There’s one more Texture Type option that we haven’t described. If you set your Texture Type to advanced, you will gain access to many more texture formats including more compression methods. Be aware of that not all compression formats may be supported by your target platform (e.g. many Android devices have different texture compression formats support, but all should support ETC).

The Risk: Compressed textures may look ugly for some kind of textures, but textures set to 16 bits or Truecolor may take up too much space. You can find textures that are taking up to much space looking at editor.log after building your game.

You can learn more about texture compression formats here.

Verifying

texture import information

The last thing you want to do is to verify your texture import information. Here at the bottom of your texture preview you will learn about:

  • Used texture size
  • Used compression format
  • Result texture size

Keep in mind that sometimes you will need to build your game before you will see it’s target size.

Continued in Part 2 here

Side note: You may be wondering why textures sizes are power-of-two numbers. If you’re curious why, please read this discussion.

You can switch your Inspector into the debug mode

Unity Inspector is extremely useful tool when it comes to tuning up your game objects and components. By default, the inspector is displaying only public and serializable fields, but sometimes you may need to know more about your objects state.

You may want to include Debug.Log() function calls in your code. Usually, this is the fastest way of debugging things. Yet there may be a quicker way!

Consider following script:

This script does nothing more than adding the Time.deltaTime value to a private time field. It’s done under one condition – when the count field is set to true (by default, it is).

When this script is added as a Component to any game object, its inspector looks like this:

counter inspector

Nothing surprising here. We can see the Script property which is a common field for all components that are scripts, and the Count property that is bound to the count field because we have set that as a public field.

Now, if we would like to debug this component, we can use Debug.Log() function as previously mentioned, but it will result in significant amount of log entries in the Console. The better way to do this might be switching the Inspector into the debug mode. Here’s how to do it:

inspector debug mode switch

As you can see, the debug mode has changed the Inspector look dramatically. If any component had custom rendering code, debug mode would disable it.

An interesting fact is that the debug mode is revealing scripts’ private fields as it did with the time field from our script:

counter time field revealed

For security reasons it is not editable, but still it displays the current value set to the time field. Let’s verify that:

debug counter start stop

When you’re finished, you can switch your Inspector back to normal mode by clicking again in the top-right corner and selecting the Normal option:

inspector debug to normal mode

Use decorator drawers to improve inspector view of your scripts

If you’re writing a custom script then most probably you want to manipulate its public field values from the Inspector. By default, the Inspector fields are placed next to each other and the field name is the only information that you receive. You can write a custom editor, but this requires creating another script with a lot of code and this takes time. If you want to keep it simple then there’s a way! Just use the Decorator Drawers!

Decorator Drawers are attributes that can be set on any public field in your script to change the way it is displayed in the Inspector view (in fact, it renders some additions before the field is rendered). There are two built-in decorator drawers:

SpaceAttribute

The SpaceAttribute can be used to add some spacing in the Inspector view. In this way you can separate two or more groups of properties so they are more readable.

Let’s take a look at this example:

This script manifests itself like this in the Inspector view:

decorator drawer without space

To improve the readability we can split these properties to two groups: the health and the shield group. In order to do that, just add [Space(10)] before the shield field.

The number 10 here means that we want the space to be 10 pixels tall. Here’s how it went:

decorator drawer space example

 

Please note that adding a [Space(10)] there doesn’t mean “put space between maxHealth and shield fields” but instead “draw a space before shield property”. Usually it won’t make a difference, but it’s good to know if you encounter any issues.

HeaderAttribute

The header attribute adds a header label before the field that this attribute is assigned to. Here’s the example code:

And here’s how it looks like:

decorator drawers header example

 

As you can see it’s just similar to SpaceAttribute but there’s also a header label visible. And it has been done with a single attribute without writing a custom editor script!

Using Space and Header at the same time

You can use both properties at the same time. All you need to know is that these will be rendered in the reversed order. So if you write:

The space will be rendered at first, then the header. Don’t worry if you forget about that. You will notice your mistake once you look at the Inspector.

Writing custom Decorator Drawers

You’re probably thinking whether you could write your own Decorator Drawers. Yes, you can! Yet we will look into this topic in another article. Thank you for reading!