一般情况下,采用指针进行交互的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框框呢?将音效片段拖进去试试看吧。如果得法,你应该能听到按钮状态音效。
方法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检视面板