由一個美術(shù)需求引發(fā)的Custom Inspector

需求

  • Editor模式下,在運行或者非運行狀態(tài)下,能夠按照指定的變化率來自動改變material中屬性數(shù)值。

需求分析

  • 如何在Editor模式下獲得一個游戲?qū)ο蠹捌浣M件,尤其是在非運行狀態(tài)下?我們知道在Unity IDE運行起來后是很容易獲得一個對象和組件的,在GameObject上掛一個腳本即可。但是在非運行狀態(tài)下呢,transform.GetComponent這樣的方法怎么執(zhí)行?好在unity已經(jīng)為我們考慮到了這個問題,提供了[ExecuteInEditMode]Attribute,通過指定這個attribute使得組件類中的方法可以在edit模式下執(zhí)行,并且是在非運行狀態(tài)下的。

  • 如何在非運行狀態(tài)下勻速改變數(shù)值呢?update方法中配合Time.deltaTime是一個完美的方案,但是即使設(shè)置了[ExecuteInEditMode],update的表現(xiàn)在非運行和運行時也是完全不同的,查資料看到 is only called when something in the scene changed. 這句話時也有種吐槽的沖動。好在unity又為大家考慮到了這個問題(話說unity editor確實功能強大,AssetAtore里面那些插件真是厲害),Edit模式下提供了EditorApplication.update,這是一個事件,我們注冊一個自己的方法就可以在非運行狀態(tài)下實現(xiàn)update的功能。我個人比較推薦使用EditorCoroutine,一個基于EditorApplication.update的協(xié)程實現(xiàn)。

功能實現(xiàn)

  • 使用一個自定義組件來實現(xiàn)material中數(shù)值的修改,這個類在UI上要體現(xiàn)出能夠設(shè)置變化速率和初始值。并且在UI上通過點擊按鈕的形式來觸發(fā)改變。
  • 使用Custom Inspector來實現(xiàn)組件UI的自定義。
  • 在運行狀態(tài)下通過使用默認(rèn)的update來實現(xiàn)勻速變化,在非運行狀態(tài)下通過使用EditorCoroutine來實現(xiàn)。

代碼實現(xiàn)

using UnityEngine;
using System.Collections;
using UnityEditor;
public class UVAnimation : MonoBehaviour
{

    public Vector2 TilingSpeed = new Vector2(1, 1);
    public Vector2 OffsetSpeed = new Vector2(0.1f, 0.1f);

    public Vector2 Tiling = new Vector2(1, 1);
    public Vector2 Offset = new Vector2(0, 0);

    float rate = 0.02f;

    EditorCoroutine coroutineOffset;
    EditorCoroutine coroutineTiling;

    bool isOffset = false;
    bool isTiling = false;

    // Use this for initialization
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {

    }

    void FixedUpdate()
    {
        if (isOffset)
        {
            transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureOffset += OffsetSpeed * Time.deltaTime;
        }
        if (isTiling)
        {
            transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureScale += TilingSpeed * Time.deltaTime;
        }
    }

    public void ChangeOffset()
    {
        if (EditorApplication.isPlaying)
        {
            isOffset = true;
        }
        else
        {
            if (coroutineOffset != null)
            {
                coroutineOffset.stop();
            }
            coroutineOffset = EditorCoroutine.start(ChangeOffsetCoroutine());
        }

    }

    IEnumerator ChangeOffsetCoroutine()
    {
        while (true)
        {
            yield return new WaitForSeconds(rate);
            transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureOffset += OffsetSpeed * rate;
        }
    }

    public void ChangeTiling()
    {
        if (EditorApplication.isPlaying)
        {
            isTiling = true;
        }
        else
        {
            if (coroutineTiling != null)
            {
                coroutineTiling.stop();
            }
            coroutineTiling = EditorCoroutine.start(ChangeTilingCoroutine());
        }
    }

    IEnumerator ChangeTilingCoroutine()
    {
        while (true)
        {
            yield return new WaitForSeconds(rate);
            transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureScale += TilingSpeed * rate;
        }
    }

    public void SetOffset()
    {
        transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureOffset = Offset;
    }

    public void SetTiling()
    {
        transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureScale = Tiling;
    }

    public void Reset()
    {
        isOffset = false;
        isTiling = false;
        transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureScale = new Vector2(1, 1);
        transform.GetComponent<Renderer>().sharedMaterials[0].mainTextureOffset = new Vector2(0, 0);
        if (coroutineOffset != null)
        {
            coroutineOffset.stop();
        }
        if (coroutineTiling != null)
        {
            coroutineTiling.stop();
        }
    }
}

using UnityEngine;
using System.Collections;
using UnityEditor;

[CustomEditor(typeof(UVAnimation))]
public class UVAnimationBuilderEditor : Editor {


    public override void OnInspectorGUI ()
    {
       base.OnInspectorGUI ();
        //DrawDefaultInspector ();
        UVAnimation uva = (UVAnimation)target;

        if (GUI.changed) {
            uva.SetTiling ();
            uva.SetOffset ();
        }

        if (GUILayout.Button("Change Tiling")) {
            uva.ChangeTiling ();    
            EditorUtility.SetDirty (target);
        }

        if (GUILayout.Button("Change Offset")) {
            uva.ChangeOffset ();
        }

        if (GUILayout.Button("Reset")) {
            uva.Reset ();
        }
    }
}

代碼解析

  • [CustomEditor(typeof(UVAnimation))]為UVAnimation創(chuàng)建的Editor類,在這個類里面可以修改UVAnimation類的UI,可以調(diào)用UVAnimation類中的方法。

  • OnInspectorGUI方法,顧名思義在里面可以對UI進(jìn)行編程,注意一下這個方法會自己生產(chǎn)一句代碼base.OnInspectorGUI ();,我所注釋掉的DrawDefaultInspector ();這句代碼都是用來繪制默認(rèn)UI的,二者只可留其一。

  • transform.GetComponent<Renderer>().sharedMaterials在edit模式下獲取材質(zhì)球的對象需要用sharedMaterials。

  • mainTextureScale對應(yīng)的就是UI上的Tiling。命名這讓人吐槽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容