topaz-dev’s

ああああああ

Unityでディレクトリ操作する

Pathの取得

C#の System.IO を用いてUnityのプロジェクトないのファイルにアクセスするために絶対パスを用いる必要がある。以下で取得できる。

string assetsPath = Application.dataPath;
// assetsPath : /Users/ **hoge** / ~プロジェクトまでのパス~ /Assets

// 実際にアクセスする際には以下のようにする
string targetPath = assetsPath + "/Scripts/Game/Player/Player.cs";

AssetDataBaseの更新

ファイル操作を行なった情報を更新するためにAssetDataBaseを更新する必要がある。ファイルを作成したり削除した際には更新処理を呼び出す必要がある。

// ~ファイルやディレクトリの生成、削除処理~
AssetDatabase.Refresh();
ディレクトリ操作
string path = "絶対パス";
// ディレクトリが存在するかどうか
bool isExist = Directory.Exsists(path);
// ディレクトリを作成する
DirectoryInfo info = Directory.CreateDirectory(path);

AssetDatabase.Refresh();

ディレクトリを作成する場合親ディレクトリが存在しなかったら階層的にディレクトリを作成していく。既に存在している場合には何も起こらない。
ディレクトリを削除する際にはmetaファイルも消さなくてはならない。Assets/Scripts/Testというディレクトリを削除する際にディレクトリだけを削除するとmetaファイルが残ってしまいAssetsDatabase.Refresh()が起こった際に再度生成されてしまうことがある。metaファイルも同時に削除する。また削除する際に指定したディレクトリが存在しない時にDirectoryNotFoundExceptionのエラーが出てしまうためディレクトリの存在確認をする必要がある。そのままではディレクトリが空でない時にエラーが生じる。ディレクトリが空でない時は第二引数にtrueを入れることで再起的に削除することができる。

string path = "絶対パス";
if(Directory.Exists(path)){

    // ディレクトリ自体の削除(ディレクトリが空の時)
    Directory.Delete(path);
    // ディレクトリを再起的に削除(子ディレクトリも削除)
    // Directory.Delete(path, true);

    // ディレクトリ情報を持つmetaファイルの削除
    File.Delete(path + ".meta");

    AssetDatabase.Refresh();
} else {
    Debug.LogWarning($"{path} は存在しませんでした"):
}
ディレクトリ以下のファイルを取得する

ディレクトリ以下のファイルを全て取得する。ディレクトリの名前はfilesには入らないがmetaファイルは入る。

string path = "絶対パス";
if(Directory.Exists(path)){

    string[] files = Directory.GetFiles(targetPath);
    // 再起的にディレクトリ以下のファイル全てを取得したい場合
    // string[] files = Directory.GetFiles(targetPath, "*", SearchOption.AllDirectories);

    Debug.LogWarning(files.Length);
    for (int i = 0; i < files.Length; i++)
    {
         // files[i]は絶対パスで返される。metaファイルも含まれる。ディレクトリは含まれない。
        Debug.Log(files[i]);
    }

} else {
    Debug.LogWarning($"{path} は存在しませんでした"):
}

まとめ

Application.datapathを使用して絶対パスを取得してからはAssets以下のディレクトリ操作を行うことができる。metaファイルを削除してAssetsDatabaseを更新しないと予期せぬエラーが生じることがあるので注意する必要がある。ディレクトリが存在しない時のエラー対応も必要である。

UnityEditorInternal.InternalEditorUtility

InternalEditorUtilityではリファレンスに載っていない。以下の二箇所にクラスが書かれている。しかし内部の実装までは見れない部分もある。

  1. UnityCsReference/InternalEditorUtility.cs at master · Unity-Technologies/UnityCsReference · GitHub
  2. UnityCsReference/InternalEditorUtility.bindings.cs at 73c12b5a403abad9a300f01a81e7aaf30a0d30b5 · Unity-Technologies/UnityCsReference · GitHub
ログファイルを開く
// コード
InternalEditorUtility.OpenEditorConsole();

Editor.logファイルを開きます。MacOS環境下では、~/Library/Logs/Unity/Editor.logが開かれました。Debug.Logなどの出力が記載されています。エラーが出たけど消してしまった時に見返すことができそうです。

エディタでファイルを開く
// コード
InternalEditorUtility.OpenFileAtLineExternal( filePath, line );

