Unity扩展UGUI组件多态按钮MultimodeButton

Unity扩展UGUI组件多态按钮MultimodeButton

    • 需求描写
      • Button
      • Multimode Button
    • 项目实际使用效果图

需求描写

多态按钮,即按钮每触发一次就会切换一张按钮贴图,并触发一个切换事件。
这个逻辑并不复杂,有很多方式可以实现。这里记录一下,依托UGUI框架所实现的方式,使用时如同普通Button一样,会比较顺手。

Button

首先,因为我装载了VS的反编译工具,可以直接将UGUI的Button组件反编译出源码:

using System;
using System.Collections;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;

namespace UnityEngine.UI
{
    [AddComponentMenu("UI/Button", 30)]
    public class Button : Selectable, IPointerClickHandler, IEventSystemHandler, ISubmitHandler
    {
        [Serializable]
        public class ButtonClickedEvent : UnityEvent
        {
        }

        [FormerlySerializedAs("onClick")]
        [SerializeField]
        private ButtonClickedEvent m_OnClick = new ButtonClickedEvent();

        public ButtonClickedEvent onClick
        {
            get
            {
                return m_OnClick;
            }
            set
            {
                m_OnClick = value;
            }
        }

        protected Button()
        {
        }

        private void Press()
        {
            if (IsActive() && IsInteractable())
            {
                UISystemProfilerApi.AddMarker("Button.onClick", this);
                m_OnClick.Invoke();
            }
        }

        public virtual void OnPointerClick(PointerEventData eventData)
        {
            if (eventData.button == PointerEventData.InputButton.Left)
            {
                Press();
            }
        }

        public virtual void OnSubmit(BaseEventData eventData)
        {
            Press();
            if (IsActive() && IsInteractable())
            {
                DoStateTransition(SelectionState.Pressed, instant: false);
                StartCoroutine(OnFinishSubmit());
            }
        }

        private IEnumerator OnFinishSubmit()
        {
            float fadeTime = base.colors.fadeDuration;
            float elapsedTime = 0f;
            while (elapsedTime < fadeTime)
            {
                elapsedTime += Time.unscaledDeltaTime;
                yield return null;
            }

            DoStateTransition(base.currentSelectionState, instant: false);
        }
    }
}

我所要做的就是在原Button组件的基础上做些修改来达到效果。当然并不会修改源码,只是将反编译的代码复制一份到自己创建的脚本中,在根据自己的需求修改。

Multimode Button

下面就是经过我修改,达到需求的程序代码:

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
using UnityEngine.UI;

namespace my_code
{
    [RequireComponent(typeof(Image))]
    public class MultimodeButton : Selectable, IPointerClickHandler, IEventSystemHandler, ISubmitHandler
    {
        ///  所有状态图片 
        public Sprite[] m_stateSprites = new Sprite[2];

        ///  当前状态索引 
        public int CurrentIndex { get; private set; }

        [Serializable]
        public class MultimodeButtonClickedEvent : UnityEvent<int> { }

        [FormerlySerializedAs("onClick"), SerializeField]
        private MultimodeButtonClickedEvent m_OnClick = new MultimodeButtonClickedEvent();

        public MultimodeButtonClickedEvent onClick { get { return m_OnClick; } set { m_OnClick = value; } }

        protected MultimodeButton()
        {
            CurrentIndex = 0;
        }

        protected override void Awake()
        {
            transition = Transition.None;
        }

        ///  重置为初始状态 
        public void OnReset()
        {
            CurrentIndex = m_stateSprites.Length;
            Press();
        }

        private void Press()
        {
            if (IsActive() && IsInteractable())
            {
                UISystemProfilerApi.AddMarker("Button.onClick", this);
                if (++CurrentIndex >= m_stateSprites.Length) CurrentIndex = 0;//确认循环
                image.sprite = m_stateSprites[CurrentIndex];//image切换状态图片
                m_OnClick.Invoke(CurrentIndex);
            }
        }

        public virtual void OnPointerClick(PointerEventData eventData)
        {
            if (eventData.button == PointerEventData.InputButton.Left)
            {
                Press();
            }
        }

        public virtual void OnSubmit(BaseEventData eventData)
        {
            Press();
            if (IsActive() && IsInteractable())
            {
                DoStateTransition(SelectionState.Pressed, instant: false);
                StartCoroutine(OnFinishSubmit());
            }
        }

        private IEnumerator OnFinishSubmit()
        {
            float fadeTime = base.colors.fadeDuration;
            float elapsedTime = 0f;
            while (elapsedTime < fadeTime)
            {
                elapsedTime += Time.unscaledDeltaTime;
                yield return null;
            }

            DoStateTransition(base.currentSelectionState, instant: false);
        }
    }
}

两个代码相差不大,其中的逻辑应该很容易理解,这里只把几个比较重要的核心逻辑解释一下:

  • RequireComponent(typeof(Image))多态按钮因为要修改UI的贴图,所以Image是必须的;
  • m_stateSprites:多个状态贴图的存储数组;
  • CurrentIndex:当前状态在数组中的索引;
  • MultimodeButtonClickedEvent:按钮所使用的事件对象类,相比一般的Button,其实就是多了一个状态索引的参数,传入的就是CurrentIndex
  • transition = Transition.None;:个人习惯,通过拖拽到物体上使用时,就不用在手动设置了;
  • OnReset():一个重置函数,可以通过调用这个函数,将按钮重置回CurrentIndex = 0;的初始状态;
  • Press():与一般Button.Press()方法对比,就是多了个贴图循环切换的逻辑。

项目实际使用效果图

Unity扩展UGUI组件多态按钮MultimodeButton_第1张图片
Unity扩展UGUI组件多态按钮MultimodeButton_第2张图片
Unity扩展UGUI组件多态按钮MultimodeButton_第3张图片

你可能感兴趣的:(UGUI,unity,游戏引擎)