【Unity】TextMeshProに数字を設定する

メモ書きになります

数字を文字列変換

TextMeshProに表示するテキストは文字列でなければならないので、次のような記述をしていました。

text = x.ToString();

こちらの方法で変換はできるのですが、文字列に変換する家庭でメモリのアロケーションが起きるよと指摘をいただきました。

SetText

TextMeshProにはSetTextという関数があります。 これを使うとアロケーションなしに文字列を変換できます。

text.SetText("{0}",x};

tsubakit1.hateblo.jp

【Unity】ジェネリック型のCustomEditor

エディタ拡張を行っている時にあるジェネリクス型のクラスのInspectorを変更したい時がありその時の知見です。

対象のクラス

例えばベースクラスとして次のようなクラスを定義しました。

public class HogeBase<T> : MonoBehaviour
{
    [SerializeField]
    private T _value;
    
}

継承したクラスはこのような感じになります。

public class HogeChild : HogeBase<float>
{

}

f:id:albatrus:20211208150715p:plain
Inspector

こちらのInspectorを拡張したい場合。

[CustomEditor(typeof(HogeBase<>),true)]
public class HogeInspector : Editor
{
    private SerializedProperty _scriptProperty;
    private SerializedProperty _valueProperty;

    private void OnEnable()
    {
        _scriptProperty = serializedObject.FindProperty("m_Script");
        _valueProperty = serializedObject.FindProperty("_value");
    }

    public override void OnInspectorGUI()
    {
        using (new EditorGUI.DisabledScope(true))
        {
            EditorGUILayout.PropertyField(_scriptProperty);
        }

        EditorGUILayout.PropertyField(_valueProperty, new GUIContent("値 "));
        
        serializedObject.ApplyModifiedProperties();
    }
}

f:id:albatrus:20211208154918p:plain
CustomEditorでInspectorを編集

CustomEditor

ジェネリクスを指定する場合には次のように指定します。 また継承先のクラスのCustomEditorの対象にするためには、第2引数をtrueにしてあげます。

[CustomEditor(typeof(HogeBase<>),true)]

複数のジェネリクスを格納する場合

次のように2つのジェネリクスの型があった場合

public class HogeBase<T,TValue> : MonoBehaviour
{
    [SerializeField]
    private T _value;
    
    [SerializeField]
    private TValue _value2;
    
}

カンマを使って指定ができます。

[CustomEditor(typeof(HogeBase<,>),true)]

【Unity】TimelineのTrackの見た目を変える

TimelineのTrackの見た目を変える場合にはTrackEditorクラスを使います。

[CustomTimelineEditor(typeof(HogeTrack))]
public class HogeTrackEditor : TrackEditor
{
}

CustomTimelineEditor Attributeに指定したTrackが拡張されます。

TrackDrawOptions

TrackEditorにはTrackDrawOptionsを指定できます。 デフォルトでは次のように設定されています。

public virtual TrackDrawOptions GetTrackOptions(TrackAsset track, UnityEngine.Object binding)
{
    return new TrackDrawOptions()
    {
         errorText = GetErrorText(track, binding, TrackBindingErrors.All),
         minimumHeight = DefaultTrackHeight,
         trackColor = GetTrackColor(track),
         icon = null
     };
}
設定できる項目
  • エラーメッセージ
  • 高さの最小値
  • Trackの色
  • アイコン

f:id:albatrus:20210715155717p:plain:w350
アイコンを変更した場合

名前の変更

名前はTrack名を変更すると変わります。 次の例ではTrackEditorのOnCreateのタイミングで名前を変更しています。

public override void OnCreate(TrackAsset track, TrackAsset copiedFrom)
{
    track.name = "ほげとらっく";
    base.OnCreate(track, copiedFrom);
}

f:id:albatrus:20210715162157p:plain:w350
Trackの名前変更

なお、名前に関してはTrackが何かしらBindingをしていると表示から消えてしまいます。

