git commit の editor もSublime Textにしようとしたもののすんなり行かなかったのでメモ。
すんなり行かなかった理由は rbenv
を入れていたから。
subl をインストール
Ruby Envのディレクトリを~/.rbenv/
と命名していたのでここの下にbinをディレクトリを作成する。
続いて次のコマンドを入力することでSublime Text
のコマンドラインツールであるsublが入る。
git commit の editor もSublime Textにしようとしたもののすんなり行かなかったのでメモ。
すんなり行かなかった理由は rbenv
を入れていたから。
Ruby Envのディレクトリを~/.rbenv/
と命名していたのでここの下にbinをディレクトリを作成する。
続いて次のコマンドを入力することでSublime Text
のコマンドラインツールであるsublが入る。
Uniswfを使用しているとプログラム上で動的にMovieClipを生成したくなることがある。
これでちょっと複雑な構造にするだけで意図した動作がなされないことが良くある。
次のコードで例を示す。
public Vector2 v2Out; MovieClip linkage; List<MovieClip> c = new List<MovieClip>(); private void Test(){ var stage = MovieClipOverlayCameraBehaviour.instance.stage; var a = new MovieClip(); var im = new MovieClip(); a.addChild(im); var textureA = Resources.Load("images/iconA") as Texture2D; var textureB = Resources.Load("images/iconB") as Texture2D; a.graphics.drawRectUV( texture, new Rect(0, 0, 1, 1), new Rect(0, 0, textureA.width, textureA.height) ); im.graphics.drawRectUV( // この描画は失われる。 texture, new Rect(0, 0, 2, 2), new Rect(0, 0, textureB.width, textureB.height) ); this.linkage.addChild( a ); c.Add(a); a.x = cor.v2Out.x; a.y = cor.v2Out.y; MovieClipOverlayCameraBehaviour.instance.stage.addChild(this.linkage); } private void TestMcStructOut(){ var stage = MovieClipOverlayCameraBehaviour.instance.stage; Debug.Log( "ListCount : " + this.c.Count + " : linkage has :" + this.linkage.numChildren + " : stage has :" + stage.numChildren + " : a's child : " + (this.linkage.getChildAt(0) as MovieClipUtil).numChildren ); } void Update(){ if(c.Count < 1) Test(); else{ //c.ForEach( d => this.linkage.addChild( d ) ); //c.ForEach( d => d.visible = true ); c[0].x = v2Out.x; c[0].y = v2Out.y; } TestMcStructOut(); }
‘Vector2’ 型のメンバ v2Out
は描画させたい MovieClip の位置を変更させるためのものとして用意。
Unityを再生中でもMovieClipをぐりぐり動かせる。
Test関数内部で作成しているMovieClipの構造を改めて示すと、
stage -> linkage -> a -> im
これを実行すると最初のフレームだけ textureA, B の両方が描画され、次のフレームでは im に描画した textureB は消滅している。
状況を整理すると
– linkage はメンバなので次のフレームでは削除される
– a はメンバではないけれども list c で参照を保持している。
– im はメンバでもないし参照を保持していない。
– 消えているのはimだけでaに描画したテクスチャは表示され続けている。
im は Test() の中で創られているので関数終了後はUnity上では参照を失っている。
なので自動でガベコレ的なものがuniSWF内で動作しているのであれば参照を保持しておけば大丈夫なはずだと考え、メンバに MovieClip 型の tmpim を追加した。
しかし結果は描画されず。
メンバ変数に格納すると参照をすぐに見いだせる。当たり前だけど参照そのもは破棄はされていないことが確認できた。
if(tmpim != null) Debug.Log("alright!"); // ここを通る事は無い。
前項で調べた通り、参照先は失われていなかったので描画対象ではなくなったのではと考え、子の数を調べる関数でチェックを行った。
private void TestMcStructOut(){ var stage = MovieClipOverlayCameraBehaviour.instance.stage; Debug.Log( "ListCount : " + this.c.Count + " : linkage has :" + this.linkage.numChildren + " : stage has :" + stage.numChildren ); }
ここに記述されている ‘numChildren’ が子の数を保持しているプロパティ。
これを回すと最初の ‘Test()’ では linkage.numChildren が 1 だけど次のフレームで記述されたログには 0 になっている。
ここで外れてしまう親子関係だけどうにかするのも手としてはありなのだけどもう一歩踏み込んでみた。
親子関係は破壊されるけれども参照先として’MovieClip’が保持される事が分かったのでこれをもうちょっと掘り進めたら以下のようになる実装になっているということが分かった。
その場で ‘new’ した ‘MovieClip’ に ‘addChild’ した孫 ‘MovieClip’ は次のフレームでは親子関係が破棄されている。
List形式とかで生成したやつは全部格納しておき、そこからアクセスするとか。
けっこう色んなパターンを調べてやっとこの結論に至ったのだけれども間違いがあったらご指摘いただきたい。
演出だけは突出した真価を発揮する。uniSWFをコレからも宜しくお願いします。間違ってもUI全部にuniSWFを使っては行けない!マジで!(涙目)
[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関数が呼ばれる。この時の関数名は何でもいい。
コードを次の様に書き換える。
変更した場所は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
試しに追加した初期値
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); }
初期化関数であるabcd()を次の様に追加してみる。
static void abcde(){ _OGKEditor window = EditorWindow.GetWindow (typeof (_OGKEditor)); window.minSize = new Vector2(300,200); GUIContent content = new GUIContent("__abcde__"); window.ShowNotification(content); }
すると、ウィンドウ生成直後に適当なサイズで文字列を表示できる。
この文字列は数秒で消えるので注意喚起とか、複数のウィンドウを開いたり閉じたりさせる場合に現在のプレファブ名だとかを表示されることで、意識的に編集できるようになり、ヒューマンエラーを防止できる。
開いた時でなくても、windowに参照さえあれば次の様に記述してイベント事に確認したいことを表示することができる。
GUIContent content = new GUIContent("Do not take my potato!"); window.ShowNotification(content);
表示できるのはイベントが発生したときや独自の通知を受けた時。
EditorWindowクラス側が用意しているイベントは次の通り。
次のコードで選択しているオブジェクトの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"); } }
と、今日はここまで。
自身を無限に生成しつづけるブラクラみたいのつくれないかな?と思ったのだけれど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"); } }
何を血迷ったかこんなエラーを発生させていた。
NSLogの引数にNSStringのメッセージ文を直接書いていたらなぜかワーニング“Format string is not a string literal”が出て気持ち悪いので調べてみたらあっさり。
NSLog([NSString stringWithFormat:@"Milk"]);
これだとWarningがでます。
グーグル先生に訪ねたらこんな回答が。
http://stackoverflow.com/questions/5428325/issue-with-code-format-string-is-not-a-string-literal
NSLog(@"%@",[NSString stringWithFormat:@"%@", entered]);
教えてくれた人曰く、セキュリティを破る事に成りかねないYOとの事。
内容があまりにも簡単過ぎるからだとは思うのだけど、日本後でこういったエラーメッセージに対応してる記事をあまりみない。英語力が解決力に通じてると実感。