2013年5月26日日曜日

Unity TIps #48 - インスペクタのリフレッシュ

前回に引き続いて Unify Community からインスペクタのリフレッシュに関する Tips の翻訳を紹介する:



http://wiki.unity3d.com/index.php/Tip_of_the_day
Jan 2013


Tip #48 Refresh Inspector


インスペクタのリフレッシュ


最近、Editor クラスの外からインスペクタを強制的に再描画するスクリプトを書く必要があった。考え付いたソリューションは全ての選択されたオブジェクトで SetDirty をコールすることだった。インスペクタは次に変更を拾って、自身をただちにリフレッシュした。
このコードは Unity 4 で動作するとはいえ、ハックの一種なのでもっとより良い方法でインスペクタを再描画させる方法はあるかもしれない。

var objects = Selection.GetFiltered(typeof(GridMap), SelectionMode.TopLevel);
foreach (var o in objects)
{
    EditorUtility.SetDirty(o);
}
-----

今回もシンプル!意外と単純な解決策はあるもんだ・・・

Unity Tips #49 - レンダリング境界の表示


前回に引き続いて Unify Community からレンダリング境界の表示に関する Tips の翻訳を紹介する:



http://wiki.unity3d.com/index.php/Tip_of_the_day
Jan 2013

Tip #49 Visualizing Render Bounds

レンダリング境界の表示

次の C# スクリプトによりレンダリング境界を表示します。ゲームオブジェクトにアタッチすれば、そのゲームオブジェクトおよびその子オブジェクトのレンダリング境界を表示します。デバッグに便利です!



  public class RendererBoundsGizmo : MonoBehaviour
    {
        public bool ShowCenter;
 
        public Color Color = Color.white;
 
        public bool DrawCube = true;
 
        public bool DrawSphere = false;
 
        /// <summary>
        /// When the game object is selected this will draw the gizmos
        /// </summary>
        /// <remarks>Only called when in the Unity editor.</remarks>
        private void OnDrawGizmosSelected()
        {
            Gizmos.color = this.Color;
 
            // get renderer bonding box
            var bounds = new Bounds();  
            var initBound = false;
            if (CBX.Utilities.Helpers.GetBoundWithChildren(this.transform, ref bounds, ref initBound))
            {
                if (this.DrawCube)
                {
                    Gizmos.DrawWireCube(bounds.center, bounds.size);
                }
                if (this.DrawSphere)
                {
                    Gizmos.DrawWireSphere(bounds.center, Mathf.Max(Mathf.Max(bounds.extents.x, bounds.extents.y), bounds.extents.z));
                }
            }
 
            if (this.ShowCenter)
            {
                Gizmos.DrawLine(new Vector3(bounds.min.x, bounds.center.y, bounds.center.z), new Vector3(bounds.max.x, bounds.center.y, bounds.center.z));
                Gizmos.DrawLine(new Vector3(bounds.center.x, bounds.min.y, bounds.center.z), new Vector3(bounds.center.x, bounds.max.y, bounds.center.z));
                Gizmos.DrawLine(new Vector3(bounds.center.x, bounds.center.y, bounds.min.z), new Vector3(bounds.center.x, bounds.center.y, bounds.max.z));
            }
 
            Handles.BeginGUI();
            var view = SceneView.currentDrawingSceneView;
            var pos = view.camera.WorldToScreenPoint(bounds.center);
            var size = GUI.skin.label.CalcSize(new GUIContent(bounds.ToString()));
            GUI.Label(new Rect(pos.x - (size.x / 2), -pos.y + view.position.height + 4, size.x, size.y), bounds.ToString());
            Handles.EndGUI();
        }
    }

