【Unity】【C#】WindowsとUnityのパスを相互変換する

はじめに

Unityを触っているとファイルなどを開くときに「Assets/」から始まるパス(以下Assetパス)で指定していることに気づくと思います。

通常Windows環境ではドライブ名から始まる「C:/Projects/MyGame/Assets/Textures/image.png」のようなパス(以下Windowsパス)が使われるので、前述の「Assets/」から始まるパスはUnity環境特有のものです。

通常であればUnity内では諸々がAssetパスで完結するのですが、エディタ拡張などでユーザ入力を受け付けるようにしたりすると、ユーザがWindowsのパスを入力するということが起こり得ます。

また、DrectoryInfoなどを使用してパスを取得したりする場合も返ってくるのはWindowsパスでありこういったときにも必要になります。

上記のようなパターンにおいてWindowsパスとAssetパスを変換できるようなメソッドを用意してあると便利です。

実装

Unityでの使用を想定して、「\」や「\\」などで入力されることがある階層の区切りを「/」に正規化しています。
「/」ではない方が望ましい場合にはNormalizePathメソッドの置換先を「Path.DirectorySeparatorChar」などに変更してください。

        /// <summary>
        /// パスの区切り文字を正規化します。
        /// </summary>
        /// <remarks>
        /// - バックスラッシュ(\)をスラッシュ(/)に変換
        /// - 連続する区切り文字(// や \\\ など)を単一のスラッシュ(/)に変換
        /// </remarks>
        /// <param name="path">正規化するパス文字列</param>
        /// <returns>
        /// 正規化されたパス文字列。
        /// 入力がnullまたは空文字の場合は、入力値をそのまま返します。
        /// </returns>
        /// <example>
        /// 以下のパスはすべて同じ文字列に正規化されます:
        /// <code>
        /// "Assets\\Path"  -> "Assets/Path"
        /// "Assets/Path"   -> "Assets/Path"
        /// "Assets//Path" -> "Assets/Path"
        /// </code>
        /// </example>
        public static string NormalizePath(string path)
        {
            if (string.IsNullOrEmpty(path)) return path;

            // すべての区切り文字を'/'に変換
            path = path.Replace('\\', '/');

            // 連続する'/'を単一の'/'に置換(複数回の置換で///なども対応)
            while (path.Contains("//"))
            {
                path = path.Replace("//", "/");
            }

            return path;
        }

        /// <summary>
        /// Windowsのフルパスを Unity の Asset パスに変換します
        /// </summary>
        /// <param name="windowsPath">
        /// 変換元のパス
        /// - Windowsフルパス (例: "C:/Projects/MyGame/Assets/Textures/image.png")
        /// - アセットパス (例: "Assets/Textures/image.png")
        /// </param>
        /// <returns>Unityのアセットパス (例: "Assets/Textures/image.png")</returns>
        public static string WindowsPathToAssetPath(string windowsPath)
        {
            if (string.IsNullOrEmpty(windowsPath)) return null;

            // パスを正規化
            windowsPath = NormalizePath(windowsPath);

            // すでにAssetsから始まる場合は、正規化したパスをそのまま返す
            if (windowsPath.StartsWith("Assets/", System.StringComparison.OrdinalIgnoreCase))
            {
                return windowsPath;
            }

            // Application.dataPath は "プロジェクトパス/Assets" を返す
            string projectPath = NormalizePath(Application.dataPath);
            // "Assets" フォルダまでのパスを取得
            string assetsBasePath = projectPath.Substring(0, projectPath.Length - "Assets".Length);

            // フルパスから相対パスに変換
            if (windowsPath.StartsWith(assetsBasePath, System.StringComparison.OrdinalIgnoreCase))
            {
                return windowsPath.Substring(assetsBasePath.Length);
            }

            Debug.LogError("Invalid path: The specified path is not within the Unity project.");
            return null;
        }

        /// <summary>
        /// Unity の Asset パスを Windows のフルパスに変換します
        /// </summary>
        /// <param name="assetPath">
        /// 変換元のパス
        /// - アセットパス (例: "Assets/Textures/image.png")
        /// - Windowsフルパス (例: "C:/Projects/MyGame/Assets/Textures/image.png")
        /// </param>
        /// <returns>Windowsのフルパス (例: "C:/Projects/MyGame/Assets/Textures/image.png")</returns>
        public static string AssetPathToWindowsPath(string assetPath)
        {
            if (string.IsNullOrEmpty(assetPath)) return null;

            // 入力パスを正規化
            assetPath = NormalizePath(assetPath);

            // すでにフルパスの場合は、正規化したパスをそのまま返す
            string projectPath = NormalizePath(Application.dataPath);
            string projectRoot = projectPath.Substring(0, projectPath.Length - "Assets".Length);
            if (assetPath.StartsWith(projectRoot, System.StringComparison.OrdinalIgnoreCase))
            {
                return assetPath;
            }

            // アセットパスが "Assets/" で始まっていない場合はエラー
            if (!assetPath.StartsWith("Assets/", System.StringComparison.OrdinalIgnoreCase))
            {
                Debug.LogError("Invalid asset path: The path must start with 'Assets/'");
                return null;
            }

            // プロジェクトルートパスとアセットパスを結合して正規化
            return NormalizePath(Path.Combine(projectRoot, assetPath));
        }

さいごに

短いですが、以上です。

共通な静的クラスなどに実装しておくと、困ったときに役立つかもしれません。

最後までお読みいただきありがとうございます!

コメント

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