かつて代官山らへんで働いてたengineerのUnityブログ

サーバサイドやってきたエンジニアがUnityとか触って遊ぶだけのブログ

【Unity】Quaternionをヨー、ピッチ、ロールに変換する【ジャイロ】

ジャイロで受け取ったQuaternionからヨー、ピッチ、ロールへの変換式です
Unityに限らず意外と使うところあると思うんですけど、あんまりネット探しても載ってないんですよね
毎度計算式忘れるので自分への備忘録の意味も込めて

void Start () {
    //ジャイロフラグをオン
    if (SystemInfo.supportsGyroscope) {
         Input.gyro.enabled = true;
    }
}

void Update () {
    Quaternion gyro = Input.gyro.attitude;
    float yaw   =  Mathf.Atan2(2 * gyro.x * gyro.y + 2 * gyro.w * gyro.z, gyro.w * gyro.w + gyro.x * gyro.x - gyro.y * gyro.y - gyro.z * gyro.z);
    float pitch = Mathf.Asin (2 * gyro.w * gyro.y - 2 * gyro.x * gyro.z);
    float roll = Mathf.Atan2 (2 * gyro.y * gyro.z + 2 * gyro.w * gyro.x, -gyro.w * gyro.w + gyro.x * gyro.x + gyro.y * gyro.y - gyro.z * gyro.z);
}


Unityの回転は鬼門だと思う

【Unity】Scene内のComponentから文字列を検索する【エディタ拡張】

だいぶ前回更新から期間が空いてしまった...
というのも、エディタ拡張を作っていました。

Scene内のオブジェクト全て(無効含む)に関連付けられたComponentから文字列を検索するエディタ拡張
題して『SceneScriptFinder』!!ヒュー!英語が怪しいぜ!
まだ改良したいところは山ほどあるのですが、とりあえず形にはなりました。

f:id:chroske:20150715220043p:plain
検索結果を階層構造で表示してなおかつ行数も教えてくれます。
ほんとはエディタの指定行に直接飛べたらよかったんだけどね。

※2015/07/16
一応パッケージ化しました。下記リンクからどうぞ
SceneScriptFinder


以下コードです
良ければコピって使ってやってくださいまし

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

public class SceneScriptFinder : EditorWindow
{
	// 変数
	private string searchText = string.Empty;

	private List<List<List<Dictionary<string,string>>>> objList = null;

	private List<bool> foldOutFlagList = new List<bool>();
	private List<bool> foldOutFlagList2 = new List<bool>();

	private Vector2 scrollPosition = Vector2.zero;

	private static bool IsRegex = true;
	

	// method
	[MenuItem("Window/SceneScriptFinder")]
	static void Open()
	{
		EditorWindow.GetWindow<SceneScriptFinder>( "SceneScriptFinder" );
	}
	

	
	void OnGUI()
	{
		GUILayout.Label( "SearchText" );
		searchText = GUILayout.TextArea( searchText );

		IsRegex = EditorGUILayout.Toggle( "大文字小文字チェック", IsRegex );


		if( GUILayout.Button("Scan") )
			Find();

		scrollPosition = GUILayout.BeginScrollView(scrollPosition);

		DrawResults(); // 結果一覧
		
		GUILayout.EndScrollView();	// スクロールバー終了
		
	}

	/* 文字列検索 */
	private void Find (){
		if(searchText != "" && searchText != null){
			objList = new List<List<List<Dictionary<string,string>>>>();
			
			//foldOutFlag format
			foldOutFlagList = new List<bool>();
			foldOutFlagList2 = new List<bool>();
			
			foreach (GameObject obj in UnityEngine.Resources.FindObjectsOfTypeAll(typeof(GameObject)))
			{
				// シーン上に存在するオブジェクトならば処理
				if(obj.activeInHierarchy){
					// アセットからパスを取得.シーン上に存在するオブジェクトの場合,シーンファイル(.unity)のパスを取得.
					string path = AssetDatabase.GetAssetOrScenePath(obj);
					// シーン上に存在するオブジェクトかどうか文字列で判定.
					bool isScene = path.Contains(".unity");
					// シーン上に存在するオブジェクトならば処理.
					if (isScene)
					{
						List<List<Dictionary<string,string>>> componentList = new List<List<Dictionary<string,string>>> ();
						
						// コンポーネント一覧を配列で取得
						var components = obj.GetComponents<MonoBehaviour> ();
						if (components != null) {
							foreach(var componentData in components){
								if(componentData != null){
									
									// コンポーネントのテキストを取得
									var monoscript = MonoScript.FromMonoBehaviour (componentData);
									List<Dictionary<string,string>> lines = new List<Dictionary<string,string>> ();
									
									// 行数カウント用
									int lineCounter = 0;
									
									foreach (var line in monoscript.text.Split( new string[]{ Environment.NewLine }, StringSplitOptions.None )) {
										
										Dictionary<string,string> lineParams = new Dictionary<string,string> ();
										
										lineCounter++;
										if (!Match (line, searchText))
											continue;
										
										// コンポーネント名
										lineParams.Add ("compornent",componentData.GetType().ToString());
										
										// オブジェクト名
										lineParams.Add ("objectName",componentData.gameObject.ToString());
										
										// 何行目か
										lineParams.Add ("lineNum",lineCounter.ToString());
										
										// ヒットした行の文字列
										lineParams.Add ("line",line);
										
										lines.Add (lineParams);
									}
									if(lines.Count != 0)
										componentList.Add (lines);
								}
							}
						}
						
						objList.Add(componentList);
					}
				}
			}
		}

	}
	

