「魔法少女戦記外伝」DL委託販売中!!

DMM 同人様 Melonbooks DL様 DLsite.com 様
DMM 同人様 Melonbooks DL 様 DLsite.com 様



最新記事ほか

【Unity】マルチシーンエディティングを使った簡易シーンローダー【小ネタ】

今回は久しぶりの Unity 小ネタシリーズでございます。
これで次回の進捗記事で「一ヶ月ぶり~」なんて言い回しを使わなくて済みそうですw

今回の小ネタなんですが、Unity5.3 以降で追加されました新機能「マルチシーンエディティング」を使った小ネタです。

この「マルチシーンエディティング」は、今までエディタ上で同時に表示できなかった複数のシーンをまとめて表示していっしょに編集しましょう!・・・というものなのですが、個人的に「使い方が面倒だな~」なんて思いまして「ちょっとしたローダーを作って楽な環境にしよう!」と思い立ったのでした。


というわけで、さっそくいってみましょう。




・・・で、その噂の「マルチシーンエディティング」なんですが、基本的な使い方としては下の画像のようにシーンファイルをドラッグ&ドロップして呼び出します。

20160408_00_DandD.gif

Unity に慣れた方には気にならない方法なのだと思いますが、個人的には「プロジェクトウインドウからわざわざシーンファイルを探し出す」という行為が面倒に感じました
「フォルダ分けしておけば~」というご指摘をうけそうですが、プロジェクトウインドウではシーンファイル以外にもマテリアルやら音声やら・・・とたくさんのファイルを扱うことがあるため、シーンを呼び出すためにわざわざシーンファイルを探すのは手間がかかるというかなんというか・・・という面倒さが目立ちまして・・・

今までは「プレハブ」という単位で部品を小分けして管理していたのですが、それすらも包み込む「シーン」という大きな単位で部品を管理できるのは非常に魅力的です。
個人的には以下のような感じでシーンを管理できると良いなぁ・・・なんて考えていました。

20160408_01_SceneMap.png

ですが先ほどのドラッグ&ドロップが面倒だなぁ・・・と思っていたところで思いついたのが、今回のお話のメインとなります簡易ローダーです。

というわけで、さっそく作成手順のご紹介。まずは先ほどの構想の「親シーン」に該当するシーンを作成します。

20160408_02_TopScene.png

適当にuGUIのキャンバスを作成し、空オブジェクト「Scene Loader」を用意。これを「TopScene」という名前でシーンを保存。

次に子シーンを作成。

20160408_03_SceneA.png 20160408_04_SceneB.png

uGUIのキャンバスを作成し、カメラを削除したシーンを2つ作成。それぞれ「SceneA」「SceneB」という名前でシーンを保存します。

20160408_05_SceneFile.png

作り終えると上の画像のようにシーンファイルが3つできていると思います。
次に最初に作成した「TopScene」を再び開いて空オブジェクト「Scene Loader」に以下のスクリプトを追加します。


using UnityEngine;
using UnityEngine.SceneManagement;
using System;
using System.Collections;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.SceneManagement;
#endif

///
/// シーンID(シーン名称と同じにする)
///

public enum SceneID
{
SceneA,
SceneB,
}
/**
* マルチシーン呼び出しクラス
*/
public class SceneLoader : MonoBehaviour
{
/// 初回に読み込むシーンID
[SerializeField]
SceneID loadScene;


//------------------------------------------------------------------------------------
// 指定シーンのロード
public void LoadScene()
{
// 指定シーン以外のシーンがあれば解放
foreach (SceneID sample in Enum.GetValues(typeof(SceneID)))
{
if(sample != loadScene)
CloseEditorScene(sample.ToString());
}
// 指定シーンのロード
OpenEditorScene(loadScene.ToString());
}
//------------------------------------------------------------------------------------
// 指定シーンの解放
public void RemoveScene()
{
CloseEditorScene(loadScene.ToString());
}

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
///
/// Editor上でのシーンの読み出し(シーンID版)
/// ※ SceneNameManager ありきの読み出し
///

/// シーン名称
void OpenEditorScene(string sceneName)
{
#if UNITY_EDITOR
// AssetDatabaseでシーンファイルを探索
foreach (var guid in AssetDatabase.FindAssets("t:Scene"))
{
string path = AssetDatabase.GUIDToAssetPath(guid);
//ファイル名を抜き出し同一名称のものをロードする
string fileName = System.IO.Path.GetFileName(path);
if (fileName.Contains(sceneName))
{
EditorSceneManager.OpenScene(path, OpenSceneMode.Additive);
break;
}
}
#endif
}
//------------------------------------------------------------------------------------
///
/// Editor上のシーンを解放
///

/// シーン名称
void CloseEditorScene(string sceneName)
{
#if UNITY_EDITOR
// 指定したシーンがロードされているかを確認
Scene scn = SceneManager.GetSceneByName(sceneName);
if (!string.IsNullOrEmpty(scn.name) && scn.isLoaded)
EditorSceneManager.CloseScene(scn, true);
#endif
}
}

