はじめに
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));
}
さいごに
短いですが、以上です。
共通な静的クラスなどに実装しておくと、困ったときに役立つかもしれません。
最後までお読みいただきありがとうございます!
コメント