f:id:albatrus:20210715162404p:plain:w350
名前が消えてしまう

その他

色々調べたのですが、現状それ以外の項目はカスタマイズできなさそうです。 Animation TrackとAudio Trackには別途ボタンが設定されているので、もしかすると何かしらのボタンはつけられるのかもしれません。

参考リンク

qiita.com

【Unity】TimelineのClipの見た目拡張

Timelineで利用するClipの拡張をする場合、ClipEditorクラスを継承をして実装を行います。

[CustomTimelineEditor(typeof(HogeClip))]
public class HogeClipEditor : ClipEditor
{

}

CustomTimelineEditor Attributeは拡張対象になるClipのクラスをしていします。

ClipDrawOptions

ClipEditorのGetClipOptionsを使えば簡単に色々な設定ができます。

ClipDrawOptionsで設定できるもの
  • エラー文言
  • Clip名の表示非表示
  • Tipsの文言
  • ハイライト色の指定
  • Icon

デフォルトでは次のように設定されています。

public virtual ClipDrawOptions GetClipOptions(TimelineClip clip)
{
    return new ClipDrawOptions()
    {
         errorText = GetErrorText(clip),
         tooltip = string.Empty,
         highlightColor = GetDefaultHighlightColor(clip),
         icons = System.Linq.Enumerable.Empty<Texture2D>()
     };
}

iconに関しては複数設定可能です。 見た目はこのような感じになります。

f:id:albatrus:20210715112035p:plain
ClipにIconを2個並べてみる

その他、拡張できるもの

その他拡張ができそうな項目

  • Clipの名前
  • 背景の拡張

Clipの名前の変更

ClipEditorにOnCreateメソッドがります。 これはClipを作成したときに呼び出されるのですが、次のようにdisplayNameを変更することができます。

public override void OnCreate(TimelineClip clip, TrackAsset track, TimelineClip clonedFrom)
{
     var hogeClip = clip.asset as HogeClip;
     if (hogeClip == null)
     {
        return;
     }

     clip.displayName = "ほげくりっぷ";
}

f:id:albatrus:20210715114855p:plain
Clip名を変更してみる

背景の拡張 DrawBackground

DrawBackgroundメソッドをCLipが描画されるときに呼び出されます。 Clipの情報が引数で渡されるので、これを使って拡張ができます。

public override void DrawBackground(TimelineClip clip, ClipBackgroundRegion region)
{
    var bgSize = new Rect(region.position.x, region.position.y, region.position.width, region.position.height);
    EditorGUI.DrawRect(bgSize,Color.blue);
}

f:id:albatrus:20210715145730p:plain
Clip背景を青色にする

バックログを仕込んだらよく分かるのですが、呼び出される頻度がとても高いメソッドですので、ロジックを書く場合にはなるべく重い処理は避ける必要がありそうです。

小ネタ

ClipBackgroundRegionに渡されるposition.heightに関してはハイライト色を除いた高さが渡されている。 ですので少し調整が必要。 f:id:albatrus:20210715150722p:plain:w300

最後に

Clipに関してはある程度決まった箇所の変更はできそうです。 この辺りを使って使いやすいようにカスタマイズを行っていきましょう。

参考リンク

qiita.com

forum.unity.com

【Unity】TimelineのTrackAsset周りを調べてみる

TimelineのTrackを自作するときにTrackAssetクラスを使います。 このクラスでは何ができるのかを調べてみました。

f:id:albatrus:20210713111001p:plain:w300
TimelineのTrack

TrackAsset

自作のTrackを作る場合にはTrackAssetクラスを継承します。

public class TestTrack : TrackAsset
{
}

Clip指定する

Trackで指定できるClipをTrackClipType Attributeを使って指定します。

[TrackClipType(typeof(TestClip))]
public class TestTrack : TrackAsset
{
}

対象のオブジェクト指定する

