うにてぃブログ

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

【Unity】演出を Animator じゃなくて Inspector で設定するツール ~2~

【Unity】演出を Animator じゃなくて Inspector で設定するツール ~1~ - うにてぃブログ

の記事の続きです

スクリプトでの制御

各Sequence は ComponentTween クラス が管理するようになっているので

登録したIDを指定して

ComponentTween.Stop("ID");

で停止したり

ComponentTween.Play("ID");

で再生できます

終了時に処理を呼び出す

public event CompleteDelegate CompleteEvent;

終了時のイベントように上記が定義してるので、こちらにイベントを登録しておけば終了時に呼び出してくれます

しかし Loop するような設定をしていると呼び出されないので注意してください

Module の追加

ModuleAbstract を継承したクラスを作成すれば自動的に Inspector の一覧にも表示されます

例えば RectTransform のモジュールを作る場合は RectTransformModule を作成し

   [Serializable]
    public abstract class RectTransformModule : ModuleAbstract
    {
        [NonSerialized]
        protected RectTransform[] Components;

        protected override int GetComponent(GameObject[] objs)
        {
            Components = GetComponentsToArray<RectTransform>(objs);
            return Components.Length;
        }
    }

RectTransform の位置を制御するための RectTransformPositionRectTransformModule を継承して作成します

その後パラメータとして扱う型を ParamType に設定し

GetValue で値の取得処理 SetValue で値の設定処理を書くだけです

   [Serializable]
    public class RectTransformPosition : RectTransformModule
    {
        public override Type ParamType => typeof(Vector2);
 
        protected override Vector4[] GetValue()
        {
            return Components.Select(c => TweenValue.Vector2ToVector4(c.anchoredPosition))
                .ToArray();
        }
 
        protected override void SetValue(TweenValue[] values)
        {
            for (var i = 0; i < values.Length; i++)
                Components[i].anchoredPosition = values[i].GetVector2();
        }
    }

【Unity】演出を Animator じゃなくて Inspector で設定するツール ~1~

Animator が エンジニア的には使いづらく、UIの動きを DoTween 等を利用してコードで作成するのは調整が面倒
※ 有料だったらあったような気もする

そのため、Inspector 上でパラメータをセットするとそれに合わせて動くツールを作成しました
一応拡張性もあるように作成しています

Component Tween Sequence

github.com

f:id:hacchi_man:20201004022746p:plain:w300

使い方

GameObject に Component Tween Sequence を追加

f:id:hacchi_man:20201004023116p:plain:w200

Sequence 横の + を押して 動作を追加

f:id:hacchi_man:20201004023502p:plain:w300

Start (開始タイミング)Length(動きの時間)を決めて

動作の対象を何にするか Module を選択する
※ 今回はTransform の 位置を変更するため TransformPosition を選択

f:id:hacchi_man:20201004023618p:plain:w300

Being (開始値)End(終了値)を設定し

特定の値を固定したい場合は Lock にチェックを入れる

f:id:hacchi_man:20201004023815p:plain:w300

もし現在の位置から相対的に動作させたい場合は IsRelative にチェックを入れる

Being から End の値の変動は Easing を 利用しているため 好きな Easing を選択 ※ 下に Animation Curveがあるように内部的にはこちらで計算している

f:id:hacchi_man:20201004023919p:plain:w300

最後に 操作対象となる TargetObjects をセットする

今回は Cube を作成しセットした

f:id:hacchi_man:20201004024042p:plain:w300

これで上部のPlay を押すか Editor を再生することで動きます

f:id:hacchi_man:20201004032538g:plain




他の詳細は別記事になります

【C#】複数のフラグを確認する

例えば フラグ判定で、そのビットが立っているかどうかを判定する際に HasFlag を利用する

   [Flags]
    public enum Test
    {
        A = 1,
        B = 2,
    }

    private void Main()
    {
        var flag = Test.A;
        flag.HasFlag(Test.A);
    }

しかし 複数のフラグを判定する場合は HasFlag を必要分だけ記述する必要がある

   [Flags]
    public enum Test
    {
        A = 1,
        B = 2,
        C = 4,
    }

    private void Main()
    {
        var flag = Test.A | Test.B;
        if ()
        {
            
        }
    }

それだと面倒なので、まとめて判定をできるような拡張メソッドを作成

using System;

public static class EnumExtension
{
    public static bool HasFlags(this Enum self, params Enum[] flags)
    {
        foreach (var flag in flags)
            if (self.HasFlag(flag))
                return true;
        return false;
    }
}

これを使うと 下記のように変換でき数が多くても長くならない

flag.HasFlag(Test.A) || flag.HasFlag(Test.B)
↓
flag.HasFlags(Test.A, Test.B)

