うにてぃブログ

主にUnityとC#に関する記事を書いていきます

記事まとめ

Github

github.com

デバッグツール
Easing関数
Missing Script 検索ツール
モデル撮影ツール
Module化ライブラリ
Unity上で使える Git Tool
単純なメッシュを作成するツール
カメラ一覧を表示
アセットのディレクトリを移動する
テクスチャ生成ツール

Unity 拡張

Animator 再生待ち
Transform の Global Scale (lossyScale) を 指定の値に変更する
Graphicの反転
WaitForSeconds のキャッシュ
テクスチャを UV スクロールする
RawImage を UVスクロールする
Image の 角を丸くする
Filled Image
Image を グラデーションする
Image を グラデーションしてFilled対応
指定した範囲にランダムで配置する
Coroutine が動作している間に 特定処理の有効無効を制御
ポストエフェクトのサイズを変える
物理演算の予測線を表示する
uGUI unmask
オブジェクトを回転させ続ける
Texture2Dの合成
PlayableGraph を利用した AnimationClip を再生するコンポーネント
ReorderableList の GUI を作り変える

Text

uGUI Text を改行させない
uGUI Text をスクロールさせる
1文字ずつ現れるuGUI Text
カーブする Text
揺れるText

Editor拡張

ProjectWindow 拡張
HierarchyWindow 拡張
Transform の Inspector 拡張
SpriteRenderer の Inspector 拡張
アセットファイルの置換ツール
List の表示を拡張する
RaycastTarget が有効なオブジェクトを強調する拡張
ScriptableObject のOnInspectorGUI
DefaultAsset の Inspector 拡張
Splitter
EditorWindow にタブを利用する
Hierarchy で GameObject を Duplicate したタイミングをハンドルする
Textureコピー
Texture生成
ScriptableSingletonの使いみち
Listを横並びに表示する
ドラッグアンドドロップ
EditorGUIのフォーカスを外す
再生、停止、一時停止をハンドル
UnityEditor起動時にのみ処理を行う
MeshFilter の Mesh を保存する
RectTransform を親にフィットさせる
UnityEditor で ターミナルを動かす

便利クラス

GUIStyleのカラーキャッシュ
GUILayoutOptionのキャッシュ

SceneView

SceneView に RectTransform の 領域を表示する
全 Collider を Scene に表示する拡張
モデルの法線を表示する
モデルのuvや頂点カラーを表示する
ImageのUVと頂点カラーを表示する

SerializedProperty

SerializedProperty と System.Type の Array と List の判定と Type 取得
SerializedProperty を用いたクラス描画手法 ~1~
SerializedProperty を用いたクラス描画手法 ~2~
List 表示を拡張
SerializedProperty の Type や FieldInfo を取得する

CustomPropertyDrawer

CustomPropertyDrawer を利用している Type 一覧の取得
Inspector に Preview を表示する
Colorの表示を拡張する
AddComponentOrGetComponent
検索できるEnum Field
GetComponentを行う
SpriteRendererのInspector拡張
パスを表示する

機能まとめ

EditorWindow で使える Scope 一覧
UnityEditor で使える Field 一覧
UnityEditor で使えるプログレスバー
UnityEditor で使えるフォルダ・ファイル選択パネル
Reflection
Video Playerのストリーミング再生
EditorWindow に MenuItem を追加する
ポストエフェクト
Play 時の Scene を固定する
Sprite の Filter Mode
タップした位置のオブジェクトを判定
Camera を使う
UnityProject外から画像をロードする
Editor Default Resources
material と sharedMaterial の違い
GUI で使える skin一覧
EditorStyles で使えるスキン一覧 【Unity2019.3未満】
EditorStyles で使えるスキン一覧 【Unity2019.3以降】
PopupWindow のテンプレート
UnityEvent一覧
LINQ一覧
Time の 変数一覧
Preset
MonoBehaviour クラスのシリアライズされた変数の Inspector をカスタマイズ する Attribute の作り方
TreeViewの拡張に利用できる変数一覧
TreeViewのoverrideメソッド一覧
検索窓付きのTreeViewサンプル
Unity の Assembly 定義について
スタックトレースを確認する

UnityTips

