马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?注册帐号
x
本帖最后由 zhiyuan 于 2018-7-16 17:00 编辑
没事没事我这不是来了嘛!上篇文章已经给大家对比了一下iTween和DoTween的编码思想区别,当然我是力挺DoTween的咯!
大家平时做项目百分之60乃至70的时间都在写基础且无逻辑的代码!
那为什么我们不把这些常用的代码或者说模块改造成链式编程的模式囊? 怎么改? 让我慢慢道来~~
1).工欲善其事,必先利其器
其实.net已经为我们提供了一个改造代码的好帮手了 -- 扩展方法
来一下下面的代码
[AppleScript] 纯文本查看 复制代码 //获取音频组件并播放
gameObject.GetComponent<AudioSource>().Play();
貌似没什么问题,但是如果我现在提出需求要换一个clip再播放该怎么办?你会说简单啊![C#] 纯文本查看 复制代码 AudioSource audioSource = gameObject.GetComponent<AudioSource>();
//更换clip
audioSource.clip = 我是clip;
//获取音频组件并播放
audioSource.Play(); 貌似有点麻烦了!我们想要的效果是audioSource.SetClip(xxx).play()那应该怎么做囊?
我们可以利用扩展方法的特性:使你能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用举个例子
[C#] 纯文本查看 复制代码 /// <summary>
/// 创建一个扩展测试类 注意!扩展方法必须是静态的所以类也必须是静态
/// </summary>
public static class TestExtend
{
/// <summary>
/// 一个静态的扩展方法
/// </summary>
/// <param name="audioSource">主要要用this关键字标注第一个参数,也就是你要扩展的类是哪个</param>
public static void DebugClip(this AudioSource audioSource)
{
Debug.Log(audioSource.clip);
}
} 拿我们如何使用它?看下面的使用代码
我们发现我们方法的第一个参数可以不用传,并且我们AudioSource的类多了一个我们自定义的方法。下面是运行图
到此我们已经给AudioSource 添加了一个方法,那如何实现audioSource.DebugClip().DebugClip() 这样,像一个链条 一个一个接下去囊?
看代码:
[C#] 纯文本查看 复制代码 /// <summary>
/// 创建一个扩展测试类 注意!扩展方法必须是静态的所以类也必须是静态
/// </summary>
public static class TestExtend
{
/// <summary>
/// 一个静态的扩展方法
/// </summary>
/// <param name="audioSource">主要要用this关键字标注第一个参数,也就是你要扩展的类是哪个</param>
/// <returns>我们只需要把要扩展的类进行返回就可以了</returns>
public static AudioSource DebugClip(this AudioSource audioSource)
{
Debug.Log(audioSource.clip);
//返回扩展的类
return audioSource;
}
}
使用方法 audioSource.DebugClip().DebugClip(); 当然如果你想
我们看运行结果:
运行了5遍 没问题,到此我们知道了我们的工具,也就是实现的方式! 下面我们就去做一个实用的例子。
2).音频播放器的改造
我们往往会遇到这种场景 1.我们要想要知道音频什么时候播放完成。 2.我们想要在指定的音频播放中的某个时间或帧中运行自己的一个方法。
我们先来分析一下这两个场景会有的解决方案 1.利用协程计时器(因为我们可以拿到音频总长度) 2.Update(可以利用unity生命周期)
我们最后选择第2中方式 Update(可以利用unity生命周期) 个人认为协程不是最好的方式原因在于 协程的消耗太大(我们要暂停播放的话还要关闭协程)
下面就请各位跟着我的思路 和我一起书写一个强大的音频扩展组件
根据需求定义大体方法:
OnUpdate
OnComplete
我们主要实现以上两个方法
当先实现扩展类之前我们要先实现一个驱动器AudioEventDriver,用来驱动Update
先贴出这个类的代码 然后慢慢解释
[C#] 纯文本查看 复制代码 /// <summary>
/// 委托定义
/// </summary>
/// <param name="Percentage">百分比</param>
public delegate void OnUpdateEventHandler(float Percentage);
public delegate void OnCompleteEventHandler();
/// <summary>
/// 委托实例
/// </summary>
public AudioEventDriver.OnUpdateEventHandler onUpdate = null;
public AudioEventDriver.OnCompleteEventHandler onComplete = null;
private AudioSource audioSource = null;
/// <summary>
/// OnUpdate 驱动方法
/// </summary>
/// <param name="audioSource_"></param>
/// <param name="onUpdateEventHandler"></param>
public void OnUpdate(AudioSource audioSource_, AudioEventDriver.OnUpdateEventHandler onUpdateEventHandler)
{
onUpdate = onUpdateEventHandler;
audioSource = audioSource_;
}
public void OnComplete(AudioSource audioSource_, AudioEventDriver.OnCompleteEventHandler onCompleteEventHandler)
{
audioSource = audioSource_;
onComplete = onCompleteEventHandler;
}
private void Update()
{
//OnUpdate 驱动
if (onUpdate != null && audioSource != null)
{
if (audioSource.isPlaying)
{
onUpdate(audioSource.time / audioSource.clip.length);
}
}
//OnComplete 驱动
if (audioSource.time == audioSource.clip.length)
{
onComplete();
}
}
} 我们可以看出我们写了两个事件委托分别取承接OnUpdate中用户的方法和OnComplete中用户的方法。
然后在Update中去分别调用者两个驱动事件。ok我们该怎么用这个驱动器类囊? 看下面的代码
我们首先先写一个静态的AudioExtend类
然后在其中书写方法GetEventDriver方法,这个方法是一个静态的
[C#] 纯文本查看 复制代码 /// <summary>
/// 获取音频事件驱动
/// </summary>
/// <param name="audioSource"></param>
/// <returns></returns>
private static AudioEventDriver GetEventDriver(this AudioSource audioSource)
{
AudioEventDriver AudioEventDriver = audioSource.gameObject.GetComponent<AudioEventDriver>();
if (AudioEventDriver == null)
{
AudioEventDriver = audioSource.gameObject.AddComponent<AudioEventDriver>();
}
return AudioEventDriver;
}
上面的实现逻辑很简单 就是有这个驱动就获取 没有就添加并获取。这里相信各位都能理解!
然后我们去实现关键的两个方法OnUpdate扩展方法和OnComplete扩展方法
[C#] 纯文本查看 复制代码 /// <summary>
/// 音频播放中回调
/// </summary>
/// <param name="audioSource"></param>
/// <param name="onUpdateEventHandler"></param>
/// <returns></returns>
public static AudioSource OnUpdate(this AudioSource audioSource, AudioEventDriver.OnUpdateEventHandler onUpdateEventHandler)
{
GetEventDriver(audioSource).OnUpdate(audioSource, onUpdateEventHandler);
return audioSource;
}
/// <summary>
/// 音频播放完成回调
/// </summary>
/// <param name="audioSource"></param>
/// <param name="onUpdateEventHandler"></param>
/// <returns></returns>
public static AudioSource OnComplete(this AudioSource audioSource, AudioEventDriver.OnCompleteEventHandler onCompleteEventHandler)
{
GetEventDriver(audioSource).OnComplete(audioSource, onCompleteEventHandler);
return audioSource;
}
这两个扩展方法只是去调用了一下我们私有的GetEventDriver这个方法会返回驱动类,然后调用驱动类的OnUpdate和OnComplete(注意这里不要搞错了哦)
然后传入一个事件 其实就是传给了GetEventDriver类中,然后驱动类就开始运作了,直到音频播放中或完成就会调用用户传入的事件
ok怎么用囊?
[C#] 纯文本查看 复制代码 audioSource
.OnUpdate((v) =>
{
Debug.Log("播放进度:" + v);
})
.OnComplete(() => {
Debug.Log("播放完成咯!");
})
.Play();
下面放上完整的扩展类代码 供大家参考
[C#] 纯文本查看 复制代码 public static class AudioExtend
{
/// <summary>
/// 获得一个音频播放器
/// </summary>
/// <param name="gameObject"></param>
/// <returns></returns>
public static AudioSource GetAudio(this GameObject gameObject, bool add = false)
{
AudioSource audio = null;
if (!add)
{
audio = gameObject.GetComponent<AudioSource>();
if (audio == null)
{
audio = gameObject.AddComponent<AudioSource>();
}
}
if (add)
{
audio = gameObject.AddComponent<AudioSource>();
}
return audio;
}
/// <summary>
/// 设置Clip
/// </summary>
/// <param name="audioSource"></param>
/// <returns></returns>
public static AudioSource SetClip(this AudioSource audioSource, AudioClip clip)
{
if (clip)
{
audioSource.clip = clip;
}
return audioSource;
}
/// <summary>
/// 获取音频事件驱动
/// </summary>
/// <param name="audioSource"></param>
/// <returns></returns>
private static AudioEventDriver GetEventDriver(this AudioSource audioSource)
{
AudioEventDriver AudioEventDriver = audioSource.gameObject.GetComponent<AudioEventDriver>();
if (AudioEventDriver == null)
{
AudioEventDriver = audioSource.gameObject.AddComponent<AudioEventDriver>();
}
return AudioEventDriver;
}
/// <summary>
/// 音频播放中回调
/// </summary>
/// <param name="audioSource"></param>
/// <param name="onUpdateEventHandler"></param>
/// <returns></returns>
public static AudioSource OnUpdate(this AudioSource audioSource, AudioEventDriver.OnUpdateEventHandler onUpdateEventHandler)
{
GetEventDriver(audioSource).OnUpdate(audioSource, onUpdateEventHandler);
return audioSource;
}
/// <summary>
/// 音频播放完成回调
/// </summary>
/// <param name="audioSource"></param>
/// <param name="onUpdateEventHandler"></param>
/// <returns></returns>
public static AudioSource OnComplete(this AudioSource audioSource, AudioEventDriver.OnCompleteEventHandler onCompleteEventHandler)
{
GetEventDriver(audioSource).OnComplete(audioSource, onCompleteEventHandler);
return audioSource;
}
}
/// <summary>
/// 音频事件驱动器
/// </summary>
public class AudioEventDriver : MonoBehaviour
{
/// <summary>
/// 委托定义
/// </summary>
/// <param name="Percentage">百分比</param>
public delegate void OnUpdateEventHandler(float Percentage);
public delegate void OnCompleteEventHandler();
/// <summary>
/// 委托实例
/// </summary>
public AudioEventDriver.OnUpdateEventHandler onUpdate = null;
public AudioEventDriver.OnCompleteEventHandler onComplete = null;
private AudioSource audioSource = null;
/// <summary>
/// OnUpdate 驱动方法
/// </summary>
/// <param name="audioSource_"></param>
/// <param name="onUpdateEventHandler"></param>
public void OnUpdate(AudioSource audioSource_, AudioEventDriver.OnUpdateEventHandler onUpdateEventHandler)
{
onUpdate = onUpdateEventHandler;
audioSource = audioSource_;
}
public void OnComplete(AudioSource audioSource_, AudioEventDriver.OnCompleteEventHandler onCompleteEventHandler)
{
audioSource = audioSource_;
onComplete = onCompleteEventHandler;
}
private void Update()
{
//OnUpdate 驱动
if (onUpdate != null && audioSource != null)
{
if (audioSource.isPlaying)
{
onUpdate(audioSource.time / audioSource.clip.length);
}
}
//OnComplete 驱动
if (audioSource.time == audioSource.clip.length)
{
onComplete();
}
}
} 这种方式 我形容为驱动器方式, 好了期待下一节吧!全部帖子
http://www.manew.com/forum-47-497-1.html
|