さらに GetBoundsWithChildren メソッドのスクリプトです:

  /// <summary>
        /// Gets the rendering bounds of the transform.
        /// </summary>
        /// <param name="transform">The game object to get the bounding box for.</param>
        /// <param name="pBound">The bounding box reference that will </param>
        /// <param name="encapsulate">Used to determine if the first bounding box to be calculated should be encapsulated into the  argument.</param>
        /// <returns>Returns true if at least one bounding box was calculated.</returns>
        public static bool GetBoundWithChildren(Transform transform, ref Bounds pBound, ref bool encapsulate)
        {
            var bound = new Bounds();
            var didOne = false;
 
            // get 'this' bound
            if (transform.gameObject.renderer != null)
            {
                bound = transform.gameObject.renderer.bounds;
                if (encapsulate)
                {
                    pBound.Encapsulate(bound.min);
                    pBound.Encapsulate(bound.max);
                }
                else
                {
                    pBound.min = bound.min; 
                    pBound.max = bound.max; 
                    encapsulate = true;
                }
 
                didOne = true;
            }
 
            // union with bound(s) of any/all children
            foreach (Transform child in transform)
            {
                if (GetBoundWithChildren(child, ref pBound, ref encapsulate))
                {
                    didOne = true;
                }
            }
 
            return didOne;
        }
-----

ん?Unityエディタのワイヤフレームに似ているとおもったけど少し発展的な用途に使うことが多いだろうか。

これも覚えておこうぜ!

2013年5月22日水曜日

Unity Tips #50 - コンパイル記号があることの確認

前回に引き続いて Unify Community からコンパイル記号に関する Tips の翻訳を紹介する:



http://wiki.unity3d.com/index.php/Tip_of_the_day
Feb 2013

Tip #50 Ensure conditional compilation symbols are present

コンパイル記号があることの確認


もし Unity のコードで条件付きコンパイル記号が必要な場合、このコードが便利かもしれない。Unity が自身のスクリプトをコンパイルした後、InitializeOnLoad 属性のあるクラスを実行します。 コード スニペットに含まれる SetupConditionalCompilation メソッドをコールすることで条件付きコンパイル記号が Unity プロジェクトで永続することを保証できます。もし記号がなくて追加された場合、Unity コンソールに通知を書き出します。


[InitializeOnLoad]
public class GridMappingSetup
{
    static GridMappingSetup()
    {
        var types = new[] { BuildTargetGroup.Standalone, BuildTargetGroup.WebPlayer };
        var toInclude = new[] { "CBXControls", "GridMapping", "QuickTools", "ToolService", "TileMaterialCreation" };
 
        SetupConditionalCompilation(types, toInclude);
    }
}
 
  public static void SetupConditionalCompilation(BuildTargetGroup[] platformTargets, string[] symbolsToInclude)
        {
            foreach (var type in platformTargets)
            {
                var hasEntry = new bool[symbolsToInclude.Length];
                var conditionals = PlayerSettings.GetScriptingDefineSymbolsForGroup(type).Trim();
                var parts = conditionals.Split(';');
                var changed = false;
 
                foreach (var part in parts)
                {
                    for (int i = 0; i < symbolsToInclude.Length; i++)
                    {
                        if (part.Trim() == symbolsToInclude[i].Trim())
                        {
                            hasEntry[i] = true;
                            break;
                        }
                    }
                }
 
                for (int i = 0; i < hasEntry.Length; i++)
                {
                    if (!hasEntry[i])
                    {
                        conditionals += (String.IsNullOrEmpty(conditionals) ? String.Empty : ";") + symbolsToInclude[i];
                        changed = true;
                    }
                }
 
                PlayerSettings.SetScriptingDefineSymbolsForGroup(type, conditionals);
 
                if (changed)
                {
                    Debug.Log(String.Format("Updated player conditional compilation symbols for {0}: {1}", type, conditionals));
                }
            }
        }
---------

地味なTipsでも積み重ねて力にしていこうぜ!

2013年5月19日日曜日

Unity Tips #52 バージョン変更で正しいリンク


前回に引き続いて Unify Community からバージョン変更で正しいリンクに関する Tips の翻訳を紹介する:



http://wiki.unity3d.com/index.php/Tip_of_the_day
Feb 2013


Tip #52 Providing proper links in version changes

バージョン変更で正しいリンク


もしアセットストアにパッケージを提出していて、HTMLリンクを伴うバージョン変更を含む場合、リンク属性の中で target="_blank" を指定するのを忘れないようにして下さい。そうしなければ、アセットストア ウィンドウがもともとリンクしていたウェブページにより置き換えられる結果となります。場合によっては Unity がクラッシュします。
-------------