ベクトルから角度を求めたり、角度からベクトルを求める
円周の位置を取得する
RecTransform の Pivot 変更
RigidBodyの重心を変更
RectTransform の範囲内は判定する
uGUI のドラッグ
Text と Image の頂点描画順
EditorWindow が開いているか判定する
Editor 上で Animation を動かす
RectTransformの中心座標を取得する
RectTransformの範囲内か判定する
uGUIをドラッグする
uGUIの自動レイアウト
Unity Build-in Shader
深度テクスチャを確認する
Text と TextMesh Pro の違い
サイコロの上面を判定する
UnityEventについて
AddComponent Menuで非表示にする
Transform の位置を変更する
z-Depthが取得できない場合
TextMesh Pro の Font Material をロードする
ランタイムでカメラの映像を保存する
どうぶつの森のような曲がった世界を作る
スクリプトからIDEを開く
EditorGUI で テキストにフォーカスする
EditorWindowを中心に持ってくる処理
GUIStyleの描画範囲を取得する
UnityEditor上のアセットバンドルネームのついているアセットを探す

パフォーマンス

コードの Profiling を行う
RenderTextureのメモリ使用量
Listの初期サイズ
boxingのGC
ToListのGC
ToArrayのGC
Transformの移動
CustomYieldInstructionのGC
Material.SetParam
OnTriggerStayの呼び出し頻度
uGUI Text のバッチング
string 結合の GC
for と foreach
for と Enumerable
昔 Vector2.Lerp や Vector3.Lerp が重いと言われていた気がするので調べてみた
transform.position にアクセスした際の GC を見る

C#

System.IO系
配列のシャッフルやランダム取得
現在のブランチ名を取得する
ulongを超える値を扱う
メソッドがオーバーライドされているか判定する
配列を入れ替える
重みをつけて抽選する
Listをシャッフルする
ランダムな文字列を返す
switchで条件式
Dictionary をソートする
ランタイム時の Array サイズ変更
配列を string にする
Stateを管理するクラス
空Actionを渡す
XY のループが面倒なので拡張してみた
クラスを拡張する
Enumerable で利用できる static メソッド
Linq で利用できるメソッド一覧

Shader

ShaderLabの条件式置き換えTips
オブジェクトの陰色を変更
画像の HSV 変換
Unlit でも 影を出す方法
波ゲージ
Grid Shader
白黒
セピア
モザイク
グレースケール
RenderType が Opaque の シェーダに アルファ 0を適応する
Dissolve
三角関数をテクスチャからロードする
SpriteAnimation
輪郭
Surface + Vertex
頂点処理を省略
ラインティングが無効な Surface
アルファテクスチャShader
頂点カラーとテクスチャを乗算する
頂点カラーShader

ジグソーパズル自動生成

1
2
3
4
5
6
7

go lang

exec.Command で git の private repository にアクセスできない問題

【C#】ベジェ曲線の長さを計算する

以前ベジェ曲線を計算するクラスを作成しました

ここで全体の距離がほしかったので処理を追加しました

以前の処理をクラスに追加すれば取得できます

計算自体もこれで正しいのかわかりませんが、曲線を分割して
分割した距離を合計しています

LOOP_VALUE の値が小さいほど正確な値が取得できますが
計算量が増えてしまうため注意が必要です

   /// <summary>
    /// 距離を取得
    /// </summary>
    public float Length => GetLength(_positions);
 
    public static float GetLength(Vector3[] pos)
    {
        const float LOOP_VALUE = 0.05f;
 
        var total = 0f;
        var prev = Eval(pos, 0f);
        var c = Vector3.zero;
        var diff = Vector3.zero;
        for (var t = LOOP_VALUE; t < 1f; t += LOOP_VALUE)
        {
            c = Eval(pos, t);
            diff = prev - c;
            total += (float)Math.Sqrt(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z);
            prev = c;
        }
        c = Eval(pos, 1f);
        diff = prev - c;
        total += (float)Math.Sqrt(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z);
 
        return total;
    }

【C#】ベジェ曲線を計算する

ベジェ曲線 - Wikipedia

wiki より計算式を拝借して、ベジェ曲線を計算するクラスを作成しました

使い方

Transform の座標を使ってやる場合はこんなふうに

f:id:hacchi_man:20201010023211p:plain

public class SampleMonoBehaviour : MonoBehaviour
{
    [SerializeField]
    private Transform[] _transforms;

    private void OnDrawGizmos()
    {
        if (_transforms == null || _transforms.Length <= 1)
            return;

        var a = _transforms.Select(t => t.position).ToArray();
        var prev = _transforms[0].position;
        for (var i = 0f; i <= 1f; i += 0.01f)
        {
            var pos = BezierCurve.Eval(a, i);
            Gizmos.DrawLine(prev, pos);
            prev = pos;
        }
    }
}

予め座標が固定されているなら
インスタンスを作成して Eval を呼び出します

