Platform-Specific Code With Preprocessor Directives In Unity
Not every platform is made the same. There are things that some platforms can and can’t do. And oftentimes, if your game is going to be on multiple platforms, you’ll need to handle parts of the code differently. This is where preprocessor directives come in.
Preprocessor directives are pieces of code that get pre-processed in the compiler before the actual code gets compiled. They are useful for letting the compiler know what gets compiled and executed in a platform. Unity provides pre-defined directives for all of its available build platforms.
It is important to learn how to do this so your game doesn’t become bloated with unnecessary lines of code that are meant for only some platforms.
Table of Contents
- How to Use Preprocessor Directives in Unity
- How to Test Directives in Unity Editor
- How to Add Custom #define Directives
- Conclusion
How to Use Preprocessor Directives in Unity
In Unity, preprocessor directives are used to make the compiler conditionally compile code in your game, meaning you can give your game different functionality across different platforms.
Preprocessor code starts with a # (sharp) symbol at the beginning of a line followed by an instruction. This tells the compiler that this line is a preprocessor directive.
The syntax looks something like this:
#if A_DEFINE_DIRECTIVE
// Do something here
#elif ANOTHER_DEFINE_DIRECTIVE
// Do another thing here
#else
// This gets compiled when none of the conditions are satisfied
#endif
Code language: C# (cs)
The #elif you see in the example is equivalent to the “else if ()” in the C# language.
The if-else preprocessor directive behaves pretty much the same as the regular if-else in most programming languages. Meaning you can make use of the operators just like the regular one, too.
#if (UNITY_IOS || UNITY_ANDROID)
// Do something when the game is running on iOS or Android
#elif !UNITY_STANDALONE_WIN
// Do something when the game is NOT running
// on a standalone player in Windows operating system
#else
// Do something when none of the conditions are satisfied
#endif
Code language: C# (cs)
Let’s take a look at an example:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
private void QuitGame()
{
Application.Quit();
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#endif
}
}
Code language: C# (cs)
In the example above, we have a script that contains a method for quitting the game. When the QuitGame method is called, one of 2 things will happen depending on where the game is running on.
Here, let’s break it down a bit as to what will happen when the QuitGame method is called.
Code language: C# (cs)Application.Quit();
The Application.Quit method tells the game to quit. Simple. But here is the catch: This method is ignored if your game is running in the Play Mode inside Unity Editor.
This is where the next few lines come into play when you want to exit the Play Mode programmatically.
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#endif
Code language: C# (cs)
This tells the game to exit the Play Mode if it is running inside Unity Editor.
You might ask: “Why do we have to use the preprocessor directives for this? Can’t we just put the code for exiting the Play Mode right next to the quit method? One of them is going to get ignored anyway.”
The reason we have to do this is that the UnityEditor class will not be included when you build the game, and it will raise an error when you try to do it.
Another good example of using preprocessor directives in Unity would be, for example, when you want a button to do one thing when the game runs on a platform with a mouse and keyboard, and another thing when it runs on a platform with a touchscreen and no mouse and keyboard.
You could potentially have a method open a different user interface based on what platform your game is running on.
For the complete list of all available built-in directives in Unity, take a look at the #define directives manual page in the official Unity Documentation site.
How to Test Directives in Unity Editor
It is possible to test and see if your platform-dependent code is working without building the game. This can simply be done by switching the build platform to the one you want to test.
Go to File > Build Settings… This will open the Build Settings window.
Select the platform you want to test and click the Switch Platform button. Wait for it to import necessary files and re-compile the scripts.
Now, whenever you start the Play Mode in Unity Editor, your game will be treated as if it is running on the selected platform.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScreenshotManager : MonoBehaviour
{
private void Start()
{
#if UNITY_STANDALONE
Debug.Log("Standalone player");
#elif UNITY_WEBGL
Debug.Log("WebGL");
#endif
}
}
Code language: C# (cs)
The example above will log “WebGL” to the Unity Editor console.
You can take advantage of this and test your game on any platform from within Unity Editor right away.
Do note that this can only test some functionality of your game, and you will still have to build the game and test it on the actual platform for a more accurate result.
How to Add Custom #define Directives
In Unity, it is possible to define custom directives for each of your target platforms. This can be done by adding them to the Scripting Define Symbols section of your project’s settings.
Navigate to Edit > Project Settings… > Player.
In the Player section of the Project Settings window, you should be able to see all of the available platforms.
If you don’t see the platforms you want, install the build modules via Unity Hub first and restart Unity Editor.
Look under the Other Settings section of each platform, you should be able to see the Scripting Define Symbols list under the Script Compilation section. This is where we will add our custom directives.
Add them by clicking on the plus sign and name them whatever you want.
Once you’re done, click Apply to confirm and let the editor work out some stuff.
Now you can use these #define directives inside your script like any other pre-defined ones by Unity.
private void Start()
{
#if MY_MAIN_PLATFORMS
Debug.Log("This is for my main platforms I'm going to build.");
#elif
Debug.Log("Not my main platforms.");
#endif
}
Code language: C# (cs)
This will log “This is for my main platforms I’m going to build.” to the console for any platform with MY_MAIN_PLATFORMS defined.
This is useful when you want a group of platforms to perform parts of the functionality in the same way.
You can also use the OR operator to achieve this, too:
#if (UNITY_STANDALONE || UNITY_WEBGL)
// Do something
#endif
Code language: PHP (php)
But it is recommended to use custom #define directives instead because it is cleaner and you won’t have to go through all of your script files if you ever want to add or remove platforms.
Conclusion
So, that’s it! Preprocessor directives are very useful if you want to build your game for multiple platforms and have it do different things depending on the platform it is currently running on. Knowing when to use the preprocessor directives will save you a lot of time.
I hope you learned something today. Have a great day and I’ll see you in other articles!
Cheers!
Attribution
Pie Chart Icon made by noomtah from www.flaticon.com