月別アーカイブ: 2013年2月

[Unity][XML][C#]テキストデータを外部ファイル化するサンプル

[wp_ad_camp_1]

Unityのプロジェクトで日本語をコード内に記述してる事案があって、これを解消した時の構造をメモ。

gist::ogkslownin

TxtLib.cs

staticで定義したテキストデータをKeyValue形式で保持したライブラリを複数所持するクラス。
プロパティは次に説明するXMLPlistContainerクラスで定義される。

使い方はライブラリの種類と取得したい文字列と対になっているkeyを渡すことで文字列データを取得する。

XMLPlistContainer.cs

クラス生成時にファイルを読み込む。
Editor上でのみ、ファイルのタイムスタンプを参照して使用時に読み直しをする。
文字列を取得する際にはインデクサを用意して、key文字列を渡すことで得られる仕組み。

fruit_default.xml

ここのファイルにkeyと対になる文字列を定義しておく。
ファイルは同名にして各国分用意する。

サンプルではアプリケーションサーバを各国で分ける前提での設計なのだけれど、各国のファイルを平行して保持したいのであれば、XMLのファイル名を国別に用意し、XMLPlistCOntainer内での読み込み時の”_default_”を、引数として受けた国名文字列と差し替える記述をすれば対応可能になる。
C#で学ぶ偏微分方程式の数値解法

[Unity3D][UnityEditor]ScriptableWizardが思ったよりも使えなかった話

[wp_ad_camp_1]

ScriptableWizardとは

ScriptableWizardは、一つのスクリプトをベースにオブジェクトを生成したい時等に利用するエディタ。EditorWindowを継承しているのでEditorWindowで出来る事は全部できるけども、独自に予めUIが用意されているのでOnGUIを仕込んではいけない。

主な用途は何か?

正直、何に使えるのか良くわからない。パラメータ違いのプレファブを大量生産するのに向いてるかと言えば、createボタンでウィンドウがきえてしまうしイマイチ不明。

もしあるとしたら、メインのEditorWindowのサブウィンドウとして出現させる等の用法。
EditorWindow内の特定のボタンをクリックしたら出現し、Wizard内の特定パラメータを変動させた上でCreateをしたら値を取得させる関数をEditorWindow側に命令するとか。
だとしてもOnGUIが使えないのでどうせならサブウィンドウもEditorWindowで生成し、各種ボタンを用意した方が用途が広い。

ただ、エラーを出したり、ヘルプを出したりできるので、特定の値を厳密に入力させたり、文字列による曖昧な入力が必要な場合等は効果的なのかもしれない。
Unityで作るスマートフォン3Dゲーム開発講座 Unity4対応

サンプル

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;

public class TestWizard : ScriptableWizard {

 public string gstring;
 public int gint;
 private string pstring;
 private int pint;


 [UnityEditor.MenuItem("Custom/OHGAKI/TestWizard")]
 static void WillAppear()
 {
  ScriptableWizard.DisplayWizard("Test Wizard Title in DisplayWizard method.",typeof(TestWizard),"createButtonName","otherButtonName");
 }

 void OnWizardCreate()
 {
  GameObject newGameObj = new GameObject("new GameObj");
  newGameObj.AddComponent("SphereCollider");
  newGameObj.AddComponent("MeshFilter");
        newGameObj.AddComponent("MeshRenderer");
 }

 void OnWizardOtherButton()
 {
  Debug.Log("otherButtonName clicked");
 }

 void OnWizardUpdate()
 {
  helpString = "type "abc" in gstring.";
  if(gstring == "abc"){
   isValid = true;
   errorString = "";
  }else{
   isValid = false;
   errorString = "gstring is not "abc".";
  }
  
  position = new Rect(200f,200f,300f,300f);
 }
}

サンプルの解説

 [UnityEditor.MenuItem("Custom/OHGAKI/TestWizard")]

でメニュー項目を作成し、その際の起動ハンドラを次の行に記述してるのはメニュー起動系の通例通り。

起動時のスクリプトも通例通りStaticの関数として宣言。

関数内で実行しているのは

ScriptableWizard.DisplayWizard()

で、引数が3つある場合は一つ目がタイトル、二つ目がメインのボタン、三つ目がその他のボタンの文字列としてウィンドウが生成される。

この関数は引数の数や種類に応じて色々とやってることが変化するので、リファレンスを参照。

http://ws.cis.sojo-u.ac.jp/~izumi/Unity_Documentation_jp/Documentation/ScriptReference/ScriptableWizard.html

  • OnWizardCreate()はボタン押された時に駆動するイベント。
  • OnWizardOtherButton()はotherButtonを出現させていた場合の生成されるボタンが押された際に呼び出されるイベント。
  • helpStringは常時表示用の文字列を格納する。
  • errorStringはエラーっぽい表示させたい文字列を格納する。中身が空だとエラーマークは出て来ない。
  • OnWizardUpdate()は項目の内容が変更すると駆動する。

ScriptableWizard

また、サンプルでは特定の文字が入った場合にerrorString等をアップデートしたり、ボタンをisValidをtrueにすることで有効にしてる。
isValidはfalseにしておくとボタンが押せないグレーアウト状態にさせることができる。

今日はここまで。

[Unity3D][UnityEditor]EditorWindowの最小構成からボタン配置やらサブウィンドウの生成やら

[wp_ad_camp_1]

最小構成

ファイルをProjectのRootにEditorフォルダを作成し、その中に各種エディター的機能を使用するクラスを格納させておく必要がある。
(Asset/Editor/)
EditorはUnityEditorライブラリを使用し、ウィンドウを表示するのであればEditorWindowを継承させておく。
下のコードが最小構成。画面上部にメニュー項目が追加される。
それをクリックするとデバッグログに文字列を表示する。

using UnityEngine;
using UnityEditor;
using System.Collections;

public class _OGKEditor : EditorWindow {

 [UnityEditor.MenuItem("Custom/OHGAKI/EdtiorTest")]
 static void abcde(){
  Debug.Log("init"); 
 }

}

メニュー項目への表示は[]で囲われた範囲で、ディレクトリ階層を指定できる。
その次の行にあたるstatic関数が呼ばれる。この時の関数名は何でもいい。

Windowの出現

コードを次の様に書き換える。
変更した場所はDebag.Logから自身のクラスの型でEditorWindowによるGetWindowクラスで生成したwindowをキャストする。

public class _OGKEditor : EditorWindow {

 [UnityEditor.MenuItem("Custom/OHGAKI/EdtiorTest")]
 static void abcde(){
  _OGKEditor window = (_OGKEditor)EditorWindow.GetWindow (typeof (_OGKEditor));
 }

 void OnGUI(){
  if(GUILayout.Button("button")){
   //ボタン押した時の動作を記述
  }
 }
}

次の関数がウィンドウ生成している。サンプルは格納後に即座に開放して参照を切っているが、生成はちゃんとなされているのでOnGUI()で指定した動作は行われる。
EditorWindow.GetWindow( typeof() );
このウィンドウだけでウィンドウそのものを生成することはできるけど、各種初期設定をすることになるので、自身の型で参照を保ったまま、各種プロパティを変更しておく方が望ましい。

EditorWindowオブジェクトのプロパティやメソッドは次に一覧されている。
http://docs.unity3d.com/Documentation/ScriptReference/EditorWindow.html

プロパティ一覧

  • wantsMouseMove
    • BOOL
    • マウスイベントを取得するか否かを指定。
  • autoRepaintOnSceneChange
  • minSize
    • Vector2
    • ウィンドウの最小サイズ
  • maxSize
    • Vector2
    • ウィンドウの最大サイズ
  • title
    • string
    • ウィンドウのタブ上に表示される文字列
  • position
    • Rect
    • ウィンドウの初期位置と初期サイズ

試しに追加した初期値

 static void abcde(){
  _OGKEditor window = EditorWindow.GetWindow (typeof (_OGKEditor));
  window.minSize = new Vector2(300f,300f);
  GUIContent content = new GUIContent("__abcde__");
  window.ShowNotification(content);
  window.title = "org editor";
  window.position = new Rect(300f,300f,300f,300f);
 }

Window生成直後にNoticeを表示

初期化関数であるabcd()を次の様に追加してみる。

 static void abcde(){
  _OGKEditor window = EditorWindow.GetWindow (typeof (_OGKEditor));
  window.minSize = new Vector2(300,200);
  GUIContent content = new GUIContent("__abcde__");
  window.ShowNotification(content);
 }

すると、ウィンドウ生成直後に適当なサイズで文字列を表示できる。

UnityEditorWindowWithNotice

この文字列は数秒で消えるので注意喚起とか、複数のウィンドウを開いたり閉じたりさせる場合に現在のプレファブ名だとかを表示されることで、意識的に編集できるようになり、ヒューマンエラーを防止できる。
開いた時でなくても、windowに参照さえあれば次の様に記述してイベント事に確認したいことを表示することができる。

  GUIContent content = new GUIContent("Do not take my potato!");
  window.ShowNotification(content);

表示できるのはイベントが発生したときや独自の通知を受けた時。

EditorWindowクラス側が用意しているイベントは次の通り。

  • OnGUI Implement your own editor GUI here.
    • 描画されたときに走る。
    • ウィンドウ内のレイアウトを切ったりするのもここ。
  • Update Called 100 times per second on all visible windows.
    • 表示中のウィンドウは漏れなく秒間100回呼び出される。
  • OnInspectorUpdate OnInspectorUpdate is called at 10 frames per second to give the inspector a chance to update
    • 秒間10回の頻度で更新されるインスペクタ上のUpdate関数。
  • OnDestroy OnDestroy is called when the EditorWindow is closed.
    • windowを閉じた時に呼ばれる。
  • OnSelectionChange Called whenever the selection has changed.
    • SceneやHierarchy内でクリックする等して選択が変更される度に呼ばれる。
    • ウィンドウとは無関係で呼ばれる。
    • Selectionクラスから色々取得できる。
  • OnFocus Called when the window gets keyboard focus.
  • OnLostFocus Called when the window loses keyboard focus.
    • アクティブになるとOnFocusが、非アクティブになるとOnLostFocusが呼ばれます。
  • OnHierarchyChange Called whenever the scene hierarchy has changed.
    • ヒエラルキーが変わったら呼ばれる。ヒエラルキーの変動で読み直しすべきデータがあるのであれば読み直しを記述する。
  • OnProjectChange Called whenever the project has changed.
    • プロジェクトが変わったら呼ばれる。
    • データを読み込んで何かを表示しているのであれば、ここに読み直しの処理等を記述する。

OnSelectionChangeのサンプル

次のコードで選択しているオブジェクトのIDをずらっと表示できる。
オブジェクトを選択する都度呼ばれる。

 void OnSelectionChange(){
  foreach(int a in Selection.instanceIDs ){
   Debug.Log("id = "+ a); 
  }
 }

http://docs.unity3d.com/Documentation/ScriptReference/EditorWindow.OnSelectionChange.html

ウィンドウからさらにウィンドウを出現させる

サブウィンドウ用にクラス内クラスを用意。

 public class SubWindow: EditorWindow
 {
  public static SubWindow WillAppear(){
   
   SubWindow window = (SubWindow)EditorWindow.GetWindow(typeof(SubWindow));
   window.minSize = new Vector2(50f,100f);
   window.title = "SubWindow";
   return window;
  }
  void OnGUI(){
   GUILayout.Label("SubWindow Here"); 
  }
 }

で、親ウィンドウ側にはボタンから呼び出す様に次ぎのように記述を変更、追加する。

 void OnGUI(){
  if(GUILayout.Button("button"+num)){
   ButtonPushed();
  }
 }
 void ButtonPushed(){
  ++num;
  subWindow = SubWindow.WillAppear();
 }

SubWindowクラスに定義したWillAppearを呼び出す。
呼び出されたサブクラス側はサイズやらタイトルが差し替えられて以下のように出現する。

!!

うごごご。動かない。
エラー内容は次のとおり。

Instance of SubWindow couldn’t be created because there is no script with that name.

SubWindowのインスタンスは作られませんでしたよ。なぜならその名前でかかれたスクリプトなんざねーからだ!

サブウィンドウは別ファイルで定義

先に記述したクラス内クラスを独立したクラスとして定義しなおす。
次の様に適当なEditorWindow継承クラスを定義して、Editorディレクトリ下に入れておく。

using UnityEngine;
using UnityEditor;
using System.Collections;

public class SubWindow: EditorWindow
{
 public static SubWindow WillAppear(){
  
  SubWindow window = (SubWindow)EditorWindow.GetWindow(typeof(SubWindow));
  window.minSize = new Vector2(50f,100f);
  window.title = "SubWindow";
  return window;
 }
 void OnGUI(){
  GUILayout.Label("SubWindow Here"); 
 }
}

UnityEditorWindowWithSubWindow

と、今日はここまで。

ゲームの作り方  Unityで覚える遊びのアルゴリズム

おまけ

自身を無限に生成しつづけるブラクラみたいのつくれないかな?と思ったのだけれどEditorWindowクラスは代々シングルトンみたいです。
以下のサンプルはボタン付きウィンドウを表示してボタンが押されると自身を生成するもの。
生成されたとたん、もともとあったウィンドウは削除される。
解りやすくする為に生成される都度、位置を変更している。

using UnityEngine;
using UnityEditor;
using System.Collections;

public class _BrowserCrasher : EditorWindow {

 public _BrowserCrasher parent;

 [UnityEditor.MenuItem("Custom/OHGAKI/bracra")]
 public static void init()
 {
  _BrowserCrasher window = initWithPosition(new Vector2(100f,100f));
  window.Show();
 }

 public static _BrowserCrasher initWithPosition(Vector2 pos)
 {
  _BrowserCrasher window = EditorWindow.GetWindow(typeof(_BrowserCrasher));
  window.position = new Rect( pos.x+10f,pos.y+10f,100f,100f);
  return window;
 }

 void OnGUI()
 {
  if(GUILayout.Button("button"))
  {
   _BrowserCrasher window = initWithPosition(new Vector2( this.position.x ,this.position.y));
   window.parent = this;
   
  }
 }
}

サンプル全容

メインウィンドウ

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;

public class _OGKEditor : EditorWindow {
	
	private int num = 0;
	private SubWindow subWindow;
	
	[UnityEditor.MenuItem("Custom/OHGAKI/EdtiorTest")]
	static void abcde(){
		_OGKEditor window = EditorWindow.GetWindow (typeof(_OGKEditor));
		window.minSize = new Vector2(300f,300f);
		window.title = "org editor";
		window.position = new Rect(300f,300f,300f,300f);
		GUIContent content = new GUIContent("__abcde__");
		window.ShowNotification(content);
	}
	
	void OnGUI(){
		if(GUILayout.Button("button"+num)){
			ButtonPushed();
		}
	}
	void ButtonPushed(){
		++num;
		subWindow = SubWindow.WillAppear();
	}
	
	
	//On!!
//	void OnSelectionChange(){
//		foreach(int a in Selection.instanceIDs ){
//			Debug.Log("id = "+ a);	
//		}
//	}
//	
//	void OnFocus(){
//		Debug.Log("OnFocus");
//	}
//	void OnLostFocus(){
//		Debug.Log("OnLostFocus");
//	}
	
	
}

サブウィンドウ

using UnityEngine;
using UnityEditor;
using System.Collections;

public class SubWindow: EditorWindow
{
	public static SubWindow WillAppear(){
		
		SubWindow window = (SubWindow)EditorWindow.GetWindow(typeof(SubWindow));
		window.minSize = new Vector2(50f,100f);
		window.title = "SubWindow";
		return window;
	}
	void OnGUI(){
		GUILayout.Label("SubWindow Here");	
	}
}

Mountain Lion + Redmine

[wp_ad_camp_1]

Mac OSX Mountain Lion にインストーラからインストールするだけで動作ができた。
該当マシンにはJenkinsが入っているのでポートを8081にする程度の変更は加えたもののDB等も含めたインストールが完了した。

ローカルエリア内からipを直接打ち込むことで別マシンからでもアクセスできるので、遠隔地のスタッフと共同等でないかぎりはこの環境でも十分やれそうだ。

しかし、Redmineからメールが送れなかったりSubversionとの連携が上手く行ってないので調べようと思ったら、Logを吐く設定をしていないことが発覚したので通常運行にはまだまだ事足らない。

Redmineのインストーラ
http://redmine.jp/download/
ここのAll-in-one

MacのApacheを機能させる
http://d.hatena.ne.jp/sakura_bird1/20120804/1344055999
http://d.aoikujira.com/blog/index.php?Mac%E3%81%AEMountain%20Lion%E3%81%A7Apache%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B

ログの場所
http://d.hatena.ne.jp/shigemk2/20120824/1345795386
ここを見なくてもConsoleを立ち上げればApache2の項目からLogを参照できる。

サーバ構築の実際がわかる Apache[実践]運用/管理 (Software Design plus)
鶴長 鎮一
技術評論社
売り上げランキング: 38,992