var curve = new BezierCurve(new []
{
    new Vector3(0, 0, 0),
    new Vector3(0, 1f, 0),
    new Vector3(1f, 0, 0),
});

var pos = curve.Eval(0.5f);

コード

using System;
using UnityEngine;

[Serializable]
public class BezierCurve
{
    private Vector3[] _positions;

    public BezierCurve(Vector3[] positions)
    {
        _positions = positions;
    }

    public Vector3 Eval(float t)
    {
        return Eval(_positions, t);
    }

    public static Vector3 Eval(Vector3[] pos, float t)
    {
        if (pos == null || pos.Length < 1)
            return Vector3.zero;

        var length = pos.Length;
        if (length == 1)
            return pos[0];

        var r = Vector3.zero;
        for (var i = 0; i < length; i++)
            r += pos[i] * Bernstein(t, length - 1, i);

        return r;
    }

    /// <summary>
    /// バースタイン基底関数
    /// </summary>
    /// <returns></returns>
    private static float Bernstein(float t, int n, int i)
    {
        return nCr(n, i) * Mathf.Pow(t, i) * Mathf.Pow(1 - t, n - i);
    }

    /// <summary>
    /// n 個から r 個を取り出すときの組み合わせの数
    /// </summary>
    private static long nCr(int n, int r)
    {
        return Factorial(n) / (Factorial(r) * Factorial(n - r));
    }

    private static int Factorial(int i)
    {
        if (i <= 1)
            return 1;

        return i * Factorial(i - 1);
    }
}

【Unity】Vector 系で利用できるインデクサー

Vector2, Vector3, Vector4, Vector2Int, Vector3Int にはインデクサーが定義されている
※ Color にもある

インデクサーとは下記のようなもので

    public float this[int index]
    {
      get
      {
        switch (index)
        {
          case 0:
            return this.x;
          case 1:
            return this.y;
          default:
            throw new IndexOutOfRangeException("Invalid Vector2 index!");
        }
      }
      set
      {
        switch (index)
        {
          case 0:
            this.x = value;
            break;
          case 1:
            this.y = value;
            break;
          default:
            throw new IndexOutOfRangeException("Invalid Vector2 index!");
        }
      }
    }

instance[num] でアクセスすることができる

例えば y の値が欲しい際には instance[1] で取得できる

var vector3 = Vector3.zero;
// x
vector3[0];
// y
vector3[1];
// z
vector3[2];

利用例

x, y, zによって乗算する倍率変えたいときに利用できたりする

   private static readonly Vector3 Value = new Vector3(1f, 1.5f, 2f);
 
    private Vector3 Calc(Vector3 src)
    {
        var ret = Vector3.zero;
#if true
        // インデクサーを利用する場合
        for (var i = 0; i < 3; i++)
            ret[i] = src[i] * Value[i];
#else
        // インデクサーを利用しない場合
        ret.x = src.x * Value.x;
        ret.y = src.y * Value.y;
        ret.z = src.z * Value.z;
#endif
 
        return ret;
    }

【Unity】EventSystems の Interface 処理をスクリプトから呼び出す

ExecuteEvents.Execute を利用することで その GameObject が所持している
コンポーネントに対して Event を実行することができます

EventSystems.ExecuteEvents-Execute - Unity スクリプトリファレンス

対応している interface は以下です

  • IBeginDragHandler
  • ICancelHandler
  • IDeselectHandler
  • IDragHandler
  • IDropHandler
  • IEndDragHandler
  • IInitializePotentialDragHandler
  • IMoveHandler
  • IPointerClickHandler
  • IPointerDownHandler
  • IPointerEnterHandler
  • IPointerExitHandler
  • IPointerUpHandler
  • IScrollHandler
  • ISelectHandler
  • ISubmitHandler
  • IUpdateSelectedHandler

サンプル

interface を継承している GameObject を渡すことで interface を 呼び出すことができます

// 各Interface で利用するパラメータを適切に設定する必要がある
var eventData = new PointerEventData();
eventData.position = position;
eventData.pressPosition = position;
eventData.button = PointerEventData.InputButton.Left;

ExecuteEvents.Execute<IPointerDownHandler>(gameObject, eventData, (handler, ev) => handler.OnPointerEnter((PointerEventData)ev));

【Unity】ListPool について

Shadow など BaseMeshEffect を継承しているクラスの場合 UIVertex を利用する際に List が必要になる

