🦢

Cluster Creator Kit と Unity Editor拡張 入門

2020/11/29に公開
1

この記事は Cluster Creator Kit Advent Calendar 2020 2020/12/04 に投稿する記事です。
https://adventar.org/calendars/5175

概要

何を書こうか迷ったけれど、 clusterゲームワールド杯 2020 に応募したワールドで利用した Unity Editor拡張 が便利だったので 一部を 入門 として記事にしてみました。
ClusterCreatorKit Clusterワールド制作ではスクリプトは使えないのですが Editor拡張 を使うと複雑なトリガー,ギミックを組み合わせたアイテムもコードで作る事ができて楽につくれるようになるので便利そうです。

内容

入門なので メニューから実行することで ワールドに必須のコンポーネント を配置するだけ のシンプルな Editor拡張 を作ってみたいと思います。

サンプル1

  1. ClusterCreatorKit 導入
  2. ワールドに必須のコンポーネント の用意
  3. Editor拡張 スクリプトを作ってみる
  4. 初期ワールド作る スクリプトを作って実行してみる
  5. ClusterCreatorKitのコンポーネントをGameObjectに追加してみる
  6. まとめ

1. ClusterCreatorKit 導入

Unity 2019.4.1f1

動作確認済バージョン 2019.4.1f1Unity ダウンロード アーカイブ からインストールする。
https://unity3d.com/jp/get-unity/download/archive

新規プロジェクトを作成


CreatorKitEditorSample でプロジェクト を 新規作成。

ClusterCreatorKit を プロジェクトに導入する

  1. ClusterCreatorKit をダウンロードして解凍する。
    https://github.com/ClusterVR/ClusterCreatorKit/releases
  2. Unityのメニュー Window > Package Manager から「Packages」ウィンドウを開いてダウンロードしたzipを解凍したファイルを選択する
  3. Project Settingsの設定
    Edit > Project Settings
項目
Player > Other Settings > Rendering > Color Space Linear

2. ワールドに必須のコンポーネント の用意

ワールドに必須のコンポーネント を参考に 3つのオブジェクトを作って Prefab にする。
https://clustervr.gitbook.io/creatorkit/world/require-components

Spawn Point

リスポーンした際の位置となるオブジェクト
- GameObject を作り 名前を SpawnPoint に設定する
- 子オブジェクト に GameObject を追加して PointObject に設定
- PointObjectSpawn Pointを設定する
- Transform Position Y を 2 に設定

Despawn Height

プレイヤーやMovable Itemをリスポーンする高さを決めるコンポーネント
- GameObject を作り 名前を Despawn Height に設定する
- 子オブジェクト に GameObject を追加して DespawnObject に設定
- DespawnObjectDespawn Heightを設定する
- Transform Position Y を -10 に設定

Floor

キャラクターが立つ為の床になるオブジェクト
- GameObject を作り 名前を Floor に設定する
- 子オブジェクト に Plane を追加
- Plane に Mesh Collider を設定する。

3つのコンポーネントを Prefab にする。

- `Asset/Editor/Items` フォルダを作成する
- Items へ 3つのコンポーネントを ドラッグ&ドロップ する
- Prefab になれば 青いアイコンに変わる

3. Editor拡張 を作ってみる

必須オブジェクトが準備できたので Editor拡張 を書いてみる。

ClusterCreatorEditorScript.cs を作成

Asset/Editor フォルダに C# スクリプト を作成 ファイル名は ClusterCreatorEditorScript にする。

ClusterCreatorEditorScript.cs を編集

  1. Unity のメニューに項目を追加して 実行 できるとこまで確認してみるコード
    ClusterCreatorEditorScript.cs 内容をコードに書き換えて Unity 画面に戻ると
    メニューに CreatorKitEditor が追加される。
ClusterCreatorEditorScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 1. UnityEditor を追加
using UnityEditor;

// 2. namespace  ClusterCreatorEditorScript を追加
namespace ClusterCreatorEditorScript
{
    // 3. class を EditorScript に名変更
    public class EditorScript
    {
        // 4. Start(), Update() は不要なので削除する
        // 5. メニューに "ClusterCreatorEditor/ワールド初期設定" を追加するコードを追加
        [MenuItem ("ClusterCreatorEditor/ワールド初期設定")]
        private static void InitWorld()
        {
            // メニューで選択されたら シーンに必須コンポーネントを配置 するメソッドを実行する
            InitScene();
        }

        // 6. シーンに必須コンポーネントを配置 するコードを追加する
        private static void InitScene() {
            Debug.Log("InitScene()");
        }
    }
}

  1. Unity のメニュー CreatorKitEditor -> ワールド初期配置 を実行してみる
    Console に InitScene() が出力される。

