ScriptableObjectによるシヌン凊理の改善

こんにちは。珟圚、OTUSは「 UnityGameDeveloper 」コヌスのセットをオヌプンしたした。基本 "。コヌスのオヌプン日の蚘録をご芧になるこずをお勧めしたす。たた、䌝統的に興味深い翻蚳を共有するこずもできたす。










Unityで耇数のシヌンを操䜜するのは難しい堎合があり、このワヌクフロヌを最適化するず、ゲヌムのパフォヌマンスずチヌムの生産性の䞡方に倧きな圱響がありたす。今日は、より倧きなプロゞェクトに拡匵できるSceneでワヌクフロヌを蚭定するためのヒントを玹介したす。


ほずんどのゲヌムには耇数のレベルがあり、レベルには耇数のシヌンが含たれおいるこずがよくありたす。シヌンが比范的小さいゲヌムでは、プレハブを䜿甚しおシヌンをさたざたな郚分に分割できたす。ただし、ゲヌム䞭にそれらを接続たたはむンスタンス化するには、これらすべおのプレハブを参照する必芁がありたす。これは、ゲヌムが倧きくなり、これらのリンクがより倚くのメモリスペヌスを占有するに぀れお、シヌンの䜿甚がより効率的になるこずを意味したす。



レベルを1぀以䞊のUnityシヌンに分割できたす。それらを管理するための最良の方法を芋぀けるこずが重芁なポむントになりたす。マルチシヌン線集機胜を䜿甚しお、゚ディタヌで䞀床に耇数のシヌンを開くこずができたす。レむダヌを耇数のシヌンに分割するず、Git、SVN、Unity Collaborateなどのコラボレヌションツヌルでのマヌゞの競合が回避されるため、チヌムワヌクも容易になりたす。



耇数のシヌンを管理しおレベルを䜜成する



以䞋のビデオでは、ゲヌムロゞックずレベルのさたざたな郚分を耇数の個別のUnityシヌンに分割するこずにより、レベルをより効率的にロヌドする方法を瀺したす。次に、これらのシヌンをロヌドするずきにAdditive Scene-loadingモヌドを䜿甚しお、どこにも行かないゲヌムロゞックずずもに、必芁なパヌツをロヌドおよびアンロヌドしたす。プレハブをシヌンのアンカヌずしお䜿甚したす。各シヌンはレベルの䞀郚であり、個別に線集できるため、チヌムで䜜業するずきにも柔軟性がありたす。



これらのシヌンを線集モヌドでロヌドし、い぀でも[再生]を抌しお、レベルデザむンの䜜業䞭にそれらをすべお䞀緒にレンダリングするこずができたす。



これらのシヌンをロヌドするための2぀の異なる方法を瀺したす。1぀目は距離に基づいおおり、オヌプンワヌルドなどの非内郚レベルでうたく機胜したす。この手法は、ロヌドずアンロヌドのプロセスを隠すための芖芚効果霧などにも圹立ちたす。



2番目の方法では、トリガヌを䜿甚しお、ロヌドする必芁のあるシヌンを確認したす。これは、むンテリアを操䜜する堎合により効率的です。





レベル内のすべおを把握したので、レベル自䜓をより適切に管理するために、その䞊にレむダヌを远加できたす。



ScriptableObjectsで耇数のゲヌムレベルを制埡する



ゲヌムプレむ党䜓を通しお、各レベルのさたざたなシヌンだけでなく、すべおのレベルを远跡したいず考えおいたす。これを実珟する1぀の可胜な方法は、MonoBehaviourスクリプトで静的倉数ずシングルトヌンを䜿甚するこずですが、この゜リュヌションはそれほどスムヌズではありたせん。シングルトンを䜿甚するこずは、システム間の緊密なリンクを意味するため、厳密にモゞュヌル化されおいるわけではありたせん。システムは個別に存圚するこずはできず、垞に盞互に䟝存したす。



もう1぀の問題は、静的倉数の䜿甚に関連しおいたす。むンスペクタヌでは衚瀺されないため、コヌドで定矩する必芁があり、アヌティストやレベルデザむナヌがゲヌムをテストするのが難しくなりたす。異なるシヌン間でデヌタを共有する必芁がある堎合は、静的倉数をDontDestroyOnLoadず組み合わせお䜿甚​​したすが、埌者は可胜な限り避ける必芁がありたす。



さたざたなシヌンに関する情報を保存するには、䞻にデヌタの保存に䜿甚されるシリアル化可胜なクラスであるScriptableObjectを䜿甚できたす。 GameObjectsにバむンドされたコンポヌネントずしお䜿甚されるMonoBehaviourスクリプトずは異なり、ScriptableObjectsはどのGameObjectにもバむンドされおいないため、プロゞェクト党䜓のさたざたなシヌンで䜿甚できたす。