正しいリンクね~。Unity のクラッシュは良くあるけど、原因のひとつづつ覚えて解決していくしかないね!

2013年5月12日日曜日

Unity Tips #54 Scale Transformとレンダラ


Unify Community にScale Transformとレンダラに関する Tips があったので紹介したい。

http://wiki.unity3d.com/index.php/Tip_of_the_day
Feb 2013

Unity Tips #54 Scale Transform

Scale Transformとレンダラ


次のコードによりゲームオブジェクトの Transform を x, z 軸に沿って特定のサイズに拡大する際にゲームオブジェクトにレンダラ (Renderer) コンポーネントがアタッチされていれば、そのレンダラの境界線もあわせて調整する。

/// 
/// Transform を x, z 軸に沿って特定のサイズに拡大する。
/// </summary>
/// <param name="transform" />
/// スケールする Transform への参照
/// 
/// <param name="width" />ターゲット サイズを表す x 軸に沿った幅
/// <param name="height" />ターゲット サイズを表す z 軸に沿った高さ
public static void ScaleTransform(Transform transform, float width, float height)
{
    // プレハブ境界を取得
    var bounds = new Bounds();
    var encapsulate = false;
    if (!Utilities.Helpers.GetBoundWithChildren(transform, ref bounds, ref encapsulate))
    {
        return;
    }
 
    // サイズの軸のうち最小の大きさを取得
    var min = Mathf.Min(width, height);
 
    // Transformの x または z 軸のうち最大の大きさを取得
    var max = Mathf.Max(bounds.size.x, bounds.size.z);
 
    // スケール係数を計算
    var scaleFactor = min / max;
 
    // Transform にスケールを適用
    transform.localScale *= scaleFactor;
}
 
/// <summary>
/// Transform のレンダラ境界を取得
/// </summary>
/// <param name="transform" />境界ボックスを取得するゲームオブジェクト
/// <param name="pBound" />境界ボックスへの参照
/// <param name="encapsulate" />最初の境界ボックスとして
/// 計算されたものが <see cref="pBound"> 引数にカプセル化すべきか判断する
/// <returns>最低でもひとつの境界ボックスが計算されていれば true を戻す。</returns>
public static bool GetBoundWithChildren(Transform transform, ref Bounds pBound, ref bool encapsulate)
{
    var didOne = false;
 
    // 'this' の境界を取得
    if (transform.gameObject.renderer != null)
    {
        var bound = transform.gameObject.renderer.bounds;
        if (encapsulate)
        {
            pBound.Encapsulate(bound.min);
            pBound.Encapsulate(bound.max);
        }
        else
        {
            pBound.min = bound.min;
            pBound.max = bound.max;
            encapsulate = true;
        }
 
        didOne = true;
    }
 
    // 子オブジェクトのすべての境界と結合
    foreach (Transform child in transform)
    {
        if (GetBoundWithChildren(child, ref pBound, ref encapsulate))
        {
            didOne = true;
        }
    }
 
    return didOne;
}
--------
Unityデフォルトだとレンダラのサイズは調整されないので便利だぜ!

Unity Tips #55 InitializeOnLoadなどの良くある間違い


Unify Community に InitializeOnLoadなどの良くある間違いに関する Tips があったので紹介したい:


http://wiki.unity3d.com/index.php/Tip_of_the_day
Feb 2013

Tip #55 InitializeOnLoad & Resources.Load gotcha’s

InitializeOnLoadおよびResources.Loadの良くある間違い


最近、 Unity 4 エディタで初めはバグだとおもった内容に遭遇した。 InitializeOnLoad からの Resources.Load メソッドの使用が絡んでいる。

例えば次のサンプルコードをみてみる:
namespace CBX.CoreProjectCode
{
    using UnityEditor;
 
    using UnityEngine;
 
    [InitializeOnLoad]
    public class EditorInitialization
    {
        static EditorInitialization()
        {
            LoadData(); // Resourceフォルダのtest.txt ファイルを参照することに失敗する
        }     
 
        private static void LoadData()
        {
            // データのロードを試みる
            var data = Resources.Load("test", typeof(TextAsset)) as TextAsset;
            if (data == null)
            {
                Debug.LogWarning("データは見つかりませんでした");
                return;
            }
 
            Debug.Log(data.text);
        }
    }
}