4. 初期ワールド作る スクリプトを作って、実行してみる

InitScene() を書き換えて ワールド初期設定 をしてみましょう。

ClusterCreatorEditorScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


// 1. UnityEditor を追加
using UnityEditor;
using UnityEditor.SceneManagement;

// 2. namespace  ClusterCreatorEditorScript を追加
namespace ClusterCreatorEditorScript
{
    // 3. class を EditorScript に名変更
    class EditorScript: EditorWindow
    {
        // 8. シーンに必須コンポーネントを配置 する実際のコードで利用するメンバ変数
        // プレハブフォルダ名 Assets/Prefab
        private static string PATH_DIST_REFAB_FOLDER_NAME = "Prefab";

        private static string PATH_SRC_DESPAWN_HEIGHTP_REFAB = "Assets/Editor/Items/DespawnHeight.prefab";
        private static string PATH_DIST_DESPAWN_HEIGHTP_REFAB = "Assets/Prefab/DespawnHeight.prefab";
        // private static Vector3[] PATH_DIST_DESPAWN_HEIGHTP_REFAB_TRANSFORM = {new Vector3(0,-10,0), Vector3.zero, new Vector3(1,1,1)};

        private static string PATH_SRC_SPAWNPOINT_REFAB = "Assets/Editor/Items/SpawnPoint.prefab";
        private static string PATH_DIST_SPAWNPOINT_REFAB = "Assets/Prefab/SpawnPoint.prefab";
        // private static Vector3[] PATH_DIST_SPAWNPOINT_TRANSFORM = {new Vector3(0,2,-4), Vector3.zero, new Vector3(1,1,1)};

        private static string PATH_SRC_FLOOR_REFAB = "Assets/Editor/Items/Floor.prefab";
        private static string PATH_DIST_FLOOR_REFAB = "Assets/Prefab/Ground.prefab";
        // private static Vector3[] PATH_DIST_FLOOR_TRANSFORM = {new Vector3(0,0,0), Vector3.zero, new Vector3(1,1,1)};

        // 4. Start(), Update() は不要なので削除する
        // 5. メニューに "ClusterCreatorEditor/ワールド初期設定" を追加するコードを追加
        [MenuItem ("ClusterCreatorEditor/ワールド初期設定")]
        private static void InitWorld()
        {
            // メニューで選択されたら シーンに必須コンポーネントを配置 するメソッドを実行する
            InitScene();
        }

        // 6. シーンに必須コンポーネントを配置 するコードを追加する
        private static void InitScene() {
            Debug.Log("InitScene()");

            // 9. シーンに必須コンポーネントを配置 する実際のコード
            // Prefab ディレクトリを作成
            Debug.Log(PATH_DIST_REFAB_FOLDER_NAME);
            if (AssetDatabase.IsValidFolder("Assets/" + PATH_DIST_REFAB_FOLDER_NAME) == false){
                Debug.Log("Create REFAB_FOLDER");
                AssetDatabase.CreateFolder("Assets", PATH_DIST_REFAB_FOLDER_NAME);
            }

            // Cluster 必須コンポーネントを Prefabから生成 する
            CreatePrefab(PATH_SRC_FLOOR_REFAB, PATH_DIST_FLOOR_REFAB /*, PATH_DIST_FLOOR_TRANSFORM */);
            CreatePrefab(PATH_SRC_SPAWNPOINT_REFAB, PATH_DIST_SPAWNPOINT_REFAB /*, PATH_DIST_SPAWNPOINT_TRANSFORM */);
            CreatePrefab(PATH_SRC_DESPAWN_HEIGHTP_REFAB, PATH_DIST_DESPAWN_HEIGHTP_REFAB /*, PATH_DIST_DESPAWN_HEIGHTP_REFAB_TRANSFORM */);
            
            // シーンを保存する
            EditorSceneManager.SaveOpenScenes();            
        }

        // 10. Cluster 必須コンポーネントを Prefab から生成 する
        private static void CreatePrefab(string pathSrc, string pashDist/*, Vector3[] transform*/) {
            // すでにあった場合は処理をしない
            GameObject dist = AssetDatabase.LoadAssetAtPath<GameObject>(pashDist);
            if (dist == null) {
                // Prefabから生成 する
                var src = PrefabUtility.LoadPrefabContents(pathSrc);
                dist = PrefabUtility.SaveAsPrefabAsset(src, pashDist);
                PrefabUtility.UnloadPrefabContents(src);
            }

            // シーンに Prefab を配置する
            // dist.transform.position = transform[0];
            // dist.transform.rotation = Quaternion.Euler(transform[1]);
            // dist.transform.localScale = transform[2];
            PrefabUtility.InstantiatePrefab(dist);
        }
    }
}