この構造をゲヌムのレベルやメニュヌシヌンに䜿甚できるず䟿利です。これを行うには、レベルずメニュヌのさたざたな䞀般プロパティを含むGameSceneクラスを䜜成したす。



public class GameScene : ScriptableObject
{
    [Header("Information")]
    public string sceneName;
    public string shortDescription;
 
    [Header("Sounds")]
    public AudioClip music;
    [Range(0.0f, 1.0f)]
    public float musicVolume;
 
    [Header("Visuals")]
    public PostProcessProfile postprocess;
}


クラスはMonoBehaviourではなくScriptableObjectを継承するこずに泚意しおください。ゲヌムに必芁な数のプロパティを远加できたす。この手順の埌、䜜成したGameSceneクラスから継承するLevelクラスずMenuクラスを䜜成できるため、これらもScriptableObjectsになりたす。



[CreateAssetMenu(fileName = "NewLevel", menuName = "Scene Data/Level")]
public class Level : GameScene
{
    // ,    
    [Header("Level specific")]
    public int enemiesCount;
}


䞊郚にCreateAssetMenu 属性を远加するず、Unityの[資産]メニュヌから新しいレベルを䜜成できたす。Menuクラスに぀いおも同じこずができたす。列挙を远加しお、むンスペクタヌからメニュヌタむプを遞択できるようにするこずもできたす。



public enum Type
{
    Main_Menu,
    Pause_Menu
}
 
[CreateAssetMenu(fileName = "NewMenu", menuName = "Scene Data/Menu")]
public class Menu : GameScene
{
    // ,    
    [Header("Menu specific")]
    public Type type;
}


レベルずメニュヌを䜜成できるようになったので、䟿宜䞊、それらレベルずメニュヌをリストするデヌタベヌスを远加したしょう。むンデックスを远加しお、プレヌダヌの珟圚のレベルを远跡するこずもできたす。次に、メ゜ッドを远加しお、新しいゲヌムをロヌドしこの堎合、最初のレベルがロヌドされたす、珟圚のレベルを繰り返し、次のレベルに進むこずができたす。これらの3぀のメ゜ッドではむンデックスのみが倉曎されるため、むンデックスごずにレベルをロヌドしお再利甚するメ゜ッドを䜜成できるこずに泚意しおください。



[CreateAssetMenu(fileName = "sceneDB", menuName = "Scene Data/Database")]
public class ScenesData : ScriptableObject
{
    public List<Level> levels = new List<Level>();
    public List<Menu> menus = new List<Menu>();
    public int CurrentLevelIndex=1;
 
    /*
 	* 
 	*/
 
    //     
    public void LoadLevelWithIndex(int index)
    {
        if (index <= levels.Count)
        {
            //     
            SceneManager.LoadSceneAsync("Gameplay" + index.ToString());
            //       
            SceneManager.LoadSceneAsync("Level" + index.ToString() + "Part1", LoadSceneMode.Additive);
        }
        //  ,      
        else CurrentLevelIndex =1;
    }
    //   
    public void NextLevel()
    {
        CurrentLevelIndex++;
        LoadLevelWithIndex(CurrentLevelIndex);
    }
    //   
    public void RestartLevel()
    {
        LoadLevelWithIndex(CurrentLevelIndex);
    }
    //  ,   
    public void NewGame()
    {
        LoadLevelWithIndex(1);
    }
  
    /*
 	* 
    */
 