Timelineでアニメーションを行うオブジェクトを指定する場合には、TrackBindingType Attributeを使います。

[TrackClipType(typeof(TestClip))]
[TrackBindingType(typeof(Image))]
public class TestTrack : TrackAsset
{
}

Trackの色を指定する

Trackの判別をするために色を付けることができます。 こちらはTrackColor Attributeを使って指定します。

[TrackClipType(typeof(TestClip))]
[TrackBindingType(typeof(Image))]
[TrackColor(255,0,0)]
public class TestTrack : TrackAsset
{
}

f:id:albatrus:20210713112733p:plain:w450
TrackとClipの色を変更

メソッド

TrackAssetで定義されているメソッドを調べてみました。

docs.unity3d.com

GetClips

Trackで設定されているClipを取得できます。

public IEnumerable<TimelineClip> GetClips()

CreateTrackMixer

このメソッドを継承することでClip同士のブレンド周りの処理を自作できます。

public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
{
    var mixer = ScriptPlayable<TestMixer>.Create(graph, inputCount);
    // 各mixerの処理
    return mixer;
}

GatherProperties

TimelineからTrackを削除したときに呼び出されます。 利用方法としては、Trackに設定されているobjectを元に戻すために利用することが多いみたいです。

public override void GatherProperties(PlayableDirector director, IPropertyCollector driver)
{

}
PlayableDirector

PlayableDirectorはTimelineを管理するコンポーネントです。

f:id:albatrus:20210713123240p:plain:w400
PlayableDirector コンポーネント

Trackに設定されているObjectを取得する場合GetGenericBindingを使います。 Imageの色を戻す場合は次のようにGatherPropertiesの記述ができそうです。

var bindingImage = director.GetGenericBinding(this) as Image;
if(bindingImage != null)
{
    // Bindingされたobjectがある場合、元に戻している
    driver.AddFromName<Text>(bindingImage.gameObject, "m_Color");
}

tsubakit1.hateblo.jp

【Unity】ExecuteAlwaysについて

Unityで使うc#のクラスでは色々なAttributeを定義することができます。 その中で「ExecuteAlways」というAttributeがあります。

docs.unity3d.com

ExecuteAlways

簡単な例は次のようになります。

[ExecuteAlways]
public class ExecuteAlwaysTest : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("Start");
    }
}

通常、Unityを再生しないとStartは呼び出されませんが、ExecuteAlwaysの場合 Prafabモードに移行したときや、再生が終わった時などに呼び出されます。

OnValidate

MonoBehaviourには、Onvalidateというメソッドがあり、これを使うとInspectorの変更時の更新処理ができます。

#if UNITY_EDITOR
    private void OnValidate()
    {
        Debug.LogError("OnValidate:" + _value);
    }
#endif

今まではこちらを使っていたのですが、ExecuteAlwaysに関しても何かしらできそうだなと感じました。

【Unity】自作のPlayableを作成しTimelineで再生できるようにする

Playable API周りについての概要がなんとなくわかってきたので、次にScriptablePlayableを自作してみたいと思い調査をしてみました。 最終目標は独自のTrackをTimelineで再生をすることです。

ScriptPlayable を自作する

ScriptPlayableを作るにはPlayableBehaviourを継承してクラスを作成します。 では適当にPlayableを作ってみます。

public class CustomPlayable : PlayableBehaviour
{
    // PlayableGraph再生時
    public override void OnGraphStart(Playable playable)
    {
        Debug.Log("Graph Start");
    }

    // PlayableGraphストップ時
    public override void OnGraphStop(Playable playable)
    {
        Debug.Log("Graph Stop");
    }
}

これはPlayableGraphで使って見ます。

 _playableGraph = PlayableGraph.Create();
           
var customPlayable = ScriptPlayable<CustomPlayable>.Create(_playableGraph, 0);
        animationPlayableOutput.SetSourcePlayable(customPlayable);
