Unityのプリプロセッサディレクティブ応用ガイド – 実践的なユースケース解説

はじめに

プリプロセッサディレクティブは、マルチプラットフォーム開発において非常に強力なツールです。この記事では、実際の開発現場で役立つ具体的な実装例と応用パターンを紹介します。

1. プラットフォーム別の広告実装

public class AdManager : MonoBehaviour
{
    private void InitializeAds()
    {
        #if UNITY_ANDROID
            // Google AdMob初期化
            string appId = "ca-app-pub-XXXXXXXXXXXXXXXX";
            MobileAds.Initialize(appId);
        #elif UNITY_IOS
            // iOS広告フレームワーク初期化
            ATTrackingManager.RequestTrackingAuthorization((status) =>
            {
                string appId = "ca-app-pub-YYYYYYYYYYYYYYYY";
                MobileAds.Initialize(appId);
            });
        #endif
    }
}

2. デバッグ機能の制御

[code language="csharp"]
public class DebugManager : MonoBehaviour
{
    public void LogDebugInfo(string message)
    {
        #if DEVELOPMENT_BUILD || UNITY_EDITOR
            Debug.Log($"[DEBUG] {message}");
            
            // デバッグUIの表示
            debugPanel.SetActive(true);
            
            // フレームレート制限解除
            Application.targetFrameRate = -1;
        #endif
    }

    public void ShowDevTools()
    {
        #if UNITY_EDITOR
            // エディタ専用のデバッグツール表示
            EditorWindow.GetWindow<DebugToolWindow>();
        #elif DEVELOPMENT_BUILD
            // ビルド版デバッグUIの表示
            RuntimeDebugPanel.Show();
        #endif
    }
}
[/code]

3. プラットフォーム固有の機能実装

[code language="csharp"]
public class PlatformFeatures : MonoBehaviour
{
    public void ShareContent(string message, string url)
    {
        #if UNITY_ANDROID
            // Android Share API
            using (AndroidJavaClass intentClass = new AndroidJavaClass("android.content.Intent"))
            using (AndroidJavaObject intentObject = new AndroidJavaObject("android.content.Intent"))
            {
                intentObject.Call<AndroidJavaObject>("setAction", intentClass.GetStatic<string>("ACTION_SEND"));
                intentObject.Call<AndroidJavaObject>("setType", "text/plain");
                intentObject.Call<AndroidJavaObject>("putExtra", intentClass.GetStatic<string>("EXTRA_TEXT"), message + " " + url);
                
                AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
                AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
                currentActivity.Call("startActivity", intentObject);
            }
        #elif UNITY_IOS
            // iOS Share Sheet
            NativeShare share = new NativeShare();
            share.SetText(message)
                 .SetUrl(url)
                 .Share();
        #endif
    }
}
[/code]

4. エディタ拡張との連携

[code language="csharp"]
public class BuildProcessor : MonoBehaviour
{
    #if UNITY_EDITOR
    [MenuItem("Build/Prepare Release")]
    public static void PrepareReleaseBuild()
    {
        // リリースビルド前の処理
        RemoveDebugSymbols();
        OptimizeAssets();
    }
    #endif

    private void ConfigureGame()
    {
        #if UNITY_EDITOR
            // エディタ実行時の設定
            EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
        #elif DEVELOPMENT_BUILD
            // 開発ビルドの設定
            EnableDebugConsole();
        #else
            // リリースビルドの設定
            DisableAllDebugFeatures();
        #endif
    }
}
[/code]

5. プラットフォーム別の最適化

[code language="csharp"]
public class PerformanceOptimizer : MonoBehaviour
{
    private void ConfigureQualitySettings()
    {
        #if UNITY_ANDROID
            // Androidデバイスの性能に応じた設定
            if (SystemInfo.processorCount <= 4)
            {
                QualitySettings.SetQualityLevel(0); // Low
                QualitySettings.shadowDistance = 15f;
                QualitySettings.particleRaycastBudget = 64;
            }
        #elif UNITY_IOS
            // iOS向けの最適化
            if (SystemInfo.deviceModel.Contains("iPhone"))
            {
                QualitySettings.antiAliasing = 0;
                QualitySettings.shadows = ShadowQuality.HardOnly;
            }
        #endif
    }
}
[/code]

プラクティスとTips

  1. 条件の組み合わせ
#if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR
    // モバイルプラットフォームのリリースビルドのみ
#endif
  1. カスタム定義シンボルの活用
#if ENABLE_FEATURE_A && !UNITY_EDITOR
    // カスタム機能の制御
#endif
  1. エディタ実行時の動作確認
[code language="csharp"]
private void TestInEditor()
{
    #if UNITY_EDITOR
    // エディタでのテスト用コード
    if (EditorApplication.isPlaying)
    {
        SimulateMobileEnvironment();
    }
    #endif
}
[/code]

注意点とベストプラクティス

  1. コードの可読性
  • プリプロセッサディレクティブのブロックは適切にインデントする
  • 条件分岐が複雑な場合はコメントで説明を追加

2. 保守性の確保

    • プラットフォーム固有のコードは別クラスに分離することを検討
    • 共通処理はできるだけディレクティブの外に配置

    3. デバッグのしやすさ

      • DEVELOPMENTビルドとリリースビルドで適切に機能を分離
      • エディタ上でのテストを容易にする

      まとめ

      プリプロセッサディレクティブを効果的に活用することで、プラットフォーム固有の機能を効率的に実装し、かつメンテナンス性の高いコードを作成することができます。実際の開発では、これらのパターンを組み合わせて使用することで、より柔軟で堅牢なアプリケーションを構築することが可能です。

      コメント

      タイトルとURLをコピーしました