	/* 文字列がマッチしたらtrueを返す */
	public static bool Match(string input, string search)
	{
		if (string.IsNullOrEmpty (input))
			return false;
		
		if (!IsRegex) {
			var match = Regex.Match (input, search, RegexOptions.IgnoreCase);
			return match.Success;
		} else {
			var result = input.IndexOf (search);
			return (result != 0 && result != -1);
		}
	}

	/* 結果一覧を描画 */
	private void DrawResults()
	{
		int i = 0;
		int j = 0;
		if (objList != null) {
			foreach(List<List<Dictionary<string,string>>> componentList in objList){
				if(componentList.Count != 0 && componentList[0].Count != 0){

					// インデント初期化
					EditorGUI.indentLevel = 0;

					// オブジェクト名Foldout
					foldOutFlagList.Add(false);
					foldOutFlagList[i] = EditorGUILayout.Foldout( foldOutFlagList[i],componentList[0][0]["objectName"]);

					if (foldOutFlagList[i]){

						foreach(List<Dictionary<string,string>> lines in componentList){
							foreach(Dictionary<string,string> lineParams in lines){
								// インデント追加
								EditorGUI.indentLevel = 1;

								// コンポーネント名+行数
								foldOutFlagList2.Add(false);
								foldOutFlagList2[j] =  EditorGUILayout.Foldout(foldOutFlagList2[j],  "    ↳" + lineParams["compornent"] + "    " + lineParams["lineNum"] );

								if (foldOutFlagList2[j]){
									// インデント追加
									EditorGUI.indentLevel = 2;

									// ヒットした行の文字列
									EditorGUILayout.SelectableLabel(lineParams["line"]);
								}
								j++;
							}
						}
					}
					i++;
				}
			}
		}
	}
}

負荷テストなんてやってないので超大規模プロジェクトとかでやったらどうなるかわかりません。
でも最悪Unityが死ぬだけだ。なんとかなる。

【Unity】文字列をファイルに書き出す【Log出力】

ログを出力したい時などに使えるかと
思ったより簡単でした

using System.IO;

// 引数でStringを渡してやる
public void textSave(string txt){
	StreamWriter sw = new StreamWriter("../LogData.txt",false); //true=追記 false=上書き
	sw.WriteLine(txt);
	sw.Flush();
	sw.Close();
}


出力先のログフォルダなどを予め作っておくとよいかと思います
もちろんエディタ拡張でも同様に使えます

【Unity】ボタンを押下させる間隔を制限する【連打防止】

ボタン押下時にデータをリストで取得するなどの重めの通信を走らせてたりすると、連打制限したいなって時ありますよね 絶対連打する人いるし....
最低限で簡単な実装ですが、今後も使いまわせそうなので載せておきます
アレンジして使っていきましょう

// ボタン押下許可フラグ
private bool isPushReloadButton = false;

// ボタンが押されてから次にまた押せるまでの時間(秒)
private TimeSpan allowTime = new TimeSpan(0, 0, 3);

// 前回ボタンが押された時点と現在時間との差分を格納
private TimeSpan pastTime;




void Update ()
{
	// 3秒後にボタン押下を許可
	if (isPushReloadButton) {
		pastTime = DateTime.Now - this.reloadTime;
		if(pastTime > allowTime){
			isPushReloadButton = false;
		}
	}
}

//ボタンイベント
public void OnClickButton ()
{
	if ( isPushReloadButton ) return;
	isPushReloadButton = true;
		
	// ここに通信処理などを書く

	//現在の時間をセット
	this.reloadTime = DateTime.Now;
}

もちろんですが、端末の時間を利用して秒をカウントしているので
動作が重い端末だと時間が変わってしまうのかも
そこは要検証ですが、ボタン連打制限ならアバウトでもきっとだいじょうぶでしょ

Unityエディタ拡張でシーン内のオブジェクトに関連付けられたコンポーネント内の変数を取得する

タイトルめっちゃ長い

シーン内の変数一覧が欲しくなったのでエディタ拡張から取得出来ないか頑張ってみました
本当は値も欲しかったのだけど、今回とれたのは変数名一覧だけでした

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


public class EditorExWindow : EditorWindow
{


	[MenuItem("Window/EditorEx")]
	static void Open()
	{
		EditorWindow.GetWindow<EditorExWindow>( "EditorEx" );
	}

	string textArea = "";

	void OnGUI()
	{
		if( GUILayout.Button("Caputure") )
		 	Find();
		GUILayout.Label( "TextArea" );
		textArea = GUILayout.TextArea( textArea );

	}

	 

