一般情况下,采用指针进行交互的UI有三种交互状态,分别为指针进入(Enter)、指针点击(Click)、指针退出(Exit),UGUI中的按钮就是一个很好的例子。最近有个需求是给按钮添加三种状态的音效,我通过两种方式实现了这个效果:第一种方法是重写Button(按钮)组件,第二种方法是实现EventSystems对应接口。

方法一:重写Button组件

优点:仅需挂载一个脚本
缺点:通用性不强,其他UI元素无法使用,并且需要多写一个编辑器脚本。

1.继承并重写Button脚本

创建一个ButtonWithAudio脚本,并继承自UGUI Button类,代码如下所示。

using UnityEngine.UI;
public class ButtonWithAudio : Button {

}

声明三个公共字段用来拖入三段状态音,声明一个AudioSource引用,用来播放声音。

    public AudioClip enterClip;
    public AudioClip clickClip;
    public AudioClip exitClip;
    AudioSource m_AudioSource;

重写对应的UI回调方法。

protected override void Start()
{
    base.Start();
    m_AudioSource = this.transform.parent.GetComponent<AudioSource>();
    if (m_AudioSource == null)
    {
        m_AudioSource = this.transform.parent.gameObject.AddComponent<AudioSource>();
        m_AudioSource.playOnAwake = false;
    }
}
//指针移入
public override void OnPointerEnter(PointerEventData eventData)
{
    base.OnPointerEnter(eventData);
    this.PlayAudio(this.enterClip);
}
//指针退出
public override void OnPointerExit(PointerEventData eventData)
{
    base.OnPointerExit(eventData);
    this.PlayAudio(this.exitClip);
}
//指针按下
public override void OnPointerDown(PointerEventData eventData)
{
    base.OnPointerDown(eventData);
    this.PlayAudio(this.clickClip);
}
//播放声音
private void PlayAudio(AudioClip ac)
{
    if(ac == null){
        //Debug.LogError(this.name + ":audioClip is Null !");
    }
    this.m_AudioSource.PlayOneShot(ac);
}

2.创建Editor脚本

保存并挂载上面的脚本后,你会发现属性面板上并没有出现自定义字段,难道我们就此GG了吗?不是的,Google一下,我在Unity论坛找到了这个回答

Yes you can. You need to create a custom inspector for the given class, and override OnInspectorGUI(). There you can add your custom GUI code and finish off with DrawDefaultInspector().

结合这篇文章,我写了一个Editor脚本,名称为ButtonWithAudioEditor。Editor脚本需要放置在名为Editor文件夹下,此文件夹的位置没有硬性要求。

using UnityEditor;
using UnityEditor.UI;
[CustomEditor(typeof(ButtonWithAudio))]
[CanEditMultipleObjects]
public class ButtonWithAudioEditor : ButtonEditor
{
    private SerializedObject obj;
    private SerializedProperty enterClip;
    private SerializedProperty clickClip;
    private SerializedProperty exitClip;

    protected override void OnEnable()
    {
        base.OnEnable();
        obj = new SerializedObject(target);
        enterClip = obj.FindProperty("enterClip");
        clickClip = obj.FindProperty("clickClip");
        exitClip = obj.FindProperty("exitClip");
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        obj.Update();
        EditorGUILayout.PropertyField(enterClip);
        EditorGUILayout.PropertyField(clickClip);
        EditorGUILayout.PropertyField(exitClip);
        obj.ApplyModifiedProperties();
    }
}

等待脚本编译完成,回到ButtonWithAudio属性面板看看,是不是已经出现三个AudioClip框框呢?将音效片段拖进去试试看吧。如果得法,你应该能听到按钮状态音效。
UGUI按钮图片

方法2:实现EventSystems接口

优点:基本上所有UI都可使用,且只写一个脚本
缺点:需要给UI多挂载一个脚本

1.创建脚本

创建一个脚本,名为UIEventWithAudio(无所谓),继承自Mono,并实现IPointerEnterHandler,IPointerExitHandler,IPointerClickHandler三个接口,代码如下所示:

using UnityEngine.EventSystems;
public class ButtonEventWithAudio:MonoBehaviour,IPointerEnterHandler,IPointerExitHandler,IPointerClickHandler {

}

2.实现接口方法

结构与1中相同,介绍看代码注释。

public AudioClip enterClip;
public AudioClip clickClip;
public AudioClip exitClip;

protected AudioSource m_AudioSource;
// Use this for initialization
void Start()
{
    m_AudioSource = this.transform.parent.GetComponent<AudioSource>();
    if (m_AudioSource == null)
    {
        m_AudioSource = this.transform.parent.gameObject.AddComponent<AudioSource>();
        m_AudioSource.playOnAwake = false;
    }
}
//点击
public void OnPointerClick(PointerEventData eventData)
{
    this.PlayAudio(this.clickClip);
}
//进入
public void OnPointerEnter(PointerEventData eventData)
{
    this.PlayAudio(this.enterClip);
}
//退出
public void OnPointerExit(PointerEventData eventData)
{
    this.PlayAudio(this.exitClip);
}
//播放音乐
private void PlayAudio(AudioClip ac)
{
    if(ac == null){
        //Debug.LogError(this.name + ":audioClip is Null !");
    }
    this.m_AudioSource.PlayOneShot(ac);
}

保存后,将该脚本挂载在任意的UI元素上,拖入音效后用鼠标点击试试看吧。

工程下载

这里提供一个测试Demo,其场景内有一个Button与一张图片,分别用上面的两种方法实现状态音效。

引用资料

1、[头图]【Unity】Unity-Japan UnityChanSD角色
1、[文章]【cnblogs】斯芬克斯 自定义Inspector检视面板

我来吐槽

*

*

4位绅士参与评论

  1. 蝉時雨07-17 09:09 回复

    阿梓喵是做游戏的么 这是什么语言
    看不懂看不懂

    • hk07-23 21:43 回复

      CocosCreator js语言 👿

  2. LingC07-16 18:27 回复

    测试打字

  3. 喵咪07-13 00:41 回复

    测试访客图片
    ceshi

  4. 野兔07-13 00:25 回复

    测试图片图片测试