この List を利用 するたびに new していると Mesh の構築頻度によりますが
メモリリークしてしまったり、CPUのスパイクが発生してしまう可能性が高くなります

        public override void ModifyMesh(VertexHelper vh)
        {
            var output = new UIVertex();
            vh.GetUIVertexStream(output);

そのために Unity の内部では ListPool を利用していました
ListPool では static の領域の List を使い回す処理をしていました

ListPool のコードはこちらをご覧くらださい
uGUI/ListPool.cs at eba27f4eca40e88ba5d76c3f439fef950f9f38a5 · Unity-Technologies/uGUI · GitHub

先程の Shadow のコードであれば このようになります

        public override void ModifyMesh(VertexHelper vh)
        {
            if (!IsActive())
                return;

            var output = ListPool<UIVertex>.Get();
            vh.GetUIVertexStream(output);

しかしながら internal なので外部からは利用できません

これを public にしてしまうとなんでもかんでもこれを利用して Relase を忘れると
メモリがやばいことになると考えて internal なんだと思います・・・

何種類もの型 を PoolList で利用することはおすすめしませんが
BaseMeshEffect を使ったクラスを作成時に、ListPool を利用するのはいいかもしれません

【Unity】AnimationClip 再生中に スクリプトを実行する

Animation Clip は タイムライン上部で右クリックすることで イベントを追加することができる

f:id:hacchi_man:20201006233540p:plain:w300

追加したイベントをダブルクリックすると Inspector に下図が表示される

f:id:hacchi_man:20201006233626p:plain:w300

これは GameObject に Animator を追加して State に設定してある Animation Clip から
Animation Clip を開かないと正しい UI になりません

f:id:hacchi_man:20201006233913p:plain:w250f:id:hacchi_man:20201006233922p:plain:w250

正しくセットできていると Inspector の表示も変化し Animator を追加した GameObject に
追加されている コンポーネントの Public メソッド一覧が表示されるようになります

引数がある場合は、ちゃんと Parameters が表示され 引数の値を指定することができます

f:id:hacchi_man:20201006234057p:plain:w300

これで Animation Clip を再生すると イベントを追加した箇所で スクリプトの呼び出しが行われます

しかし、汎用的ではないので Animator を追加した GameObject が指定してある メソッド を実行できない場合は何も起こりません

【Unity】UIBehaviour について

MonoBehaviour を継承した UIBehaviour というクラスが存在する

EventSystems.UIBehaviour - Unity スクリプトリファレンス

CanvasScalerGraphic など uGUI で利用するクラスの多くはこれを継承して作られている

実装されているメソッドは以下の通りで基本的には override して利用する

Github のコードはこちら
uGUI/UIBehaviour.cs at 2017.1 · Unity-Technologies/uGUI · GitHub

protected virtual void Awake()
 
protected virtual void OnEnable()
 
protected virtual void Start()
 
protected virtual void OnDisable()
  
protected virtual void OnDestroy()
 
/// <summary>
/// Returns true if the GameObject and the Component are active.
/// </summary>
public virtual bool IsActive()
 
#if UNITY_EDITOR
 
protected virtual void OnValidate()
 
protected virtual void Reset()
 
#endif
 
/// <summary>
/// This callback is called if an associated RectTransform has its dimensions changed. The call is also made to all child rect transforms, even if the child transform itself doesn't change - as it could have, depending on its anchoring.
/// </summary>
protected virtual void OnRectTransformDimensionsChange()
 
protected virtual void OnBeforeTransformParentChanged()
 
protected virtual void OnTransformParentChanged()
 
protected virtual void OnDidApplyAnimationProperties()
 
protected virtual void OnCanvasGroupChanged()
 
/// <summary>
/// Called when the state of the parent Canvas is changed.
/// </summary>
protected virtual void OnCanvasHierarchyChanged()
 
/// <summary>
/// Returns true if the native representation of the behaviour has been destroyed.
/// </summary>
/// <remarks>
/// When a parent canvas is either enabled, disabled or a nested canvas's OverrideSorting is changed this function is called. You can for example use this to modify objects below a canvas that may depend on a parent canvas - for example, if a canvas is disabled you may want to halt some processing of a UI element.
/// </remarks>
public bool IsDestroyed()

uGUI で利用するときに便利なのかと思うが OnRectTransformDimensionsChange 等のイベントは
MonoBehaviour を継承したクラスに 定義すると利用できる

どんなイベントが利用できるか知る分にはいいかもしれないが、 個人的には現状の UIBehaviour を利用する必要性は無いと思っています

すべての UI に使われているコンポーネントをこれを継承して作る等のルールがあれば
スクリプトを見れば UI 用かどうか分かるので 多少便利かもしれません・・・