タグ別アーカイブ: error

sublime text X git

Sublime Text を git commit のエディタにする

git commit の editor もSublime Textにしようとしたもののすんなり行かなかったのでメモ。

すんなり行かなかった理由は rbenv を入れていたから。

subl をインストール

Ruby Envのディレクトリを~/.rbenv/と命名していたのでここの下にbinをディレクトリを作成する。

続いて次のコマンドを入力することでSublime Textのコマンドラインツールであるsublが入る。

続きを読む

[Unity][uniSWF]newしたMovieClipが突然なくなってしまう現象でハマった話

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に描画したテクスチャは表示され続けている。

推察1 MovieClip im がメンバじゃないから失われている

im は Test() の中で創られているので関数終了後はUnity上では参照を失っている。
なので自動でガベコレ的なものがuniSWF内で動作しているのであれば参照を保持しておけば大丈夫なはずだと考え、メンバに MovieClip 型の tmpim を追加した。

しかし結果は描画されず。

メンバ変数に格納すると参照をすぐに見いだせる。当たり前だけど参照そのもは破棄はされていないことが確認できた。

    if(tmpim != null) Debug.Log("alright!"); // ここを通る事は無い。

推察2 親子関係だけ外れてしまったのでは?

前項で調べた通り、参照先は失われていなかったので描画対象ではなくなったのではと考え、子の数を調べる関数でチェックを行った。

    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’が保持される事が分かったのでこれをもうちょっと掘り進めたら以下のようになる実装になっているということが分かった。

uniSWF_couldnotStoreMovieClip by Kunihiro OHGAKI, on Flickr

その場で ‘new’ した ‘MovieClip’ に ‘addChild’ した孫 ‘MovieClip’ は次のフレームでは親子関係が破棄されている。

まとめ

  • MovieClip をその場で生成する場合はメンバに格納すべき。
  • メンバに格納済の MovieClip でも、さらにその子の MovieClip に描画した場合は親子関係が破棄される。
  • その場で ‘new’ した MovieClip に直接 graphics を記述した場合は問題なく保持される。

対策

List形式とかで生成したやつは全部格納しておき、そこからアクセスするとか。

けっこう色んなパターンを調べてやっとこの結論に至ったのだけれども間違いがあったらご指摘いただきたい。

Unityによる2Dゲーム開発入門 ~プログラミング初心者がゲームを公開する最短コース

おまけ

uniSWFの問題点

  • uniSWFはswf化してからunityに取り込むので何かするにもFlaファイルを開かなければならないのでアプリケーション常に2つ立ち上げっぱなし。
  • さらにflaの素材編集となるとphotoshopも立ち上げなければならない。
  • さらにphotoshopのデータで曲線使ってたりするとillustratorも…
  • ちょっとしたレイアウト調整がGameObjectのInspectorでできない。やれるけど標準的ではない。
  • ソフトウェアレンダリングなので最初の1フレームはデバイスの画面によって拡大縮小された表示が見える。
  • 描画コストが高い。ドローコール減らせない。
  • unityのアップグレードにどこまでついて来れるのやら心配。
  • ドキュメントが完成してない。実は実装済みでドキュメントに記載が無いって事も多々ある。
  • swf作成のお約束が多い。
  • フォントが不自由。
  • フォントサイズも不自由。

uniSWFの使いどころ

  • アニメーション作業がしやすいのでガチャみたいな画面全域で表示しつつ演出過剰にしたい場所では作業を完全に切り分けられるのでオススメ。
  • monoDevelopでソースが見れるのでswfがどういう構造になってるのか勉強になるかも。

演出だけは突出した真価を発揮する。uniSWFをコレからも宜しくお願いします。間違ってもUI全部にuniSWFを使っては行けない!マジで!(涙目)

[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");	
	}
}

Format string is not a string literal

警告!な写真
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との事。

内容があまりにも簡単過ぎるからだとは思うのだけど、日本後でこういったエラーメッセージに対応してる記事をあまりみない。英語力が解決力に通じてると実感。