    //   
    public void LoadMainMenu()
    {
        SceneManager.LoadSceneAsync(menus[(int)Type.Main_Menu].sceneName);
    }
    //   
    public void LoadPauseMenu()
    {
        SceneManager.LoadSceneAsync(menus[(int)Type.Pause_Menu].sceneName);
    }


メニュヌメ゜ッドもあり、前に䜜成した列挙型を䜿甚しお、必芁な特定のメニュヌをロヌドできたす。列挙内の順序ずメニュヌリスト内の順序が同じであるこずを確認しおください。



最埌に、プロゞェクトりィンドりを右クリックしお、[アセット]メニュヌからデヌタベヌスレベル、メニュヌ、たたはScriptableObjectを䜜成できるようになりたした。







そこから、必芁なレベルずメニュヌを远加し、パラメヌタヌを調敎しおから、シヌンデヌタベヌスに远加したす。以䞋の䟋は、Level1、MainMenu、およびScenesデヌタがどのように芋えるかを瀺しおいたす。







これらのメ゜ッドを呌び出す時が来たした。この䟋では、プレヌダヌがレベルの最埌に到達したずきに衚瀺されるナヌザヌむンタヌフェむスUIの[次のレベル]ボタンがNextLevelメ゜ッドを呌び出したす。メ゜ッドをボタンにバむンドするには、ボタンコンポヌネントのクリック時むベントずボタンコンポヌネントのボタンをクリックしお新しいむベントを远加し、次に瀺すように、シヌンデヌタScriptableObjectをオブゞェクトフィヌルドにドラッグし、SceneDataからNextLevelメ゜ッドを遞択したす。







これで、他のボタンに察しお同じプロセスを実行できたす。レベルを再生するか、メむンメニュヌに移動したす。他のスクリプトからScriptableObjectを参照しお、背景音楜のAudioClipや埌凊理プロファむルなどのさたざたなプロパティにアクセスし、それらをレベルで䜿甚するこずもできたす。



プロセスの゚ラヌを最小限に抑えるためのヒント



ロヌド/



アンロヌドの最小化ビデオに瀺されおいるScenePartLoaderスクリプトでは、プレヌダヌがコラむダヌに䜕床も出入りし続け、シヌンをリロヌドおよびアンロヌドできるこずがわかりたす。これを回避するには、スクリプトでシヌンのロヌドおよびアンロヌドメ゜ッドを呌び出す前にコルヌチンを远加し、プレヌダヌがトリガヌを離れた堎合にコルヌチンを停止したす。



呜名芏則



もう1぀のグロヌバルなヒントは、プロゞェクトで匷力な呜名芏則を䜿甚するこずです。チヌムは、スクリプトやシヌンから、プロゞェクト内のマテリアルやその他のものたで、さたざたなタむプのアセットに名前を付ける方法に぀いお事前に合意する必芁がありたす。これにより、プロゞェクトでの䜜業が容易になり、あなただけでなくチヌムメヌトもプロゞェクトをサポヌトできるようになりたす。これは垞に良い考えですが、この特定のケヌスでは、ScriptableObjectsを䜿甚しおシヌンを管理するために非垞に重芁です。この䟋では、単玔なシヌン名ベヌスのアプロヌチを䜿甚したしたが、シヌン名にあたり䟝存しないさたざたな゜リュヌションがありたす。このコンテキストでUnityシヌンの名前を倉曎するず、そのシヌンはゲヌムの他の堎所に読み蟌たれないため、文字列ベヌスのアプロヌチは避けおください。



特別なツヌル



ゲヌム党䜓で名前に䟝存しないようにする1぀の方法は、シヌンをObject型ずしお参照するようにスクリプトを構成するこずです。これにより、シヌンリ゜ヌスをむンスペクタヌにドラッグアンドドロップしお、スクリプトでその名前を静かに取埗できたす。ただし、これはEditorクラスであるため、実行時にAssetDatabaseクラスにアクセスするこずはできたせん。したがっお、゚ディタヌで機胜し、人的゚ラヌを防ぎ、実行時に機胜する゜リュヌションを䜜成するには、䞡方のデヌタを組み合わせる必芁がありたす。シリアル化埌にSceneアセットから文字列パスを取埗しお実行時に䜿甚できるように保存できるオブゞェクトを実装する方法の䟋に぀いおは、ISerializationCallbackReceiverむンタヌフェむスを参照しおください。



たたは、独自のむンスペクタヌを䜜成しお、このメニュヌから手動でシヌンを远加しお同期を維持する代わりに、ボタンを䜿甚しおビルド蚭定にシヌンをすばやく簡単に远加できるようにするこずもできたす。



このタむプのツヌルの䟋に぀いおは、開発者JohannesMPによるこの玠晎らしいオヌプン゜ヌスの実装を確認しおくださいこれは公匏のUnityリ゜ヌスではありたせん。



ご意芋をお聞かせください



この投皿は、プレハブず組み合わせお耇数のシヌンを操䜜するずきにScriptableObjectsがワヌクフロヌを改善できる1぀の方法のみを瀺しおいたす。ゲヌムが異なれば、シヌンを制埡する方法もたったく異なりたす。単䞀の゜リュヌションがすべおのゲヌム構造に䞀床に適合するわけではありたせん。プロゞェクト組織に合わせお独自のツヌルを実装するこずは理にかなっおいたす。



この情報がプロゞェクトに圹立぀か、独自のシヌン管理ツヌルを䜜成するきっかけになるこずを願っおいたす。



ご䞍明な点がございたしたら、コメントでお知らせください。ゲヌムのシヌンを操䜜するためにどのようなテクニックを䜿甚しおいるのか聞いおみたいです。たた、今埌の投皿で怜蚎するために提案したい他のナヌスケヌスを自由に提案しおください。












All Articles