#if UNITY_EDITOR
/**
* Inspector の表示を変更するエディタ拡張
*/
[CustomEditor(typeof(SceneLoader))]
public class SceneLoaderInspector : Editor
{
public override void OnInspectorGUI()
{
serializedObject.Update();

SceneLoader obj = target as SceneLoader;

EditorGUILayout.PropertyField(serializedObject.FindProperty("loadScene"), new GUIContent("Load Scene"));
// シーン呼び出し
if (GUILayout.Button("Open Scene"))
{
obj.LoadScene();
}
// シーン解放
if (GUILayout.Button("Close Scene"))
{
obj.RemoveScene();
}

serializedObject.ApplyModifiedProperties();
}
}
#endif


大雑把なスクリプトの解説になりますが、部分的に重要そうな箇所は以下のようになります。


///
/// シーンID(シーン名称と同じにする)
///

public enum SceneID
{
SceneA,
SceneB,
}


この列挙型で呼び出したいシーン名称を管理しています。

呼び出すシーンを増やしたい場合はこちらの記述に新しいシーン名称を追加していくことになります。この実装では「列挙型の名称=シーン名称」になっているため、C#の文法で禁止される名称(スペースを挟んだ名称など)はNGです。


public void LoadScene()
{
// 指定シーン以外のシーンがあれば解放
foreach (SceneID sample in Enum.GetValues(typeof(SceneID)))
{
if(sample != loadScene)
CloseEditorScene(sample.ToString());
}
// 指定シーンのロード
OpenEditorScene(loadScene.ToString());
}


指定されたシーンを呼び出す部分ですが構想で呼び出す子シーンは1つという前提で作成したため、指定シーン以外のシーンが存在していたら解放する処理を呼び出す前に行っています。
これまでのシーンを残しつつ新しい子シーンをたくさん作りたい場合は foreach~から始まる解放処理を削除することで実現できます。


void OpenEditorScene(string sceneName)
{
#if UNITY_EDITOR
// AssetDatabaseでシーンファイルを探索
foreach (var guid in AssetDatabase.FindAssets("t:Scene"))
{
string path = AssetDatabase.GUIDToAssetPath(guid);
//ファイル名を抜き出し同一名称のものをロードする
string fileName = System.IO.Path.GetFileName(path);
if (fileName.Contains(sceneName))
{
EditorSceneManager.OpenScene(path, OpenSceneMode.Additive);
break;
}
}
#endif
}


このメソッドで「AssetDatabase」を利用してプロジェクト内部のシーンファイルを検索して同名ファイルをロードする仕掛けがあるのですが、この辺りの不便さはUnity の扱いに精通した素晴らしい技術者の皆様が解決してくださるのではないかなぁ~なんて甘い期待を描いていますw
(例えばシーンの一覧を自動生成して外部ファイルにリストとして出力する~的な技術を応用するとか・・・)


#if UNITY_EDITOR
/**
* Inspector の表示を変更するエディタ拡張
*/
[CustomEditor(typeof(SceneLoader))]
public class SceneLoaderInspector : Editor
{


このクラスはエディタ拡張機能の一つで、Inspector 上にボタンを配置するための記述です。ボタンが押されると指定されたメソッドが呼び出される~という仕掛けです。

このスクリプトの追加が終了すると、Inspector が以下の画像のようになっていると思います。

20160408_06_Inspector.png

この Inspector で表示されているボタン「Open Scene」「Close Scene」を押すことで、「Load Scene」で指定されたシーンを呼び出したり削除することが可能となります。
ちなみにこのボタンですが、プロジェクトを実行していない編集中の状態での利用を想定しています。

20160408_07_Result.png

「Open Scene」が正常に動作すると上のような画面になっていると思います。
(uGUIの設定に問題があると見た目が違う可能性はありますが、シーンは2つロードされていると思います)


というわけで、駆け足気味に説明しましたがいかがでしたでしょうか?
個人的にはこの記事をご覧になられた素晴らしい Unity 技術者様がさらに便利に改良してくださるだろうことを期待していますw
(改良された際には利用させていただきたいのでご一報いただけますと幸いですw)

ではでは今回はこの辺で~ノシ
スポンサーサイト

コメントの投稿

非公開コメント

プロフィール

Empress

Author:Empress
同人サークル「Atelier Empress」を立ち上げてしまった愚か者です。少しずつでも作品を公開していければと思う次第でございます。

検索フォーム
リンク
カテゴリ
タグ一覧

同人 Unity 進捗 雑記 コミケ C89 小ネタ プログラミング Unity小ネタ 年末 新年 Android 

委託販売
スポンサード リンク
FLOWER KNIGHT GIRL オンラインゲーム 千年戦争アイギス オンラインゲーム
Twitter