	private void Find (){
		// TextAreaクリア
		textArea = "";

		List<GameObject> AllObjects =  new List<GameObject>();
		List<MonoBehaviour> allMonobehaviourList = new List<MonoBehaviour> ();

		foreach (GameObject obj in UnityEngine.Resources.FindObjectsOfTypeAll(typeof(GameObject)))
		{
			// アセットからパスを取得.シーン上に存在するオブジェクトの場合,シーンファイル(.unity)のパスを取得.
			string path = AssetDatabase.GetAssetOrScenePath(obj);
			// シーン上に存在するオブジェクトかどうか文字列で判定.
			bool isScene = path.Contains(".unity");
			// シーン上に存在するオブジェクトならば処理.
			if (isScene)
			{
				AllObjects.Add (obj);
			}
		}

		allMonobehaviourList.AddRange (GetComponentsInList<MonoBehaviour> (AllObjects));

		foreach(var componentData in allMonobehaviourList){
			foreach(MemberInfo mi in componentData.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance |  BindingFlags.DeclaredOnly)){
				textArea += mi.Name + "\n";
			}
		}
	}

	public static IEnumerable<T> GetComponentsInList<T> (IEnumerable<GameObject> gameObjects ) where T : Component 
	{
		var componentList = new List<T> ();

		foreach (var obj in gameObjects) {
			var components = obj.GetComponents<T> ();
			if (components != null) {
				foreach(var component in components){
					componentList.Add (component);
				}
			}
		}
		return componentList;
	}
}

変数名が取れたんだから中身も取れると思うんだけど...
もうちょっとがんばろう


github.com

Unityエディタ拡張を作ってみる

やっとUnityの記事が書ける
エディタ拡張だけど

というわけでエディタ拡張のサンプルを作ってみました
元々サーバの方の人間なのでUnityって作業の自動化とか効率化ってどうやってるのっていうのはずっと気になってました

参考にさせてもらったのはケットシーウェアさんのサイト
【エディタ拡張徹底解説】初級編①:ウィンドウを自作してみよう【Unity】 | ケットシーウェア


僕がなに書いても意味ないくらい超丁寧でわかりやすかったです
それで出来たのがこちら

using UnityEngine;
using UnityEditor;
using System.Collections;

public class EditorExWindow : EditorWindow
{
	[MenuItem("Window/EditorEx")]
	static void Open()
	{
		EditorWindow.GetWindow<EditorExWindow>( "EditorEx" );
	}

	string textArea = "";

	void OnGUI()
	{
		if( GUILayout.Button("Find  Objects") )
		 	Find();
		GUILayout.Label( "TextArea" );
		textArea = GUILayout.TextArea( textArea );

	}

	private void Find (){
		// TextAreaクリア
		textArea = "";
		foreach (GameObject obj in UnityEngine.Resources.FindObjectsOfTypeAll(typeof(GameObject)))
		{
			// アセットからパスを取得.シーン上に存在するオブジェクトの場合,シーンファイル(.unity)のパスを取得.
			string path = AssetDatabase.GetAssetOrScenePath(obj);
			// シーン上に存在するオブジェクトかどうか文字列で判定.
			bool isScene = path.Contains(".unity");
			// シーン上に存在するオブジェクトならば処理.
			if (isScene)
			{
				// GameObjectの名前を表示.
				Debug.Log(obj.name);
				textArea += obj.name + "\n";
			}
		}
	}
}


Unityエディタから表示してみるとこんな感じになります
f:id:chroske:20150608202732p:plain

やってることは
①Findボタンが押されたらイベント実行
②イベントからResources.FindObjectsOfTypeAllでシーン内のオブジェクトを全て取得
③TextAreaに書き込む
これだけです

これで何が出来るってわけでもないけど
なにが出来そうっていうのはなんとなくわかったのではなかろうか
もちろん取得だけじゃなくて操作や生成も行える
すばらしい、夢が広がるね
なにか実用的なものができたらまた載せようと思う

はてなブログでのソースコードの載せ方

ネタがないのではてなブログのことでも

前までさくらVPSを借りたりraspberry piを自宅サーバにしたりしてwordpressを動かしてたのですが
さくらVPSはテラリアのゲームサーバに使い始め、raspberry piは夏だし燃えたらこわいので(燃えないと思うけど)こっちに引っ越してきた
こっち来てまず調べたのはブログへのソースコードの載せ方、一応技術ブログなので


>||
ここにソースコードを書くよ
||<


こんなかんじで「>||」「||<」で囲むと中がエスケープになりなんでも書き放題です
ちなみにこれははてな記法での書き方になっており、デフォルトでは「見たままモード」になっているので、はてなブログの設定の編集モードのところから変えてやりましょう
C#に特化した見た目にしたい場合は


>|cs|
ここにC#ソースコードを書くよ
||<


こんな感じです
多分他の言語もあるんじゃないかな




ちなみにエスケープに使われてる「>||」「||<」はどうやってエスケープしてんのよって話ですが、別にわざわざ「見たままモード」にしてるわけではなくASCIIコードをそのまま貼り付けてます
じゃあASCIIコードで書いたエスケープはエスケープできんのか?!って話ですが
やってみた感じできませんでした。
まあ使わないしいっか