Upload
others
View
1
Download
0
Embed Size (px)
Citation preview
1
平成 28年度 卒業論文
Unityにおけるゲームオブジェクトの
依存解析ツールの設計と実装
Game object in Unity
Design and implementation of dependency analysis tool
指導 松野 裕 准教授
日本大学理工学部応用情報工学科
3089 深沼 二葉
2
概要
Unity プロジェクト開発では、プログラムの多くの機能を GUI ベースで作
成することができる。そのため、簡単に 2D・3D プログラムを作ることがで
きる。
ゲームオブジェクト同士の参照関係の構築もその一つである。ゲームオブ
ジェクトに別のゲームオブジェクトやスクリプトをドラッグアンドドロップ
するだけで、容易に参照関係を構築することができる。また、スクリプト内
で生成した Transfome 型の変数にも同様の方法で参照関係を構築することが
できる。
しかし、それゆえにプロジェクトが大規模化するにつれて、オブジェクト
同士の関係を把握するのが困難になる。
本研究では、Unity プロジェクト開発を円滑に進めるために、オブジェク
ト・スクリプトの関係を容易に把握することができる支援ツールを設計・開
発する。
3
目次
第 1 章 はじめに ........................................................................................... 4
1.1. 研究の背景 ............................................................................................... 4
1.2. 研究の目的 ............................................................................................... 5
第 2 章 既存研究の紹介 ................................................................................. 6
2.1. 依存解析とは ............................................................................................. 6
2.2. Unity の依存解析 ...................................................................................... 7
第 3 章 Unity の用語説明 .............................................................................. 9
第 4 章 Unity プロジェクトの依存解析ツールの設計及び実装 .................... 12
4.1. ツールの概要 ........................................................................................... 12
4.2. 画面構成 .................................................................................................. 12
4.3. プログラム概要 ........................................................................................ 15
4.3.1. メイン画面を作成するプログラム ................................................ 16
4.3.2. サブ画面を作成するプログラム ................................................... 17
4.3.3. それぞれの関係を調べるプログラム ............................................ 18
4.3.4. ノードの色やタイトル名を決めるプログラム .............................. 19
第 5 章 Unity プロジェクトの依存解析ツールの評価 .................................. 21
第 6 章 まとめ ............................................................................................. 27
謝辞 ....................................................................................................................... 28
参考文献 ................................................................................................................. 29
付録 ....................................................................................................................... 36
4
第1章 はじめに
1.1. 研究の背景
Unity はゲーム開発エンジンの一つで、直感的な操作とコードだけで
2D/3D ゲームを開発することができる。
図 1:Unity で作成したゲームの一例(自動生成迷路ゲーム)
Unity では、基本的に Scene と呼ばれる一つのステージのようなものにゲ
ームオブジェクトを配置して画面を作成する。このオブジェクトにスクリプ
トをアタッチすることで初めてスクリプトが機能する。
図 1 の迷路ゲームの緑色のキューブは、置く位置をプログラムでランダム
に設定して置いている。どのような形のオブジェクトを置くかは画面上でド
ラッグアンドドロップするだけで決めることができるので、キューブではな
く円柱や他の 3D モデルにすることもできる。
また、オブジェクトに別のオブジェクトをアタッチするだけで親子関係を
構築することができる。これも画面上でドラッグアンドドロップするだけで
行うことができる。
まとめると、Unity では簡単な操作だけで容易に参照関係を構築すること
ができる。しかし、それゆえにプログラムが大規模化するにつれて、オブジ
ェクトやスクリプトの関係を把握するのが困難になる。そのため、参照する
オブジェクトを間違ってしまったり、参照し忘れてしまったりといったケア
レスミスが発生しやすくなる。
5
図 2:Unity における参照関係構築の例
1.2. 研究の目的
本研究では、Unity プロジェクト開発を円滑に進めるために、図 3 のよう
に、オブジェクトやスクリプトの関係を容易に把握することができる支援ツ
ールを設計・開発する。対応言語は javascript とする。
ツールは UnityEditor を拡張して作成する。
図 3:作成するツールで分析する依存関係の例
6
第2章 既存研究の紹介
2.1. 依存解析とは
依存解析とは、オブジェクト間の様々な依存関係を解析するプログラム解
析の一種である。最も基礎的な解析として、use-def 解析がある。use-def 解
析は変数の依存関係、つまり変数がどこで定義されてどこで使われているか
を解析している。例えば、プログラムの命令として、以下があったとする。
x=x+y;
x=3
a=x+y;
a=x+y;で用いられる x は、直前の x=3;で値が代入された x である。このと
き、x=3 の x から、a=x+y の x に線を結ぶ。このようにしてできる線の集ま
りを use-def チェーンという。
図 4:use-def チェーン
上の例の場合、x=x+y;で定義された x か、x=3;で定義された x のどちらが以
降のプログラムで用いられるかは一般に自明ではない。Use-def 解析の準備
として、定義した変数名が他の変数名と同じだった場合、その変数の名前を
書き換え、各変数の定義を字面上唯一にする。これを SSA(静的単一代入)と
いう。上の例では、以下のように書き換えられる。
x1=x2+y1;
x2=3
7
a1=x2+y1;
この結果、a1 への代入文で用いられる x が、x2=3;で定義されたものである
ことがすぐにわかる。
一般的な依存解析ツールの例として、jdeps と Understand について紹介
したい。
jdeps は、JDK8(java の開発元である Oracle 社が無償で提供しているソフ
トウェア開発のためのパッケージ)のコマンドライン・ツールの一つである。
Java のクラスやファイルの依存関係をパッケージ・レベルまたはクラス・
レベルで表示することができる。なお、表示方式は文字ベースである。
Understand はテクマトリックス株式会社が提供するプログラム解析ツー
ルである。プログラム内の関数の呼び出しや参照、クラスの構成、制御フロ
ーなどを解析し、グラフィカルに可視化することができる。C++や java、C#
など様々な言語に対応していて、400 万行のコードをわずか 15 分で解析す
ることが可能である。
2.2. Unity の依存解析
オブジェクトの親子関係なら、画面上の Hierarchy ウィンドウ(ゲームオ
ブジェクトの管理ウィンドウ)から確認することができる。また、スクリプト
で 取 得 す る こ と も 可 能 で あ る 。 C# の 場 合 、 親 な ら
「transfome.parent.gameObject」、
子なら「transfome.GetChild(i).gameObject」と記述すれば、親及び子が返
される。なお、この i は何番目の子を取得するかを示す変数である。
ゲームオブジェクトにアタッチされたコンポーネント(スクリプトを含む)
もインスペクターウィンドウを見ればわかる。スクリプトからなら、
GetComponent(複数探したい場合は GetComponents)を呼び出せばよい。例
えば今回の場合、アタッチされたスクリプトを探したいので、「オブジェク
ト名.GetComponent<MonoBehaviour>」と記述する。これを仮に A としよ
う。次に、「MonoScript.FromMonoBehaviour(A)」と記述することで、
MonoBehaviour が継承されているスクリプトから MonoScript を返しても
らうことができる。ここで得た MonoScript がアタッチされたスクリプトで
8
ある。
どのAssetをどのゲームオブジェクトが使用しているかということならば、
Unity 内の機能「Find References In Scene」で確認できる。また、オブジ
ェクト単位で確認したい場合は Profiler を使用すれば追跡する事ができる。
これも Unity の機能の一つである。しかしこれらはどちらも文字ベースで表
示されるため、ひとめで全て把握することは困難である。
ノードベースで作成されたものとしては、SeldomTools が作成した、
RelationsInspector などが AssetStore(UnityEditor からアクセスできる
Asset を販売しているオンラインショップ ) で販売されている。
RelationsInspector はいくつかの機能があるが、その中の一つ「Asset
referencs backend」では、「Find References In Scene」で確認できる情報
をノードベースで表示することができる。
本研究は、特に Unity プログラミング環境の特有の依存関係を解析するツ
ールを設計、試作する。
9
第3章 Unity の用語説明
• Unity
Unity とは、Unity Technologies 社が提供するゲーム開発エンジンである。
UnityScript(javaScript)、C#などの言語が使用可能である。 マルチプラッ
トフォームに対応しており、具体的にはニンテンドー3DS や playstation4
から、ios、android まで様々である。また、Unity 5.1 より、複数の VR デ
バイスをサポートするようになった。さらに、他のライブラリを Unity に入
れることで AR アプリケーションも作成可能である。
• シーン
新しい Unity プロジェクトを作成した時必ず作成されるものである。シー
ンにはゲームオブジェクトが含まれていて、環境や障害物、装飾を配置する
ことでゲームを細かく設定できる。あるシーン内で別のシーンを読み込むと
そのシーンに遷移できる。
• Asset
ゲームやプロジェクトで使用されるテクスチャや 3D モデルなどといった
個々のアイテムを表すものである。
Asset は外部から作成したファイルから取り込むことができる。種類によ
っては Unity 内部で作成できるものもある。
• ゲームオブジェクト(GameObject)
Unity の基礎となるオブジェクトである。ゲームオブジェクト自体の機能
は多くはないが、コンポーネントをアタッチすることによって実際の機能を
実装することができる。
ゲームオブジェクトには常に位置と回転、スケールを表すゲームオブジェ
クトコンポーネントがアタッチされている。ゲームオブジェクトコンポーネ
ントは親子関係化と呼ばれる概念を実装する。
• インスペクターウィンドウ(InspectorWindow)
ゲームオブジェクトのプロパティーや、Asset のインポート設定を見る事
10
ができる。
ゲームオブジェクトのプロパティーにはそのオブジェクトにアタッチさ
れた全てのコンポーネントとマテリアルのプロパティーが表示され、それら
を編集することができる。また、アタッチされたスクリプトの public 変数も
表示される。他のコンポーネントなどと同様に、スクリプトのパラメータや
初期値を設定することができる。
設定することのできるプロパティーは参照と値の二つに分類される。
➢ 参照プロパティー
他のオブジェクトやAssetとリンクさせるタイプのプロパティーである。
インスペクター内のプロパティーに適切なタイプのオブジェクトや
Asset をドラッグアンドドロップで割り当てることができる。
➢ 値プロパティー
変数やチェックボックス、カラーなどを変更できるプロパティーであ
る。
• プレハブ(Prefub)
作成済みのオブジェクトを複製する機能のことである。これを利用するこ
とで、元となるプレハブの設定と全く同じ性質のオブジェクトを多数作成す
ることができる。
• UnityEditor 拡張
UnityEditor では、環境設定の仕方やバージョン管理システムからビルド
の作成などができる。
UnityEditor 拡張とは UnityEditor に独自の機能を追加することである。
これにより、開発を手助けするツールを作成することができる。使用できる
言語は C#である。
• MonoBehaviour
Unity における全てのスクリプトから派生するベースクラスのことである。
Javascript を使用するときは自働的に MonoBehaviour から派生されるが、
C#または Boo の場合は明示的に派生させる必要がある。
11
• MonoScript
スクリプトのアセットを扱うクラスである。
12
第4章 Unity プロジェクトの依存解析ツールの設計及び実
装
4.1. ツールの概要
本研究にて作成するツールでは、選択したゲームオブジェクト、またはス
クリプトについて、次の 3 つの関係について調べ、ノードで表す。
• ゲームオブジェクト(O)にアタッチされたゲームオブジェクト(O)の関係。
以下この関係を OO とする。
• ゲームオブジェクト(O) にアタッチされたスクリプト(S) の関係。以下
この関係を OS とする。
• スクリプト(S) とスクリプトで生成した空のゲームオブジェクト(O)の
関係。以下この関係を SO とする。
4.2. 画面構成
本研究にて作成するツールにはメインウィンドウとサブウィンドウがあ
る。メインウィンドウは調査対象の設定を、サブウィンドウには結果の木構
造が表示される。図 5 は実際に作成したメインウィンドウである。
13
図 5:メインウィンドウ
メインウィンドウでは次の操作が可能である。
• メインウィンドウを閉じる
• ゲームオブジェクト選択
関係を調べたいゲームオブジェクトを選択できる。
• フォルダ選択
スクリプトが入っているフォルダを選択する。もし選んだフォルダに
スクリプトが入っていなかった場合、そのスクリプトの SO 関係を見る
ことはできない。
• スクリプト選択
関係を調べたいスクリプトを選択できる。
• ゲームオブジェクトを選択した場合のノード作成ボタン
• スクリプトを選択した場合のノード作成ボタン
このボタンを選択すると、メインウィンドウ上部にポップアップウィ
ンドウが表示される。そのポップアップウィンドウを図 6 に示す。ポッ
プアップウィンドウには選択したスクリプトをアタッチしたオブジェ
クト一覧を表示するポップアップメニューと、ノード作成ボタンがある。
ポップアップメニューから関係を知りたいオブジェクトを選択するこ
14
とができる。
• サブウィンドウを閉じる
図 6: ポップアップウィンドウ
それぞれに対応したノード作成ボタンをクリックすると、作成された画面
がサブウィンドウとして表示される。
図 7:サブウィンドウ
ツールの基本的な操作手順は次のようになる。
① メインウィンドウを開く。
② 調べたいゲームオブジェクトもしくはスクリプトを選択する。
③ SO 関係を知りたい場合、そのスクリプトが入っているフォルダを選択
15
する。
④ 調べたい対象に対応したノード作成ボタンを押す。もしスクリプトを選
択した場合は⑤へ進む。
⑤ 表示されたポップアップウィンドウからさらにオブジェクトを選択し
ポップアップウィンドウ上のノード作成ボタンを押す。
4.3. プログラム概要
本研究のツールは、メイン画面を作成するプログラム、サブ画面を作成す
るプログラム、それぞれの関係を調べるプログラム、ノードの色やタイトル
名を決めるプログラムで構成されている。図 8 に各プログラムの関係図を示
す。
各オブジェクト・スクリプトの依存関係はパスのような形で表してリスト
に格納する。このリストを以下データリストと呼ぶ。パスの形というのは、
例えば図 3 のオブジェクト C なら『オブジェクト A/オブジェクト B/オブジ
ェクト C』、スクリプト A なら『オブジェクト A/スクリプト A』といったよ
うに、そのスクリプトの親やアタッチ対象の名前を各オブジェクト・スクリ
プトに追加し、スラッシュで区切る。
16
図 8:プログラムの関係図
4.3.1. メイン画面を作成するプログラム
Unityに用意された独自のクラスEditorGUILayoutなどを利用して作成
した。また、このプログラムでは同時にノードの作成も行った。メインウ
ィンドウの作画及びノードに関する処理を指示するクラスを MainWindow
クラスと呼び、ノードの作画に関わる関数を Node クラスと呼ぶ。
ノードの作成に関わる関数について説明する。これは参考文献[38][37]の
プログラムを参考に作成した。
node_make 関数と Init 関数は MainWindow クラスの関数である。
MainWindow クラスでは、あらかじめ何も参照していない Node クラスの
オブジェクト root を生成しておく。
• node_make 関数
① もし root が空だった場合、それぞれの関係を調べるプログラムを呼び
出す。そのあと、ノード情報を Init 関数に渡す。
17
② Draw 関数を呼び出す。
• Init 関数
① i=0 とする。
② データリスト[i]を元に、ノードの座標、名前、色、タイトルを設定す
る。
③ もし現在作成しているノードがトップだった場合、設定したノードの
情報を root に渡して、Node クラスのコンストラクタを呼び出し、⑤
に進む。トップではない場合は④に進む。
④ 設定したノードの情報を root のリスト children に渡して、Node クラ
スのコンストラクタを呼び出す。
⑤ データリストの要素数と i の数が等しい場合は終了、そうでない場合は
i++して②へ進む。
Draw 関数、DrawNodeWindow 関数、DrawNodeLine 関数は Node クラ
スの関数である。
• Draw 関数
ノード本体を描く関数。
• DrawNodeWindow 関数
ノードをドラッグ可能する。また、ノード名を記すラベルを作成す
る。
• DrawNodeLine 関数
ノード間の線を描く関数。
4.3.2. サブ画面を作成するプログラム
このプログラムは 2 つのクラスが存在する。一つはサブウィンドウ用の
クラス、もう一つはメインウィンドウで、スクリプトを選択した場合のノ
ード作成ボタンを押した時に表示されるポップアップウィンドウの処理に
関するクラスである。
サブウィンドウクラスはノード作成を指示し、表示するクラスである。
ポップアップウィンドウ用のクラスでは、選択したスクリプトをアタッ
18
チしているオブジェクトを検索し、ポップアップメニューに表示する処理
を行っている。
4.3.3. それぞれの関係を調べるプログラム
依存関係の探索は、OO と OS は Unity 独自の関数で行い、SO は正規分
析で行った。ここで取得した関係はデータリストに逐次格納していく。
各関数のアルゴリズムを次に示す。
関係を知りたいゲームオブジェクト(以下オブジェクト A)とする。
• OO について調べる関数のアルゴリズム
① オブジェクト A のパスを取得し、データリストに追加する。この時、
もしオブジェクトAが階層の一番上のオブジェクトでなかったならば、
same_word 関数に追加するパスとオブジェクト A の名前を渡し、オ
ブジェクト名の重複を調べる。
② OSについて調べるプログラムを呼ぶ。この時渡す値はオブジェクトA
とする。
③ OO について調べるプログラムを呼ぶ。この時渡す値はオブジェクト
A の子供とする。オブジェクト A の子供の数だけ③を繰り返す。
④ オブジェクト A の階層の一番上のオブジェクトの名前を返す。
• OS について調べる関数のアルゴリズム
① オブジェクト A にアタッチされているスクリプトを全て取得する。
② 『オブジェクト A のパス/スクリプト名』をデータリストに追加する。
③ SOについて調べるプログラムを呼ぶ。この時渡す値はオブジェクト A
にアタッチされたスクリプトとする。戻り値として、スクリプトで作
成された空のオブジェクト名(以下空オブジェクト)をリストで受け取
る。
④ 『オブジェクト A のパス/スクリプト名/空オブジェクト』をデータリ
ストに追加する。これを③で受け取ったリストの数だけ繰り返す。
⑤ アタッチされているスクリプトがまだあった場合、②に戻る。
関係を知りたいスクリプトをスクリプト A と表記する。
19
• SO について調べる関数のアルゴリズム
① スクリプトにアクセスするためのパスを取得する。
② スクリプトを一行ずつ切り取り、regax 関数に渡す。得られた変数名
をリストに格納する。
③ ②で作成したリストを返す。
• regax 関数
① コメントアウトの記号「//」か「/*」があるかどうか調べる。「//」なら
null を返し終了、「/*」なら「*/」があるかどうか探す。あったら次に
進む。なかったら null を返し終了する。
② 正規表現で「var 変数名:Transform」を探す。
③ もしあったらその変数名を返す。なかったら null を返し終了する。
また、別のノードと名前が重複した場合に名前を一時的に変更する関数
も作成した。
• same_word 関数
① i=0、p=渡されたパス文字列とする。
② 渡されたパスに『オブジェクト A の名前/』があるか検索し、その位置
を取得する。
③ 取得した位置が−1 より大きければ i に1を足す。
④ 取得した位置以降のパス文字列を取得し、①に渡す。
⑤ i が 0 より大きければ p=渡されたパス文字列.over+i とする。
⑥ p を返す。
4.3.4. ノードの色やタイトル名を決めるプログラム
ノードの色やタイトル名に関する処理を行うプログラムである。主に
MainWindow クラスの Init 関数でノードの情報を設定する時に呼び出さ
れる。
• Sorting 関数
受け取った文字列の後ろからスラッシュを探索し、スラッシュ以下の文
20
字列を返す関数。
• over_name 関数
same_word 関数で追加した文字列『.over』以下を削除する関数。
• line_get 関数
受け取ったノードの親のデータリスト番号を探索し、その番号を返す関
数。
• decision_color 関数
各ノードの色とノードのタイトル名を決める関数。選択したオブジェク
ト/スクリプトは黄色、ゲームオブジェクトは青、スクリプトは赤、空のゲ
ームオブジェクトは緑で表示される。
21
第5章 Unity プロジェクトの依存解析ツールの評価
以下の Unity プロジェクトに対し依存解析ツールを使用した。
• 3 年次に作成した迷路ゲーム(Javascript)
スクリプト数は全シーン合わせて 30 である。
• 参考文献[37]のプログラムを元に作られた迷路ゲーム(Javascript)
• Unity の StandardAssets(C#)
• 他研究室の作成したメダルゲーム(C#)
図 9 は、3 年次に作成した迷路ゲームの迷路生成シーンに存在するゲームオ
ブジェクト Enemy の依存関係解析結果である。
図 9:3 年次に作成した迷路ゲーム(Javascript)のの迷路生成シーンに
存在するオブジェクト「Enemy」の解析結果
この図から、選択したオブジェクト Enemy の子にオブジェクト Enemy(1)と
Enemy(2)が存在し、それぞれに EnemyMove.js と hit.js がアタッチされてい
ることがわかる。また、EnemyMove.js では空のオブジェクト player が宣言
されている。
22
図 10はEnemyのHierarchyである。Enemyの下にEnemy(1)とEnemy(2)
が表示されていることから、この2つのオブジェクトが Enemy の子であるこ
とがわかる。
図 10:Enemy の Hierarchy
23
図 11:Enemy(2)のインスペクター
図 11 は Enemy の子オブジェクト Enemy(2)のインスペクターである。
Enemy(2)のインスペクターに EnemyMove.js と hit.js があることから、この
2 つのスクリプトが Enemy(2)にアタッチされていることがわかる。また、
EnemyMove.js の欄にオブジェクトがアタッチできる変数 player が表示され
ている。
これらの結果から、解析結果から得られた情報と実際の Unity 画面から得
られる情報は一致しているといえる。よって、ゲームオブジェクト Enemy の
依存関係は正しく解析されているといえる。
また、ツールを使用した際に以下の問題点が見つかった。
• 取得出来ない変数が存在した。
だが、変数名を変えてもインスペクターの表示自体が変わらないこ
と、別のプログラムで同じ変数を使用した際は取得できたことから、
Unity もしくは元のプログラム側の問題だと考えられる。
24
• オブジェクト名とスクリプト名が同じであった時、正しいデータを取
得できない。
• オブジェクト名が同じオブジェクトが複数存在する場合、選択したオ
ブジェクトのノードだけでなく、同じ名前のオブジェクトのノードも
黄色(選択したオブジェクトの色)になってしまう。
• アタッチしているスクリプトが C#であっても、ノード名が「スクリプ
ト名.js」となる。
これは取得したスクリプト名の拡張子に関わらず必ずノード名の末
に「.js」を付ける処理を行っているからである。
• ノードの数が多い時、ウィンドウに入りきらないことがある。
スクロール量が定められているのが原因と考えられる。
• ノード名がノードの幅より長い場合、ノード名が入りきらない。
• Namespace 名がある場合、スクリプト名ではなく Namespace 名が取
得される。
また、今回のツールは javascript のみ対応としたが、Unity では C#も盛ん
に使用されており、実際、サンプルプロジェクトを探す際、C#で作成された
プロジェクトの方が多いと感じた。よって C#にも対応する必要がある。
これらの問題点から、以下の改善すべき点が見つかった。
• OS 関係を調べる際、スクリプトとアタッチ先のオブジェクトが同じ
名前かどうか調べる。
• 取得したスクリプトの種類によってノード名に付ける拡張子を変える。
• ノードの数によってウィンドウのスクロール量を可変にする。
• ノード名の長さが一定以上の場合、ノードサイズを変更する。
• C#に対応できるようにする。
C# で空のゲームオブジェクトを生成するには、「 public
GameObject 変数名」と宣言すればよい。よって「 public
GameObject」という文字列をスクリプトから探索し、変数名を取得
できるようにすればよい。
また、実際に Unity を利用している方々からは、次のような点を改善すべ
きとのコメントをいただいた。
25
• 変数の競合関係を解析できるようにする
Unity が大規模になるにつれ、別のスクリプトで同じ名前のグロー
バル変数が存在することが多くなる。しかし、どのスクリプトにその
変数が使用されていたかわからなくなってしまうことが多い。そこで、
変数の競合関係も表示することができたらよいと感じた。
• static で宣言した空のゲームオブジェクトを区別できるようにする。
このツールでは static 変数も他の変数と変わらず表示されるが、
Unity では static で宣言した変数はインスペクターに表示されない。
static 変数のノードの色を変えるなど、他の変数と区別できるように
すべきである。
• ツール起動までのステップ数が多いため、ツールを使わない方が依存
関係の把握が早い場合がある。
例えば先ほど例に挙げた Enemy なら、1 回ボタンを押すだけで
Enemyの親子関係を把握することができる。また、そこからEnemy(1)
と Enemy(2)にアタッチしたスクリプトと、スクリプトで宣言した変
数を把握するためには 1 回ずつボタンを押せばよいので、合計 3 回ク
リックするだけで図 9 の情報を得ることができる。しかし作成したツ
ールだと、図 9 の情報を得るまで計 4 回ボタンをクリックする必要が
ある。このように、ノードがあまり深くない場合はツールを使わない
方が早く依存関係の把握ができる場合がある。つまり、ノードが深い
方がこのツールの有効性は高い。
そこで、オブジェクトやスクリプトのインスペクターに解析結果表
示ボタンを作成し、そのボタンを押したらそのインスペクター元のオ
ブジェクトやスクリプトの依存関係が見れる機能を追加すればよいと
考えた。
まとめると、名前の競合などで取得出来ないオブジェクトやスクリプトが
存在したり、ノードやノード名を表示しきれない、ノード名のミスなどのバ
グがいくつか見つかった。しかしアタッチしていないオブジェクトやスクリ
プト(拡張子のミスを除く)が表示されるなどといった、間違った依存関係が表
26
示されることはなかった。また、バグの他にいくつかの改善点も見つかった。
27
第6章 まとめ
本研究では Unity におけるオブジェクトとスクリプト間の依存関係解析を
行うツールを開発した。そして、自分が開発した Unity プロジェクト、ウェ
ブを参考に作成したプロジェクト、Unity のサンプルプロジェクト、他研究
室での Unity のテストプロジェクトの4つのプロジェクトにおいて開発した
ツールを適用した。その結果オブジェクトとスクリプト間の依存関係を概ね
正しく解析することができた。
今後は、見つかったバグの修正や、発見した改善点、いただいた改善点を
直していきたい。また、UI をもっとわかりやすく、ボタンを押す回数を減ら
し、より快適に使用できるようにしたい。他にも、スクリプトだけでなく、
Rigidbody(物理特性)など他のコンポーネントがオブジェクトにアタッチされ
ているかどうかの解析機能や、親もしくは子のノードのみを表示するなどと
いった機能を追加し、よりツールの完成度を高めていきたい。
28
謝辞
本研究及び論文に関しまして、様々なご指導をいただきました松野裕先生に
心より感謝いたします。また、Unity プロジェクトの提供や、様々なアドバ
イスを下さいました松野研究室及び吉川研究室の皆様に感謝いたします。
29
参考文献
1章
[1] 丸ノ内テック、“【Unity】オブジェクトの生成、追加”のページ、アク
セス日 2016 年 12 月 2 日
http://marunouchi-tech.i-studio.co.jp/2204/
[2] Unity エディター拡張入門、“概要”のページ他、アクセス日 2016 年
12 月 2 日
http://anchan828.github.io/editor-manual/web/summary_editor_exte
nsion.html
2章
[3] SATO, Hiroyuki's Page in the University of Tokyo、“プログラミング
言語処理系論 (10)”のページ、アクセス日 2017 年 1 月 25 日
http://www-sato.cc.u-tokyo.ac.jp/SATO.Hiroyuki/PLDI2012/2012-10.
[4] Cornell CIS Computer Science、“Introduction to Compilers”のペー
ジ、アクセス日 2017 年 1 月 25 日
http://www.cs.cornell.edu/courses/cs412/2004sp/lectures/lec36.pdf
[5] 静的単一代入最適化部、“静的単一代入形式に基づく最適化に関する研
究 研究成果”のページ、アクセス日 2017 年 1 月 25 日
http://www.is.titech.ac.jp/~sassa/coins-www-ssa/japanese/ssa-seika.p
df
[6] IT 用語辞典 e-Words、“JDK 【 Java Development Kit 】”のページ、
アクセス日 2017 年 1 月 25 日
http://e-words.jp/w/JDK.html
[7] ORACLE、“Java SE 概要”のページ、アクセス日 2017 年 1 月 25 日
http://www.oracle.com/technetwork/jp/java/javase/overview/8-whats-
new-2157071-ja.html
[8] ORACLE、“jdeps”のページ、アクセス日 2017 年 1 月 25 日
https://docs.oracle.com/javase/jp/8/docs/technotes/tools/unix/jdeps.ht
ml
30
[9] IT 用語辞典 e-Words、“JDK 【 Java Development Kit 】”のページ、
アクセス日 2017 年 1 月 25 日
http://e-words.jp/w/JDK.html
[10] ORACLE、“Java SE 概要”のページ、アクセス日 2017 年 1 月 25 日
http://www.oracle.com/technetwork/jp/java/javase/overview/8-whats-
new-2157071-ja.html
[11] ORACLE、“jdeps”のページ、アクセス日 2017 年 1 月 25 日
https://docs.oracle.com/javase/jp/8/docs/technotes/tools/unix/jdeps.ht
ml
[12] CodeZine、“400 万行のコードを 15 分で見える化!プログラム解析ツー
ル『Understand』で開発効率アップ”のページ、アクセス日 2017 年
1 月 25 日
https://codezine.jp/article/detail/5204
[13] TechMatrix、“ソースコード解析ツール Understand”のページ、アク
セス日 2017 年 1 月 25 日
https://www.techmatrix.co.jp/product/understand/index.html
[14] Qiita、“【Unity】スクリプトからオブジェクトやコンポーネント操作ま
とめ”のページ、アクセス日 2017 年 1 月 25 日
http://qiita.com/shoridevel/items/e3985b05824848720e83
[15] Unity|DOCUMENTATION、“MonoScript.FromMonoBehaviour”の
ページ、アクセス日 2017 年 1 月 25 日
https://docs.unity3d.com/jp/current/ScriptReference/MonoScript.Fro
mMonoBehaviour.html
[16] Unity|DOCUMENTATION、“GameObject.GetComponent”のページ、
アクセス日 2017 年 1 月 25 日
https://docs.unity3d.com/ja/current/ScriptReference/GameObject.Get
Component.html
[17] 寺シュールブログ、“【Unity】指定のプレハブやテクスチャが、どのシ
ーンのどのオブジェクトで使用されているのかを見つける”のページ、
アクセス日 2017 年 1 月 20 日
http://tsubakit1.hateblo.jp/entry/2015/09/01/233000
[18] unity、“UNITY のシーンをひも解き把握するには…”のページ、アク
31
セス日 2017 年 1 月 20 日
http://japan.unity3d.com/unite/unite2015/files/DAY2_1300_room2_Y
amamura.pdf
[19] unity、“RelationsInspector エディタ拡張/ユーティリティ”のページ、
アクセス日 2017 年 1 月 20 日
https://www.assetstore.unity3d.com/jp/#!/content/53147
[20] Seldom Tools Editor extensions for Unity、“Dependency backend”の
ページ、アクセス日 2017 年 1 月 20 日
https://seldomu.github.io/riBackends/ObjectDependency/
[21] Unity|DOCUMENTATION、“Unity マニュアル”のページ、アクセ
ス日 2017 年 1 月 20 日
https://docs.unity3d.com/ja/current/Manual/index.html
3章
[22] ハコソフト、“Unity で AR アプリを作る”のページ、アクセス日 2016
年 12 月 2 日
http://pg-box.jp/blog/20140909/ar
[23] 侍エンジニア塾ブログ、“【入門者必見】Unity とは?意味や特徴、特性、
使い道を徹底解説”のページ、アクセス日 2016 年 12 月 2 日
http://www.sejuku.net/blog/6616#Unity
[24] Unity マニュアル、“VR 概要”のページ、アクセス日 2016 年 12 月 2
日
https://docs.unity3d.com/ja/current/Manual/VROverview.html
[25] atmarkit、“ゲーム開発初心者のための Unity 入門(12):Unity で
GameObject を Prefab 化し、スクリプトで動的にインスタンス生成す
るには (2/6)”のページ、アクセス日 2017 年 1 月 20 日
http://www.atmarkit.co.jp/ait/articles/1502/12/news041_2.html
[26] Unity|DOCUMENTATION、“アセットワークフロー”のページ、アク
セス日 2017 年 1 月 20 日
https://docs.unity3d.com/ja/current/Manual/AssetWorkflow.html
[27] Unity|DOCUMENTATION、“ゲームオブジェクト”のページ、アクセ
ス日 2017 年 1 月 20 日
https://docs.unity3d.com/ja/current/Manual/class-GameObject.html
32
[28] Unity|DOCUMENTATION、“コンポーネントの紹介”のページ、アク
セス日 2017 年 1 月 20 日
https://docs.unity3d.com/ja/current/Manual/Components.html
[29] Unity|DOCUMENTATION、“インスペクターウィンドウ”のページ、
アクセス日 2017 年 1 月 20 日
https://docs.unity3d.com/ja/current/Manual/UsingTheInspector.html
[30] Unity|DOCUMENTATION、“プロパティーの編集”のページ、アクセ
ス日 2017 年 1 月 20 日
https://docs.unity3d.com/ja/current/Manual/EditingValueProperties.
html
[31] Unity|DOCUMENTATION、“エディター機能”のページ、アクセス日
2017 年 1 月 20 日
https://docs.unity3d.com/ja/current/Manual/EditorFeatures.html
[32] Unity|DOCUMENTATION、“シーン”のページ、アクセス日 2017
年 1 月 20 日
https://docs.unity3d.com/jp/current/Manual/CreatingScenes.html
[33] Qiita、“[Unity] Scene の役割や使い方をざっくりまとめた”のページ、
アクセス日 2017 年 1 月 20 日
http://qiita.com/lycoris102/items/bf0a9ec4a653b4dd97b9
[34] TECHACADEMY、“複製が簡単にできる!Unity でプレハブ(Prefabs)
を作る方法【初心者向け】”のページ、アクセス日 2017 年 1 月 20 日
https://techacademy.jp/magazine/2553
[35] Unity|DOCUMENTATION、“MonoBehaviour”のページ、アクセス
日 2017 年 1 月 20 日
https://docs.unity3d.com/jp/current/ScriptReference/MonoBehaviour.
html
[36] Unity|DOCUMENTATION、“MonoScript”のページ、アクセス日
2017 年 1 月 20 日
https://docs.unity3d.com/jp/current/ScriptReference/MonoScript.html
4章
[37] Unity 入門、“Unity 立体迷路を作ろう”のページ、アクセス日 2017
33
年 1 月 26 日
https://openbook4.me/projects/161/sections/958
プログラム
[38] Qiita、“【Unity】エディター拡張で木構造を表示させる”のページ、ア
クセス日 2017 年 1 月 20 日
http://qiita.com/r-ngtm/items/9df4629a27cb080bfc70
[39] Qiita、“Unity の拡張でノードベースなウィンドウを作る”のページ、
アクセス日 2016 年 10 月 18 日
http://qiita.com/bonon0/items/f71a0c33766b67b9f891
[40] atmarkit、“LINQ:文字列中における特定文字の出現回数をカウントす
るには?[C#、VB]”のページ、アクセス日 2017 年 1 月 20 日
http://www.atmarkit.co.jp/ait/articles/1411/25/news131.html
[41] iPentec Document Global Index、“[C#] 文字列を後方から検索する -
LastIndexOf による文字列検索”のページ、アクセス日 2017 年 1 月
20 日
https://www.ipentec.com/document/document.aspx?page=csharp-stri
ng-lastindexof
[42] テラシュールブログ、“Unity のシーン内で特定のコードを持つコンポ
ーネントを見つける機能を作った”のページ、アクセス日 2017 年 1
月 20 日
http://tsubakit1.hateblo.jp/entry/2014/11/24/232623
[43] 忘れ物はプログラム、“Unity : エディタ拡張でフォルダを受け取る.”
のページ、アクセス日 2017 年 1 月 20 日
http://seesaawiki.jp/wasure_matsu_program/d/Unity%20%3A%20%A
5%A8%A5%C7%A5%A3%A5%BF%B3%C8%C4%A5%A4%C7%A5%D
5%A5%A9%A5%EB%A5%C0%A4%F2%BC%F5%A4%B1%BC%E8%
A4%EB.
[44] 万年素人から Geek への道、“FileInfo から拡張子を外して取得”のペー
ジ、アクセス日 2017 年 1 月 20 日
http://d.hatena.ne.jp/shinriyo/20131122/p2
[45] 端くれプログラマの備忘録、“[C#] テキストファイルを読み込む”のペ
34
ージ、アクセス日 2017 年 1 月 20 日
http://www.84kure.com/blog/2014/07/02/c-テキストファイルを読み込
む/
[46] 某エンジニアのお仕事以外のメモ、“C#で正規表現を使って文字列を抽
出する”のページ、アクセス日 2017 年 1 月 20 日
http://bacchus.ivory.ne.jp/gin/post-799/
[47] unity、“How do I count or get references to all gameobjects that are
tagged with a particular tag?”のページ、アクセス日 2017 年 1 月 20
日
http://answers.unity3d.com/questions/9821/how-do-i-count-or-get-ref
erences-to-all-gameobject.html
[48] Unity|DOCUMENTATION、“Null Reference Exception”のページ他、
アクセス日 2016 年 10 月 18 日
https://docs.unity3d.com/ja/current/Manual/NullReferenceException.
html
[49] Qiita、“Unity エディタ拡張の作り方 1”のページ、アクセス日 2016
年 10 月 18 日
http://qiita.com/ysida/items/9e0c801b2353abc140b8
[50] ケットシーウェア、“【エディタ拡張徹底解説】初級編④:配置調整用の
Horizontal と Vertical【Unity】”のページ、アクセス日 2016 年 10 月
18 日
http://caitsithware.com/wordpress/archives/1393
[51] ケットシーウェア、“【エディタ拡張徹底解説】初級編①:ウィンドウを
自作してみよう【Unity】”のページ、アクセス日 2016 年 10 月 18 日
http://caitsithware.com/wordpress/archives/1377
[52] 万年素人から Hacker への道、“List の参照渡し C# Unity”のページ、
アクセス日 2016 年 10 月 18 日
http://shinriyo.hateblo.jp/entry/2015/09/09/List の 参 照 渡 し
_C%23_Unity
[53] 某エンジニアのお仕事以外のメモ、“C#で正規表現を使って抽出した文
字列から一部を取り出す”のページ、アクセス日 2016 年 10 月 18 日
http://bacchus.ivory.ne.jp/gin/post-802/
35
[54] も う な ん か 色 々 と 断 片 化 し て い ま @jigaX 、
“[Unity3D][UnityEditor]EditorWindow の最小構成からボタン配置や
らサブウィンドウの生成やら”のページ、アクセス日 2016 年 10 月 18
日
http://jigax.jp/unity3dunityeditoreditorwindow/
[55] よろしくおねがいしました、“Unityのエディタ拡張でのメチャ細Tips”
のページ、アクセス日 2016 年 10 月 18 日
http://sassembla.github.io/Public/2015:08:27%2021-54-57/2015:08:27
%2021-54-57.html
[56] コガネブログ、“【Unity】すべての子オブジェクトを取得する拡張メソ
ッド”のページ、アクセス日 2016 年 10 月 18 日
http://baba-s.hatenablog.com/entry/2014/07/29/082441
[57] Buravo46's Note、“【Unity】Hierarchy 上のゲームオブジェクトを全て
取得”のページ、アクセス日 2016 年 10 月 18 日
http://buravo46.hatenablog.com/entry/2014/12/31/064658
[58] devlog [naru design]、“Unity3D:ファイルの一覧を取得する”のページ、
アクセス日 2016 年 10 月 18 日
http://narudesign.com/devlog/unity-get-file-list/
[59] 丸ノ内テック、“【Unity】他のオブジェクトにアタッチされたスクリプ
トにアクセスする”のページ、アクセス日 2016 年 10 月 18 日
http://marunouchi-tech.i-studio.co.jp/2284/
[60] MIZUTANIKIRIN、“[Unity] 多次元 List の作り方”のページ、アクセ
ス日 2016 年 10 月 18 日
http://mizutanikirin.net/unity-多次元 list の作り方
[61] けいごのなんとか、“様々な EditorWindow①”のページ、アクセス日
2017 年 1 月 26 日
http://anchan828.hatenablog.jp/entry/2013/02/14/022551
[62] プログラムは、用いる言葉の選択で決まる、“【Unity】簡単なメッセー
ジボックスをつくる”のページ、アクセス日 2017 年 1 月 26 日
http://taka-say.hateblo.jp/entry/2014/02/28/001514
36
付録
付録として、実際のプログラムを載せる。
• MainWindow.cs(行数は 206 行)
1 using UnityEngine;
2 using UnityEditor;
3 using System.Collections;
4 using System.Collections.Generic; //List 用
5 using System.Text.RegularExpressions;
6 using System.IO; //外部データ読み書き
7 using System; //エラー用
8
9 public class MainWindow : EditorWindow
10 {
11 private Node root;
12
13 [MenuItem ("依存関係/依存関係チェックツール")]
14 public static void ShowWindow () {
15 EditorWindow.GetWindow(typeof(MainWindow));
16 }
17
18 static DefaultAsset searchFolder = null;
19 static Transform select_object=null;
20 static MonoScript select_script = null;
21 static GameObject top_SO=null;
22
23 node_data getdata;
24 node_config config;
25
26 open_pop s_popup;
27
28 List<string> all_data = new List<string>();
29
30 static bool object_flag;
37
31 static bool script_flag;
32
33 public int index = 0;
34
35 open_pop script_pop;
36 Rect buttunRect;
37
38 void OnGUI () {
39 if (GUILayout.Button ("MainWindow Close")) {
40 Close();
41 }
42
43 EditorGUILayout.LabelField ("調べたいオブジェクトかスクリプトを選択してください");
44
45 select_object = (Transform)EditorGUILayout.ObjectField("オブジェクト",select_object, typeof(Transform), true);
46
47 select_script = (MonoScript)EditorGUILayout.ObjectField ("スクリプト",select_script, typeof(MonoScript), true);
48 EditorGUILayout.HelpBox ("js ファイル限定です\n 何か選ばないとエラーが起きます", MessageType.Info);
49
50 searchFolder = (DefaultAsset)EditorGUILayout.ObjectField ("検索フォルダ", searchFolder, typeof(DefaultAsset), true);
51 EditorGUILayout.HelpBox ("調べたいスクリプトが入っているフォルダを選択してください。", MessageType.Info);
52
53 if (GUILayout.Button ("Find object dependencies")) {
54 object_flag = true;
55 script_flag = false;
56
57 if (select_object == null) {
58 UnityEditor.EditorUtility.DisplayDialog ("Notice", "オブジェクトを選択してください", "OK");
59 } else {
60 var w = EditorWindow.GetWindow<SubWindow> ();
61 w.Show ();
62 }
63 }
64
38
65
66 if(GUILayout.Button ("Find script dependencies")){
67 getdata= new node_data(all_data,searchFolder,select_script,select_object,object_flag,script_flag,top_SO);
68
69 object_flag = false;
70 script_flag = true;
71 string check_path=getdata.get_path();
72
73 DirectoryInfo dir = new DirectoryInfo(check_path);
74 FileInfo[] info = dir.GetFiles("*.cs");
75
76 if (select_script == null) {
77 UnityEditor.EditorUtility.DisplayDialog ("Notice", "スクリプトを選択してください", "OK");
78 } else if (info.Length > 0) {
79 foreach (FileInfo f in info) {
80 Debug.Log ("f>" + f + "\t" + Path.GetFileNameWithoutExtension (f.Name));
81 if (Path.GetFileNameWithoutExtension (f.Name) == select_script.name) {
82 UnityEditor.EditorUtility.DisplayDialog ("Notice", "jsファイルを選択してください", "OK");
83 break;
84 }
85 script_pop = new open_pop (select_script, top_SO);
86 PopupWindow.Show (buttunRect, script_pop);
87 }
88 }else {
89 script_pop = new open_pop (select_script, top_SO);
90
91 PopupWindow.Show (buttunRect, script_pop);
92 }
93
94 }
95
96 if (GUILayout.Button ("SubWindow Close")) {
97 EditorWindow.GetWindow<SubWindow> ().Close();
98 }
99
39
100 }
101 public void node_make(){
102 string mother = null;
103
104 all_data.Clear();
105 getdata= new node_data(all_data,searchFolder,select_script,select_object,object_flag,script_flag,top_SO);
106
107 if (this.root == null) {
108 mother=getdata.data ();
109
110 if (object_flag == true) {
111 this.Init (mother, select_object.name);
112 } else if (script_flag == true) {
113 this.Init (mother, select_script.name);
114 }
115 }
116
117 BeginWindows ();
118 this.root.Draw ();
119 EndWindows ();
120 }
121
122 public string label_name;
123
124 public void Init(string top_name,string select_name){
125 string node_name;
126 string node_color=null;
127
128 int position_x = 0, position_y = 0;
129 int id = 0;
130 int mae_id;
131
132 int list_count = all_data.Count;
133
134 config=new node_config(select_name,select_object);
135
40
136
137 for (int i = 0; i < list_count; i++) {
138 id = i;
139 //ある文字からある文字までにいくつ/があったか?
140 position_x = all_data [i].Length - all_data [i].Replace('/'.ToString(), "").Length;
141 int yi = System.Math.Abs(position_x -i); //絶対値
142 position_y = 60 * yi;
143
144 node_name = config.Sorting(all_data [i]);
145
146 node_color = config.decision_color(node_name,all_data[i],ref label_name);
147 mae_id=config.line_get (all_data [i],ref all_data)-1;
148 Debug.Log (">>>"+label_name);
149
150 if (node_name == top_name || node_name == top_name+".js") {
151 root = new Node (id, new Vector2 (220f * position_x + 20, 10f + position_y), node_name, node_color,mae_id,label_name);
152 } else {
153 node_name = config.over_name (node_name);
154 root.children.Add (new Node (id, new Vector2 (220f * position_x + 20, 10f + position_y), node_name, node_color,mae_id,label_name));
155 }
156
157 }
158
159 }
160
161 public class Node{
162 public int id;
163 public int mae_id;
164
165 public Rect window;
166 public List<Node> children = new List<Node>();
167
168 public string name;
169 public string color;
41
170 public string label;
171
172 public Node(int id, Vector2 position,string name,string node_color,int mae_id,string label){
173 this.id = id;
174 this.window = new Rect(position, new Vector2(150, 50));
175 this.name=name;
176 this.color=node_color;
177 this.mae_id=mae_id;
178 this.label=label;
179 }
180
181 public void Draw(){
182 this.window = GUI.Window(this.id, this.window, DrawNodeWindow,label,this.color);
183
184 foreach (var child in this.children){
185 if(child.mae_id>-1){
186 DrawNodeLine(children[child.mae_id].window, child.window);
187 }else{
188 DrawNodeLine(this.window, child.window);
189 }
190 child.Draw();
191 }
192 }
193
194 void DrawNodeWindow(int id){
195 GUI.DragWindow();
196 GUI.Label(new Rect(20, 22, 120, 50), "["+id+"]"+name, EditorStyles.label);
197 }
198
199 //ラインを作る
200 static void DrawNodeLine(Rect start, Rect end){
201 var start_line = new Vector3 (start.x + start.width, start.y + start.height / 2f, 0f);
202 var end_line = new Vector3 (end.x, end.y + end.height / 2f, 0f);
203 Handles.DrawLine (start_line, end_line);
204 }
205 }
42
206 }
• SubWindow.cs(行数は 85 行)
1 using UnityEngine;
2 using UnityEditor;
3 using System.Collections.Generic; //List 用
4 using System.Collections;
5 using System; //エラー用
6
7 public class SubWindow: EditorWindow
8 {
9 MainWindow T_main = new MainWindow();
10 Vector2 leftScrollPos = Vector2.zero;
11
12 void OnGUI(){
13 leftScrollPos = EditorGUILayout.BeginScrollView (leftScrollPos, GUI.skin.box);
14 {
15 T_main.node_make ();
16 GUILayoutUtility.GetRect(new GUIContent(string.Empty), GUIStyle.none, GUILayout.Width(1500), GUILayout.Height(1500));
17 }
18 EditorGUILayout.EndScrollView ();
19 }
20
21 }
22
23
24 public class open_pop:PopupWindowContent{
25 List<string> SO_objname = new List<string>();
26 List<GameObject> SO_obj = new List<GameObject>();
27 public string[] option_obj;
28 static int index = 0;
29 public MonoScript select_script;
30 public GameObject top_select=null;
31
32 public open_pop(MonoScript select_script,GameObject top_select){
43
33 this.select_script = select_script;
34 this.top_select = top_select;
35 }
36
37 public override void OnGUI(Rect rect){
38 pop ();
39 EditorGUILayout.HelpBox ("調べたいスクリプトは次のオブジェクトにアタッチされています。\n" +
40 "関係を知りたいオブジェクトを選んでください。", MessageType.Info);
41
42 index = EditorGUILayout.Popup("select object>",index,option_obj);
43
44 if(GUILayout.Button ("Find script dependencies")){
45 var w = EditorWindow.GetWindow<SubWindow> ();
46 w.Show ();
47 }
48
49 }
50
51 public override Vector2 GetWindowSize(){
52 return new Vector2 (300,100);
53 }
54
55 public GameObject pop(){
56 SO_objname.Clear ();
57 SO_obj.Clear ();
58
59 foreach (GameObject obj in UnityEngine.Object.FindObjectsOfType(typeof(GameObject))) {
60 MonoBehaviour[] script_name = obj.GetComponents<MonoBehaviour> ();
61 foreach (MonoBehaviour sc in script_name) {
62 if (MonoScript.FromMonoBehaviour (sc).name == select_script.name) {
63 Debug.Log ("sc>" + MonoScript.FromMonoBehaviour (sc).name + "\tobj>" + obj);
64 SO_objname.Add (obj.name);
65 SO_obj.Add (obj);
66 }
67 }
44
68
69 }
70
71 if(SO_obj.Count>0){
72 option_obj= SO_objname.ToArray ();
73 top_select = SO_obj [index];
74
75 Debug.Log (index+">"+top_select+"\t"+SO_obj [index]);
76
77 }else{
78 option_obj =new string[] {"Noting"};
79
80 }
81 return top_select;
82
83 }
84
85 }
• node_data.cs(行数は 295 行)
1 using UnityEngine;
2 using UnityEditor;
3 using System.Collections;
4 using System.Collections.Generic; //List 用
5 using System.Text.RegularExpressions;
6 using System.IO; //外部データ読み書き
7 using System; //エラー用
8
9 public class node_data {
10 List<string> data_list = new List<string>();
11
12 public DefaultAsset searchFolder;
13 public Transform select_object;
14 public MonoScript select_script;
15 public bool o_flag;
16 public bool s_flag;
45
17 public GameObject top_SO;
18
19 open_pop s_popup;
20
21 public node_data(List<string> data_list,DefaultAsset searchFolder,MonoScript select_script,Transform select_object,bool o_flag,bool s_flag,GameObject top_SO){
22 this.data_list = data_list;
23 this.searchFolder = searchFolder;
24 this.select_object = select_object;
25 this.select_script = select_script;
26 this.o_flag = o_flag;
27 this.s_flag = s_flag;
28 this.top_SO = top_SO;
29 }
30
31 public string data(){
32 string mother = null;
33
34 GameObject top = null;
35 List<string> SO_list = new List<string>();
36
37 SO_list.Clear ();
38
39 //OOOS
40 foreach (GameObject obj in UnityEngine.Object.FindObjectsOfType(typeof(GameObject))) {
41 if(obj.activeInHierarchy ){
42 Transform obj_t = obj.transform;
43 if(o_flag==true&& obj_t == select_object){
44 //もし親がいたらそっちを調べる
45 top=get_top(obj);
46 // シーン上に存在するオブジェクトならば処理.
47 mother = read_OO (top);
48 }
49 }
50 }
51
46
52 if(s_flag==true){
53 s_popup = new open_pop(select_script,top_SO);
54 top_SO = s_popup.pop();
55 Debug.Log ("top_SO>"+top_SO);
56 if (top_SO != null) {
57 top = get_top (top_SO);
58 Debug.Log ("top>" + top);
59 mother = read_OO (top);
60 } else {
61 mother = select_script.name;
62 SO_list = read_SO (select_script);
63 data_list.Add (mother+".js");
64 foreach(string s in SO_list){
65 data_list.Add (mother+".js/"+s);
66 }
67 }
68 }
69
70 foreach(string a in data_list){
71 Debug.Log ("<color=blue>"+a+"</color>");
72 }
73
74 return mother;
75 }
76
77 public GameObject get_top(GameObject obj){
78 if (obj.transform.root.gameObject == obj) {
79 return obj;
80 } else {
81 return obj.transform.root.gameObject;
82 }
83 }
84
85
86 public string get_path(){
87 string path = null;
47
88
89 if (searchFolder != null) {
90 //アセットからパスを取得
91 path = AssetDatabase.GetAssetOrScenePath (searchFolder);
92
93 string[] folderList = path.Split ('/');
94
95 //フォルダ以外は排除
96 if (folderList [folderList.Length - 1].Contains (".")) {
97 searchFolder = null;
98 }
99
100 } else {
101 path = "Assets";
102 }
103
104 return path;
105 }
106
107 //SO
108 public List<string> read_SO(MonoScript check_script){
109 string path=null;
110 string script_path=null;
111
112 List<string> list_seiki = new List<string>();
113
114 path = get_path ();
115
116 if(path!=null){
117 Debug.Log("パスは"+path);
118
119 DirectoryInfo dir = new DirectoryInfo(path);
120 FileInfo[] info = dir.GetFiles("*.js");
121
122 foreach(FileInfo f in info){
123 if(check_script != null && Path.GetFileNameWithoutExtension(f.Name)==check_script.name){
48
124 script_path = path + "/" + f.Name;
125 openscript (script_path,ref list_seiki,check_script.name);
126 }
127 }
128 }
129
130 return list_seiki;
131 }
132
133 //スクリプトを一行ずつ読み込み
134 public void openscript(string script_path,ref List<string> list_seiki,string s_name){
135 try
136 {
137 StreamReader reader = new StreamReader(script_path);
138
139 int count = 0; // line counter
140 string line; // line buffer
141 string re_kekka;
142
143 while ((line = reader.ReadLine()) != null) // read one line
144 {
145 re_kekka=regex(line);
146
147 if(re_kekka != null){
148 list_seiki.Add(re_kekka);
149 }
150
151 count++; // count up
152 }
153
154 reader.Close();
155 Debug.Log("Total lines = {0}"+count);
156
157 }
158 catch (NullReferenceException ex)
159 {
49
160 Debug.Log("エラー");
161 }
162
163 }
164
165 bool flag_comment=false; //コメントアウト内かどうかのフラグ
166
167 public string regex(string check_word){
168 string kekka;
169
170 // コメントアウトで囲まれた言葉を除く
171 if (flag_comment == false) {
172 //一行コメントアウト
173 Match mO_Slash = Regex.Match (check_word, @"//");
174 //コメントアウト開始を調べる
175 Match mO_Start = Regex.Match (check_word, @"/\*");
176
177 if (mO_Slash.Success) {
178 return null;
179 }else if(mO_Start.Success){ //発見、フラグを上げる
180 flag_comment = true; //コメントアウト開始
181 }
182
183 }
184
185 if(flag_comment==true){ //コメントアウト内の時、同じ行に/*と*/があった場合
186 //コメントアウト終了を調べる
187 Match mO_End = Regex.Match(check_word, @"\*/");
188 if(mO_End.Success){
189 //Debug.Log (mO_End.Value);
190 flag_comment = false; //フラグを下げる
191 }else{
192 return null;
193 }
194
195 }
50
196
197 //空のオブジェクトを宣言しているかどうか調べる
198 Match matchedObject = Regex.Match (check_word, "var (.*):.*Transform");
199
200 if (matchedObject.Success) {
201 kekka = matchedObject.Groups [1].Value;
202 return kekka;
203 } else {
204 return null;
205 }
206
207 }
208
209 public string read_OO(GameObject Ob_OO){
210 string top;
211 string _parent=null;
212
213 top=Ob_OO.transform.root.gameObject.name;
214
215 //top とオブジェクトの名前が違うならそのオブジェクトはトップではない、つまり親が存在する
216 if (Ob_OO.transform.root.gameObject != Ob_OO) {
217 _parent = Ob_OO.transform.parent.gameObject.name;
218 Transform p = Ob_OO.transform.parent;
219 string pa=null;
220
221 //親を探索
222 while(p!=null){
223 pa=p.name+"/"+pa;
224 p=p.transform.parent;
225 }
226
227 string ppp = same_word (pa+""+Ob_OO.name,Ob_OO.name);
228 data_list.Add(ppp);
229 Debug.Log ("<color=red>"+pa+""+Ob_OO.name+"</color>");
230
231 Debug.Log("親は"+_parent);
51
232 }
233 else {
234 Debug.Log (Ob_OO.name+"がトップ");
235 data_list.Add(Ob_OO.name);
236 _parent=top;
237 }
238
239 read_OS (Ob_OO);
240
241 for(int i=0;i<Ob_OO.transform.childCount;i++){
242 read_OO (Ob_OO.transform.GetChild(i).gameObject);
243 }
244
245 return _parent;
246 }
247
248
249 public void read_OS(GameObject Ob_OS){
250 if(Ob_OS.GetComponent<MonoBehaviour>() != null){
251 MonoBehaviour[] script_name = Ob_OS.GetComponents<MonoBehaviour> ();
252 string name = data_list [data_list.Count - 1];
253
254
255 for(int i=0;i<Ob_OS.GetComponents<MonoBehaviour> ().Length;i++){
256 List<string> seiki=new List<string>();
257
258 //type(型)名とスクリプト名は同じ
259 data_list.Add (name+"/"+script_name[i].GetType().FullName+".js");
260
261 seiki = read_SO (MonoScript.FromMonoBehaviour (script_name[i]));
262
263 foreach(string s in seiki){
264 data_list.Add (name+"/"+script_name[i].GetType().FullName+".js/"+s);
265 }
266
267 }
52
268 }
269 }
270
271 //オブジェクト/スクリプト名が被った時に名前を一時的に付け直す
272 public string same_word(string add_word,string how){
273 string p=add_word;
274 string check_add=add_word;
275 int i=0;
276 int discovery = 1;
277
278 while(discovery>0){
279 discovery=check_add.LastIndexOf(how+"/"); //逆からこの文字を検索
280 string name = check_add.Substring (discovery + 1); //ある文字以降を取り出す
281 Debug.Log(check_add+"\tdi_how>"+discovery);
282 if(discovery>-1){
283 i++; //必ず1回は行うので i は 1 になる
284 }
285 check_add=name;
286 }
287
288 if (i > 0) {
289 Debug.Log (add_word + ".over" + i);
290 p = add_word + ".over" + i;
291 }
292
293 return p;
294 }
295 }
• node_confug.cs(行数は 95 行)
1 using UnityEngine;
2 using UnityEditor;
3 using System.Collections;
4 using System.Collections.Generic; //List 用
5 using System.Text.RegularExpressions;
6 using System.IO; //外部データ読み書き
53
7 using System; //エラー用
8
9 public class node_config{
10 public string color;
11
12 public string select_name;
13 public Transform select_object;
14
15 public node_config(string select_name,Transform select_object){
16 this.select_name = select_name;
17 this.select_object = select_object;
18 }
19
20 public string Sorting(string data_s){
21 int discovery=data_s.LastIndexOf("/"); //逆からこの文字を検索
22 string name = data_s.Substring (discovery + 1); //ある文字以降を取り出す
23
24 return name;
25 }
26
27 public string over_name(string name){
28 int dis_over=name.LastIndexOf(".over");
29 if(dis_over>-1){
30 name = name.Substring (0,dis_over);
31 }
32
33 Debug.Log (">>>"+name);
34 return name;
35
36 }
37
38 public int line_get(string data_s,ref List<string> all_data){
39 int discovery=data_s.LastIndexOf("/"); //逆からこの文字を検索
40
41 string mae = null;
42 int mae_id=-1;
54
43
44 if(discovery>-1){
45 mae=data_s.Substring (0,discovery); //ある文字までを取り出す
46 }
47
48 for(int i=0;i<all_data.Count;i++){
49 if(all_data[i]==mae){
50 mae_id = i;
51 }
52 }
53
54 return mae_id;
55 }
56
57
58 public string decision_color(string node_s,string fullname,ref string node_title){
59 int full_discovery=fullname.LastIndexOf(".js");
60 int discovery=node_s.LastIndexOf(".js");
61
62 Debug.Log ("<color=green>" + node_s + "\t" + fullname +"\t"+select_name +"</color>");
63
64 node_title = "test";
65
66 if (full_discovery > -1) {
67 if (discovery > -1) {
68 color = "flow node 6";
69 node_title = "Script";
70
71 } else {
72 color = "flow node 3";
73 node_title = "変数";
74 }
75 } else {
76 color = "flow node 1";
77 node_title = "Object";
78 }
55
79
80 Debug.Log ("<color=red>"+node_s+"\t"+select_name+"</color>");
81 node_s = over_name (node_s);
82
83 Debug.Log ("<color=red>"+node_s+"\t"+select_name+"</color>");
84
85 if(node_s==select_name || node_s==select_name+".js"){
86 color="flow node 4";
87 node_title = "select";
88 }
89
90 Debug.Log (node_s+"\t"+node_title+"\t"+color);
91 return color;
92
93 }
94
95 }