実行

hierarchy に配置されている3つのprefabを削除してから、メニュー ClusterCreatorEditor/ワールド初期設定 を実行する。
コードが正しければワールドに必須の要素が配置されるはず。

5. ClusterCreatorKitのコンポーネントをGameObjectに追加してみる

エディター上のウインドウで GameObjectを指定して ClusterCreatorKitのコンポーネント を設定できるようにしてみましょう。

ClusterCreatorEditorScript.cs

// 11. ClusterCreatorKit を利用する設定の追加
using ClusterVR.CreatorKit.Item;
using ClusterVR.CreatorKit.Item.Implements;
using ClusterVR.CreatorKit.Gimmick;
using ClusterVR.CreatorKit.Gimmick.Implements;
using ClusterVR.CreatorKit.Trigger.Implements;

public class EditorScript : EditorWindow
{
	// 12. エディターの GUI で使う メンバ変数を定義する
	private static GameObject selectGrabbableObject = null;

	// 13. メニューの追加 ClusterCreatorEditor/ユーティリティ
        [MenuItem ("ClusterCreatorEditor/ユーティリティ")]
        private static void OpenUtility()
        {
            // メニューで選択されたら ウインドウを開く
            EditorWindow.GetWindow<EditorScript>("ClusterCreatorEditor");
        }

        // 14. エディターの GUI を実装
        void OnGUI () {
            using (new GUILayout.VerticalScope())
            {
                EditorGUILayout.LabelField("Grabbable Item", EditorStyles.boldLabel);
                using (new GUILayout.HorizontalScope())
                {

                EditorGUILayout.LabelField("GameObject",  GUILayout.Width (100));                
                selectGrabbableObject = EditorGUILayout.ObjectField(selectGrabbableObject, typeof(Object), true) as GameObject;
                }

                if (GUILayout.Button("addGrabbable"))
                {
                    // selectGrabbableObject に Grabbable Item を設定する
                    addGrabbableObject();
                }
            }
        }
        
        // 15. selectGrabbableObject に Grabbable Item を設定する
        private static void addGrabbableObject(){
	    if (selectGrabbableObject == null) {
                Debug.Log(string.Format("<color=#ff0000>{0}</color>", "GameObject を指定してください"));
                return;
            }
            // CreatorKit で定義されているコンポーネントを AddComponent する
            selectGrabbableObject.AddComponent<GrabbableItem>();
        }
}

実行

  1. 手にもてるアイテムを作る為 Hierarchyに 新規で GameObject を配置。名前を GrabbableObject に変更
  2. 子オブジェクトに Cube を配置 position Y 1 scale 0.5,0.5,0.5 にする
  3. メニュー ClusterCreatorEditor -> ユーティリティ を選択して ウインドウを開く
  4. GameObject 欄に GrabbableObject をドラッグ&ドロップする
  5. addGrabbable ボタンを押す。
  6. GrabbableObject の Inspector に GrabbableItemに 必要コンポーネントが自動で追加される。

まとめ

4. 初期ワールド作る スクリプトを作って実行してみる5. ClusterCreatorKitのコンポーネントをGameObjectに追加してみる ができるようになると、Unity Editor 上では見た目複雑なアイテムも、コードから生成できるようになってすっきりしそうです。 Editor拡張 使いこなせるとワールド作成の幅ひろがるかなーと思います!

12/5 は #clusterゲームワールド杯で クイズ・正解にタッチ! ワールドを作った vin さんです。
logicつかったワールドの記事との事 気になります!

https://cluster.mu/w/954ece86-6d5b-46d8-803e-3aba42c08980

コード一式

https://github.com/tfuru/Cluster-CreatorEditorScriptSample.git

参考

Cluster Creator Kit ドキュメント
https://clustervr.gitbook.io/creatorkit/

ワールドに必須のコンポーネント
https://clustervr.gitbook.io/creatorkit/world/require-components

【cluster用アイテム】ハトソード
https://booth.pm/ja/items/2162556
ClusterCreatorKitのプロパティをGameObjectに追加する方法は 【cluster用アイテム】ハトソード のコードも参考になりそうです。コンポーネントのクラス名などは ClusterCreatorKit 自体のコードを参考に。

Cluster-World-Creator-Support
https://github.com/tfuru/Cluster-World-Creator-Support
自分で作っている 1ボタンでワールドに必要な要素を配置したり、ゲーム作成に便利な機能をUnityに追加する Unityエディタ拡張スクリプト です。

Discussion