【Unity】 選択したアセットのパスを取得する

f:id:hacchi_man:20201001181257p:plain:w300

ProjectWindow で右クリックで出てくる CopyPath を選択するとそのアセットのパスを取得することができます

あとはどこかでペーストすれば クリップボードに保存されているアセットのパスがペーストされます

特に使わない気がしたのですが、フルパスを取得するにはどうするんだろうと思い作成してみました

using UnityEditor;
using UnityEngine;

public static class Utility
{
    [MenuItem("Assets/Copy Full Path")]
    public static void CopyAssetPath()
    {
        var guids = Selection.assetGUIDs;
        if (guids.Length <= 0)
            return;
 
        var fullPathEnv = Application.dataPath.Replace("Assets", AssetDatabase.GUIDToAssetPath(guids[0]));
        var fullPath = fullPathEnv.Replace('/', System.IO.Path.DirectorySeparatorChar);
        GUIUtility.systemCopyBuffer = fullPath;
    }
}

【Unity】クリップボードへアクセスする

Unity で クリップボード 関連の機能を作りたかったので探していると
GUIUtility.systemCopyBuffer を使えばクリップボードの操作が可能そうでした

GUIUtility-systemCopyBuffer - Unity スクリプトリファレンス

// クリップボードから取得
var clipboard =  GUIUtility.systemCopyBuffer;
 
// クリップボードへ設定
GUIUtility.systemCopyBuffer = "Clipboard";

【Unity】UnityWebRequest で ファイルを保存する方法

UnityWebRequest でファイルを保存するには request.downloadHandler = new DownloadHandlerFile(savePath); を指定する

ロードする前にファイルのチェック処理を書かないと再度ロードされてしまうので、ちゃんとチェック処理を書きましょう

using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using System.IO;
 
public class SampleMonoBehaviour : MonoBehaviour
{
    [SerializeField]
    private SpriteRenderer _sprite;
 
    private const string URI = "https://1.bp.blogspot.com/-tWP38QNcn04/X1CK4cXnvjI/AAAAAAABavY/W2xyveWsZCggkTecEC_tEjaBBhCTUmXkQCNcBGAsYHQ/s400/daidougei_cigar_box_woman.png";
 
    private IEnumerator Start()
    {
        var saveRoot = Path.Combine(Application.temporaryCachePath, "Cache");
        var savePath = Path.Combine(saveRoot, "test.png");
 
        yield return LoadAndSaveTexture(URI, savePath);
 
        _sprite.sprite = GetTexture(savePath);
    }
 
    /// <summary>
    /// キャッシュからテクスチャをロード
    /// </summary>
    private Sprite GetTexture(string savePath)
    {
        // ファイルがなければ null
        if (!File.Exists(savePath))
            return null;
 
        // 保存してあるテクスチャのロード
        var texture = new Texture2D(0, 0);
        texture.LoadImage(File.ReadAllBytes(savePath));

        // Sprite に変換
        return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
    }
 
    /// <summary>
    /// ファイルをロード
    /// ファイルがあればロードしない
    /// </summary>
    private IEnumerator LoadAndSaveTexture(string uri, string savePath)
    {
        // ファイルがあるので終了
        if (Directory.Exists(savePath))
            yield break;
 
        var dir = Path.GetDirectoryName(savePath);
        // ディレクトリがなければ作成する
        if (!Directory.Exists(dir))
            Directory.CreateDirectory(dir);
 
        using (var request = UnityWebRequestTexture.GetTexture(uri))
        {
            request.disposeUploadHandlerOnDispose = false;
            // ファイルを保存
            request.downloadHandler = new DownloadHandlerFile(savePath);

            yield return request.SendWebRequest();

            if (request.isHttpError || request.isNetworkError)
                Debug.LogError(request.error);
        }
    }
}

【Unity】Reveal In Finder / Show in Explorer をスクリプトから呼び出す

アセットを右クリックした際に Reveal In Finder / Show in Explorer を選べば ファイラーが開きます

f:id:hacchi_man:20200924000130p:plain:w200

これをスクリプトから呼び出したい場合は EditorUtility.RevealInFinder を利用する

ファイルを指定した場合は ファイルを選択した状態でファイラーを開けますが
ディレクトリを指定した場合は親ディレクトリが選択した状態でファイラーが開いてしまいます

// ルートからのパス と Assets からのパス 両方指定できる
EditorUtility.RevealInFinder(Application.temporaryCachePath);
EditorUtility.RevealInFinder("Assets/");
 
// Assets の親ディレクトリを選択した状態で開く
EditorUtility.RevealInFinder("Assets/");
 
// Sample.unity ファイルが選択状態で開く
EditorUtility.RevealInFinder("Assets/Sample.unity");