前回に引き続き、自動生成ネタです。
UnityのLayerをEnumにしてくれるEditor拡張を作った
今回は、SceneをEnumにして扱えたら楽なんじゃないか?と思って作ってみた次第です。
単純にEnumにするのではく、stringの配列も加えています。
SceneInfoCreator.cs
using UnityEngine;
using UnityEditor;
using System.Linq;
using UnityEditorInternal;
using System.Collections.Generic;
using System;
using System.IO;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
[InitializeOnLoad]
public class SceneInfoCreator
{
private const string SCENE_ENUM_HASH_KEY = "Scene_Info_Hash";
[MenuItem("Assets/SceneInfoCreator")]
public static void _sceneNameCreator()
{
if (EditorApplication.isPlaying || Application.isPlaying)
return;
EditorApplication.delayCall += BuildSceneName;
}
static SceneInfoCreator()
{
if (EditorApplication.isPlaying || Application.isPlaying)
return;
EditorApplication.delayCall += BuildSceneName;
}
static void BuildSceneName()
{
System.Text.StringBuilder builder = new System.Text.StringBuilder();
builder = WriteManagerClass(builder);
string text = builder.ToString().Replace(",}", "}");
string assetPath = Application.dataPath + "/Scripts/Utility/SceneInfo.cs";
if (AssetDatabase.LoadAssetAtPath(assetPath.Replace("/Editor/..", ""), typeof(UnityEngine.Object)) != null && EditorPrefs.GetInt(SCENE_ENUM_HASH_KEY, 0) == text.GetHashCode())
return;
System.IO.File.WriteAllText(assetPath, text);
EditorPrefs.SetInt(SCENE_ENUM_HASH_KEY, text.GetHashCode());
AssetDatabase.Refresh(ImportAssetOptions.ImportRecursive);
EditorApplication.delayCall -= BuildSceneName;
}
static System.Text.StringBuilder WriteManagerClass(System.Text.StringBuilder builder)
{
var sceneNames = new List<string>();
EditorBuildSettings.scenes
.Where(_ => _.enabled)
.Select(_ => Path.GetFileNameWithoutExtension(Path.Combine(Directory.GetCurrentDirectory(), _.path)))
.Where(_ => !string.IsNullOrEmpty(_))
.ForEach(_ => sceneNames.Add(_));
builder.AppendLine("/// <summary>");
builder.AppendFormat("/// Access Scene Class").AppendLine();
builder.AppendLine("/// </summary>");
///
builder.Append("public sealed class SceneInfo {").AppendLine();
WriteSceneEnum(builder, sceneNames);
WriteSceneNameArray(builder, sceneNames);
builder.AppendLine("}");
return builder;
}
static void WriteSceneEnum(System.Text.StringBuilder builder, List<string> sceneNames)
{
builder.Append("\t").AppendLine("/// <summary>");
builder.Append("\t").AppendFormat("/// Access Scene Number Enum").AppendLine();
builder.Append("\t").AppendLine("/// </summary>");
builder.Append("\t").Append("public enum SceneEnum {").AppendLine();
sceneNames.ForEach((sceneName, i) =>
{
var comma = (i == sceneNames.Count() - 1) ? "" : ",";
builder.Append("\t").Append("\t").AppendFormat("{0} = {1}", sceneName.SymbolReplace(), i + comma).AppendLine();
});
builder.Append("\t").AppendLine("};");
}
static void WriteSceneNameArray(System.Text.StringBuilder builder, List<string> sceneNames)
{
builder.Append("\t").AppendLine("/// <summary>");
builder.Append("\t").AppendFormat("/// Access Scene Name Array").AppendLine();
builder.Append("\t").AppendLine("/// </summary>");
builder.Append("\t").Append("public static readonly string[] SceneNames = new string[]{");
sceneNames.ForEach((sceneName, i) =>
{
var comma = (i == sceneNames.Count() - 1) ? "" : ",";
builder.AppendFormat(@"""{0}""" + comma, sceneName);
});
builder.AppendLine("}; ");
}
}
上記の処理を実行した時にBuildSettingsで仮にInit.sceneとTest.sceneを登録した場合、以下のようなスクリプトが生成されます。
SceneInfo.cs
/// <summary>
/// Access Scene Class
/// </summary>
public sealed class SceneInfo {
/// <summary>
/// Access Scene Number Enum
/// </summary>
public enum SceneEnum {
Init = 0,
Test = 1
};
/// <summary>
/// Access Scene Name Array
/// </summary>
public static readonly string[] SceneNames = new string[]{"Init","Test"};
}
これの自動生成があるだけでもかなりミスが減らせる気がします。InspectorでもEnum表示してScene選ぶとかできますし、何かと楽になりそうです。
ファイルの保存場所は適宜変えてください。
コピペでうまく動かない人は、前回の記事に書いてある拡張メソッドを追加してみてください。
自作フレームワークに組み込んで改修を続けているのでご興味あれば
https://github.com/MizoTake/MomijiFramework