游戏蛮牛学习群(纯技术交流,不闲聊):539178957
游戏蛮牛 手机端
开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:2258

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 1395|回复: 108

[志远] 大话链式编程之Audio改造术(二)

  [复制链接]  [移动端链接]
排名
9838
昨日变化
10

3

主题

129

帖子

598

积分

Rank: 9Rank: 9Rank: 9

UID
21402
好友
1
蛮牛币
164
威望
0
注册时间
2014-4-14
在线时间
247 小时
最后登录
2018-7-16

认证开发者

发表于 2018-7-6 11:58:11 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

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);
    }
}
拿我们如何使用它?看下面的使用代码
1.png


我们发现我们方法的第一个参数可以不用传,并且我们AudioSource的类多了一个我们自定义的方法。下面是运行图

1.png 1.png
到此我们已经给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(); 当然如果你想 1.png
我们看运行结果:
1.png 运行了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();



下面放上完整的扩展类代码 供大家参考
游客,如果您要查看本帖隐藏内容请回复
这种方式 我形容为驱动器方式, 好了期待下一节吧!全部帖子
http://www.manew.com/forum-47-497-1.html



评分

参与人数 11鲜花 +40 收起 理由
kckbkckb2 + 5 很给力!
yanis + 5 很给力!
Mrwang86 + 5 很给力!
QQAQ + 5 很给力!
LeoOS + 5
asai8diao2410 + 5 很给力!
雨落随风 + 2 赞一个!
luwenwan666 + 2 很给力!
bce + 2 赞一个!
lilybeast + 2 很给力!
uselessShadow + 2 神马都是浮云

查看全部评分


回复

使用道具 举报

排名
9838
昨日变化
10

3

主题

129

帖子

598

积分

Rank: 9Rank: 9Rank: 9

UID
21402
好友
1
蛮牛币
164
威望
0
注册时间
2014-4-14
在线时间
247 小时
最后登录
2018-7-16

认证开发者

 楼主| 发表于 2018-7-9 20:49:10 | 显示全部楼层
fd578 发表于 2018-7-9 19:41
GetEventDriver里的GetComponent在OnUpdate?
还有为什么用的扩展方法this却用了普通的函数调用方法? ...

OnUpdate 是扩展方法 用户调用一次就只执行一次儿哟  调用普通方法是因为我们需要unity的Update生命周期,这里OnUpdate只是用来让用户传递委托的,不是真正的Update,真正的Update在我们的驱动器里,是不是很神奇,下一篇文章马上写好了,主要是再做一个实例 以及做一点有趣的实验

回复 支持 反对

使用道具 举报

3偶尔光临
252/300
排名
8248
昨日变化
82

2

主题

25

帖子

252

积分

Rank: 3Rank: 3Rank: 3

UID
253227
好友
0
蛮牛币
511
威望
0
注册时间
2017-11-8
在线时间
93 小时
最后登录
2018-7-17
发表于 2018-7-6 13:56:13 | 显示全部楼层
卢本伟,牛逼!

回复

使用道具 举报

7日久生情
2765/5000
排名
387
昨日变化

1

主题

356

帖子

2765

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
2219
好友
1
蛮牛币
7342
威望
0
注册时间
2013-8-19
在线时间
856 小时
最后登录
2018-7-16
发表于 2018-7-6 14:23:55 | 显示全部楼层
牛逼!没事没事我这不是来了嘛!

回复 支持 反对

使用道具 举报

5熟悉之中
916/1000
排名
3108
昨日变化
1

0

主题

119

帖子

916

积分

Rank: 5Rank: 5

UID
160175
好友
0
蛮牛币
788
威望
0
注册时间
2016-8-2
在线时间
373 小时
最后登录
2018-7-13
发表于 2018-7-6 14:24:34 | 显示全部楼层
6666666666666666666666666

回复 支持 反对

使用道具 举报

2初来乍到
116/150
排名
13206
昨日变化
242

0

主题

6

帖子

116

积分

Rank: 2Rank: 2

UID
251989
好友
0
蛮牛币
102
威望
0
注册时间
2017-11-1
在线时间
50 小时
最后登录
2018-7-17

一贫如洗

发表于 2018-7-6 14:54:18 | 显示全部楼层
看看大佬的代码
[发帖际遇]: 一个袋子砸在了 hell425 头上,hell425 赚了 1 蛮牛币. 幸运榜 / 衰神榜

回复

使用道具 举报

3偶尔光临
202/300
排名
10435
昨日变化
5

0

主题

16

帖子

202

积分

Rank: 3Rank: 3Rank: 3