// 使用例 : Assets/Scripts/Hoge.csの29行目を開く
string path = Application.dataPath + "/Scripts/Hoge.cs";
InternalEditorUtility.OpenFileAtLineExternal( path , 29 );

Consoleで表示されているパスをクリックするとエディタを開くのはこれが利用されていると思います。

パスを取得する

さまざまなパスを取得することができます。実際に利用することは少ないと思います。

InternalEditorUtility.GetAssetsFolder();
/* 出力
Assets
*/
InternalEditorUtility.GetEditorFolder();
/* 出力
Editor
*/
InternalEditorUtility.GetEngineAssemblyPath();
/* 出力
 /Applications/Unity/Hub/Editor/2021.3.6f1/Unity.app/Contents/Managed/
UnityEngine/UnityEngine.dll
*/
InternalEditorUtility.GetEngineCoreModuleAssemblyPath();
/* 出力
/Applications/Unity/Hub/Editor/2021.3.6f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CoreModule.dll
*/
InternalEditorUtility.GetFullUnityVersion();
/* 出力
2021.3.6f1 (7da38d85baf6)
*/
// 他のPath
Application.dataPath
/* 出力
/Users/ **hogehoge** / ~プロジェクトの位置までのパス~ / Assets
Assetsまでの絶対パスを取得できる。
Applecation.dataPath + "/" + "Scripts/hoge/hoge.cs"; のように使用する。
*/

カスタムオブジェクトを使用する。

WIP 書き途中

Cloud Fire Storeではデータを扱いやすくするためにカスタムオブジェクトを作成して使用することができる。こちらの基本的には公式サイトが充実しているのでそちらを参照してくれればよい。

// クラスにつける属性
[FirestoreData]
public class City
{
        // プロパティにつける属性
        [FirestoreProperty]
        public string Name { get; set; }

        [FirestoreProperty]
        public string State { get; set; }

        [FirestoreProperty]
        public string Country { get; set; }

        [FirestoreProperty]
        public bool Capital { get; set; }

        [FirestoreProperty]
        public long Population { get; set; }
}

使用可能の型はこちらに記載されている。基本的な型は大抵使えるが多次元配列を使えないのが注意が必要。一次元配列に落とすか、Maoなどを使う必要がある。 データを保存するためのカスタムオブジェクトクラスと、実際にアプリで使用するクラスは別にしてコンバーターを作るのが良さそうである。コンバータークラスを作るもいいし内部で処理を書いてもよい。

public class City
{
    public CityInGame Convert()
    {
        CityInGame cityInGame = new CityInGame();
        // 初期化する
        return cityInGame;
    }
}

拡張メソッドを定義する方法もある。どちらいいけど使いやすいように設計すると良さそう。ゲーム内と全く同じクラスを作るのはあまり好きではない。。。

public class CityExtension
{
    public static CityInGame ConvertToGame(this City self)
    {
        CityInGame cityInGame = new CityInGame();
        // 初期化する
        return cityInGame;
    }
}

データの追加は比較的単純に行える。

// インスタンスの取得
FirebaseFirestore db = FirebaseFirestore.DefaultInstance;
// ドキュメントへの参照を取得
DocumentReference docRef = db.Collection("cities").Document("LA");
City city = new City
{
        Name = "Los Angeles",
        State = "CA",
        Country = "USA",
        Capital = false,
        Population = 3900000L
};
docRef.SetAsync(city);

まとえm

WIP

スクリプトからスクリプタブルオブジェクトを生成する。

キーワード

スクリプタブルオブジェクト(ScriptableObject)、スクリプト(Script)

概要

スクリプタブルオブジェクトをエディタ拡張など、スクリプトから生成したときのメモ

スクリプトからスクリプタブルオブジェクトを生成する。

スクリプタブルオブジェクトは.assetの形式で保存されている。そのためこの形式で保存すればスクリプタブルオブジェクトを生成できる。
ScriptableObjectTestというScriptableObjectを継承したクラスがあるとする。

    private void CreateScriptableObject()
    {
        var obj = CreateInstance<ScriptableObjectTest>();

        AssetDatabase.CreateAsset(obj, "Assets/GameData/SOTest001.asset");
    }

CreateInstanceで型指定したインスタンスを生成してAssetDatabaseで.asset形式で保存するとスクリプタブルオブジェクトとして生成される。

まとめ

スクリプタブルオブジェクトはScriptableUtitlityなどではなく、AssetDatabaseを通して作成することができる。