var scriptOutput = ScriptPlayableOutput.Create(_playableGraph, "custom");
scriptOutput.SetSourcePlayable(customPlayable);
            
 _playableGraph.Play();

Unityで再生するとPlayableGraph Visualizerではこのように表示されています。 (デバックログも吐き出されています)

f:id:albatrus:20210708175742p:plain
PlayableGraph Visualizerの中身

ProcessFrame

PlayableBehaviourにProcessFrameというメソッドが定義されています。 PlayableGraph再生時の経過情報を受け取ることができます。

public override void ProcessFrame(Playable playable, FrameData info, object playerData)
{

}

FrameDataにはdeltaTimeなどの情報がありますのでこれを使うことで、何かしらのアニメーションを設定できたりできそうです。

Playableの時間を設定する

現状、Unity再生中にこのPlayableはずっと再生されています。 次に、Playableの再生時間を設定する方法を調べます。

public override void ProcessFrame(Playable playable, FrameData info, object playerData)
{
    var time = playable.GetTime();
    var duration = playable.GetDuration();
}

現在の経過時間はPlayableのGetTimeで取得でき、Playableの再生時間はGetDurationで取得ができます。 これを使い、必要な処理を行うことができます。

再生時間はPlayableのSetDurationで指定できます。

playable.SetDuration(1.0f);

ProcessPrameは経過時間を過ぎても呼び出し続けますので、もし止めたい場合には playable.Pause()を呼び出します。

 playable.Pause();

Timelineで使いたい

Playableについて少しわかってきたので、当初の目的であるTimelineで使えるようする方法が調べました。

blog.unity.com

必要なクラス

TImelineで用意するためには次の3つを表示できるクラスです。

  • Track
  • Playable
  • PlayableAsset (Clip)

f:id:albatrus:20210709150426p:plain
PlayableをTimelineで使うために必要な要素

f:id:albatrus:20210709151946p:plain:w300
編集のためのInspector

Playableを定義する

TImelineが再生されたときのClipの挙動をPlayableで作成されています。 今回はUGUIのImageの色を変更するできるように実装をしました。

public class CustomTimelineClipPlayable : PlayableBehaviour
{
    public Color StartColor = Color.white;
    public Color EndColor = Color.white;
    
    public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
        var image = playerData as Image;
        if (image != null)
        {
            var duration = playable.GetDuration();
            var time = playable.GetTime();
            image.color = Color.Lerp(StartColor, EndColor, (float) (time / duration));
        }
    }
}

Color.Lerpを使って色変化を実装しているのですが、もしかしたらもっと良い方法あるかもしれません。

PlayableAsset

次にTimeline上にClip表示と編集ができるようにPlayableAssetを作成します。 今回はImageの始値終値を設定できるようにしました。

[System.Serializable]
public class CustomTimeLinePlayableAsset : PlayableAsset
{
    public Color startColor = Color.white;
    public Color endColor = Color.white;

    // Factory method that generates a playable based on this asset
    public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
    {
        var playable = ScriptPlayable<CustomTimelineClipPlayable>.Create(graph);
        var behaviour = playable.GetBehaviour();

        // PlayableへInspectorでの設定値を渡しています。
        behaviour.StartColor = startColor;
        behaviour.EndColor = endColor;
        
        return playable;
    }
}

Trackを自作する

Timelineで使うTrackを作成します。

[TrackClipType(typeof(CustomTimeLinePlayableAsset))]
[TrackBindingType(typeof(Image))]
public class CustomTimelineTrack : TrackAsset
{
    
}

TrackBindingTypeで対象のImageを設定できるようにしています。

確認

これで準備完了です。 TimelineでTrackを作成するときに、新しく「CustomTimelineTrack」が選択できるようになっているはずです。

最後に

とりあえず、自作のPlayableをTimeline上で動かせるようになりました。 ただ、簡単なPlayableでしたので、今後はもう少し複雑なPlayableが作れるようにしたいないと思いました。