UID
182254
好友
0
蛮牛币
185
威望
0
注册时间
2016-11-9
在线时间
97 小时
最后登录
2018-7-16
QQ
发表于 2018-7-6 15:03:00 | 显示全部楼层
或许这就是我和大佬的区别吧

回复 支持 反对

使用道具 举报

6蛮牛粉丝
1382/1500
排名
1411
昨日变化
1

3

主题

107

帖子

1382

积分

Rank: 6Rank: 6Rank: 6

UID
80787
好友
1
蛮牛币
1861
威望
0
注册时间
2015-3-17
在线时间
464 小时
最后登录
2018-7-13
QQ
发表于 2018-7-6 16:48:57 | 显示全部楼层
厉害,学到了,如果能完成整个引擎的改造,需要有巨大量的静态函数,是不是应该考虑放个项目到github上面?
[发帖际遇]: goodboy3 在网吧通宵,花了 3 蛮牛币. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

6蛮牛粉丝
1064/1500
排名
1934
昨日变化
1

1

主题

24

帖子

1064

积分

Rank: 6Rank: 6Rank: 6

UID
84554
好友
1
蛮牛币
1409
威望
0
注册时间
2015-3-25
在线时间
403 小时
最后登录
2018-7-12
发表于 2018-7-6 17:24:39 | 显示全部楼层
谢谢楼主分享!!!!

回复

使用道具 举报

7日久生情
1794/5000
排名
862
昨日变化

0

主题

110

帖子

1794

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
56231
好友
1
蛮牛币
979
威望
0
注册时间
2014-11-18
在线时间
614 小时
最后登录
2018-7-16
QQ
发表于 2018-7-6 17:46:39 | 显示全部楼层
谢谢楼主分享!!!!

回复

使用道具 举报

排名
44617
昨日变化
27

0

主题

1

帖子

19

积分

Rank: 1

UID
276097
好友
0
蛮牛币
46
威望
0
注册时间
2018-4-8
在线时间
15 小时
最后登录
2018-7-13
QQ
发表于 2018-7-6 17:53:52 | 显示全部楼层
学到了

回复

使用道具 举报

排名
9838
昨日变化
10

3

主题

129

帖子

598

积分

Rank: 9Rank: 9Rank: 9

UID
21402
好友
1
蛮牛币
164
威望
0
注册时间
2014-4-14
在线时间
247 小时
最后登录
2018-7-16

认证开发者

 楼主| 发表于 2018-7-6 18:51:09 | 显示全部楼层
goodboy3 发表于 2018-7-6 16:48
厉害,学到了,如果能完成整个引擎的改造,需要有巨大量的静态函数,是不是应该考虑放个项目到github上面? ...

后面会讲非静态链式

回复 支持 反对

使用道具 举报

5熟悉之中
859/1000
排名
2951
昨日变化
5

1

主题

144

帖子

859

积分

Rank: 5Rank: 5

UID
194381
好友
0
蛮牛币
1852
威望
0
注册时间
2016-12-31
在线时间
276 小时
最后登录
2018-7-16
发表于 2018-7-6 21:31:54 | 显示全部楼层
受教了!
[发帖际遇]: Smilexs 在网吧通宵,花了 1 蛮牛币. 幸运榜 / 衰神榜

回复

使用道具 举报

7日久生情
2039/5000
排名
1035
昨日变化
3

0

主题

212

帖子

2039

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
147766
好友
0
蛮牛币
476
威望
0
注册时间
2016-5-6
在线时间
849 小时
最后登录
2018-7-17
QQ
发表于 2018-7-7 09:06:27 | 显示全部楼层
学习学习

回复

使用道具 举报

5熟悉之中
572/1000
排名
5136
昨日变化
5

2

主题

105

帖子

572

积分

Rank: 5Rank: 5

UID
252095
好友
1
蛮牛币
527
威望
0
注册时间
2017-11-2
在线时间
215 小时
最后登录
2018-7-17
发表于 2018-7-7 09:43:01 | 显示全部楼层
感谢大神的我还需要努力

回复 支持 反对

使用道具 举报

3偶尔光临
290/300
排名
7520
昨日变化
9

2

主题

37

帖子

290

积分

Rank: 3Rank: 3Rank: 3

UID
70743
好友
0
蛮牛币
211
威望
0
注册时间
2015-1-23
在线时间
101 小时
最后登录
2018-7-16
发表于 2018-7-7 09:46:10 | 显示全部楼层
厉害,打开新的思路。学习学习
[发帖际遇]: lilybeast 发帖时在路边捡到 1 蛮牛币,偷偷放进了口袋. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

关闭

站长推荐 上一条 /1 下一条

快速回复 返回顶部 返回列表