Unity がスクリプトをコンパイルした後、InitializeOnLoad によりマークされたクラスの static なコンストラクタを実行する。しかし、この時点で私は Unity がまだ Resources フォルダの中にあるアセットについては識別できていないとみている。クラスのコンストラクタが Resources.Load メソッドをコールしたとき、 text.txt リソースファイルを呼ぶことに失敗し、コンソールに警告メッセージを表示する。

この時点でやることが可能であることのひとつはプロジェクトウィンドウの Assets フォルダを右クリックして Reimport を選択することだ。 Unity は Assets を再インポートして、 InitializeOnLoad によりマークされたクラスをコールする。しかし、今回は Resources.Load は正しく test.txt の読み込みを行い、内容を Unity コンソールウィンドウに表示する。

この問題の回避方法のひとつは、 EditorApplication.Update コールバックをフックしてそこから LoadData メソッドへのコールを行うことだ。以下にそのサンプルを示す:

namespace CBX.CoreProjectCode
{
    using UnityEditor;
 
    using UnityEngine;
 
    [InitializeOnLoad]
    public class EditorInitialization
    {
        private static bool ranOnce;
 
        static EditorInitialization()
        {
            EditorApplication.update += RunCallbacks;
        }
 
        private static void RunCallbacks()
        {
            if (!ranOnce)
            {
                // Resource フォルダの test.txt がみつかり内容が
                // 表示される
                LoadData();
                ranOnce = true;
 
                // returnするかはあなた次第
                return;
            }
 
            // 必要な処理があれば記述
        }
 
        private static void LoadData()
        {
            var data = Resources.Load("test", typeof(TextAsset)) as TextAsset;
            if (data == null)
            {
                Debug.LogWarning("データはみつかりませんでした");
                return;
            }
 
            Debug.Log(data.text);
        }
    }
}
これがバグであるかどうかは認識していないが、Unity にバグレポートの提出は行っている。リンクは次のとおりだ。
-----------------

先人の知恵は重要。Unity プログラミングに活かそうぜ!

Unity Tips #56 プロジェクトフォルダおよびカレントディレクトリの取得



今回は Unify Community で紹介されている Tips からカレントディレクトリの変更に関する Tips を紹介したい:

http://wiki.unity3d.com/index.php/Tip_of_the_day
Feb 2013

Tip #56 Get project folder & current directory

プロジェクトフォルダおよびカレントディレクトリの取得


Unity にプロジェクトフォルダ取得の API はないが、System.IO.Directory.GetCurrentDirectory を活用できる。Unity エディタはつねにカレントディレクトリがプロジェクトフォルダにセットされていることを前提にしている。

もしエディタスクリプトの中でカレントディレクトリを System.IO.Directory.SetCurrentDirectory により変更する場合、処理が完了した後に必ずディレクトリをプロジェクトフォルダにリストアしておく必要がある。そうしないと Unity でコンパイルする次の機会にダイアログボックスのプロンプト表示がなされてカレントディレクトリをプロジェクトディレクトリにリストアする必要が出てきて、 「Quit」ボタンにより Unity を終了せざるを得なくなる。

// プロジェクトフォルダを保存
var projectFolder = System.IO.Directory.GetCurrentDirectory();
 
// 指定のフォルダに カレントディレクトリをセットする
System.IO.Directory.SetCurrentDirectory("c:\\some folder name");

// 必要な処理を行う
// ...
 
// カレントディレクトリをプロジェクトディレクトリにリストアする
System.IO.Directory.SetCurrentDirectory(projectFolder);
---------

小さなテクニックでも積み上げていけば大きいぜ!

ブックマークに追加

このエントリーをはてなブックマークに追加

自己紹介

自分の写真
Unity3D公式マニュアル翻訳やってる人がスマホ(iPhone, Android)のゲーム開発しています。気軽に面白く初心者が遊べる内容がモットー。Blogでは開発情報をひたすら、Twitterではゲーム作成の過程で参考にしている情報を中心につぶやきます

ページビューの合計

過去7日間の人気投稿