第二章 升级你的播放器为V2版本
在这里,你所必须知道的相关知识:
Sound.duration(属性,声音的持续时间,以毫秒为单位)
Sound.position(属性,返回声音已播放的毫秒数。假如声音是循环的,则在每次循环开始时,位置将被重置为 0)
Sound.start(方法,可指定两个可选参数,开始播放处的位置和循环次数。假如未指定参数,则从开头开始播放最近附加的声音)
function (函数声明,更具体的信息,你可以查找教程关于这章的扩展 Function 功能强大的函数声明)
MovieClip.onEnterFrame(事件处理函数;以影片帧频持续调用。首先处理与 enterFrame 剪辑事件关联的动作,然后才处理附加到受影响帧的所有帧动作脚本。 必须定义一个在调用该事件时执行的函数。更具体的信息,你可以查找教程关于这章的扩展 MovieClip.onEnterFrame及其它事件处理)
setInterval(动作;在播放影片时,每隔一定的时间间隔,就调用函数、方法或对象。更具体的信息,你可以查找教程关于这章的扩展 setInterval:超越帧速率的限制)
clearInterval(动作;清除对 setInterval 函数的调用。更具体的信息,你可以查找教程关于这章的扩展 setInterval:超越帧速率的限制)
if(条件判定。更具体的信息,你可以查找教程关于这章的扩展 if ..else..条件判定语句)
这是最终完成的版本:
这是FireWorks的界面的源文件(PNG格式):
首先,请答应我在这里花一点时间来对你讲解一些好的程序设计的方法。因为它对于而言很重要,甚至要重要过你学到的ActionScript语句。
很多人在一开始就忙着写代码。在急着写你的代码之前,你最好养成先规划、构思一下你的应用程序框架的好习惯。这可能会费你些许的时间。但和以后你浪费在查找和修改代码上的时间比起来,这点时间显得更微不足道。而且它带来的好处是:不会让你手忙脚乱。
假如说这个应用程序可以看作是一个小小的项目,我想我也没有说得太过份。一个成功的项目(非凡是大项目)需要良好的规划和足够的设计草图以及人员间的交流。当然,我不会在这里讲述太多的细节,因为就这个程序对你而言,只是个演习。所以你可以略去商业项目中的某些部份(前期的市场调查、客户需求分析以及项目组人员的安排等),你也可略去项目完成部份的项目资料归档、整理工作。
假如你是两个人开发,你所要做的是将你希望它完成的功能列出来,然后将它写在纸上,然后和你的合作者一起讨论某些环节:该如何规划好界面,以及它的大致ActionScript模型。以及一些可能的意外的情况。当然,假如可能,也为你以后扩展它的功能多考虑些“后门”。并将它们记在纸上或俩人都可以访问的电脑资源中。当你们达成共识后,你们就可以开始工作了。假如你们一个是界面设计师,一个是代码编写者。并不意味着代码编写必须等到界面设计师设计好界面后才能开始他的工作。假如你们在开始时达成了一些界面和代码上的共识(也并不是说你要理解它的界面设计的所有含义,或者你的界面设计师要理解你的代码的所有含义,为了更好更快速的沟通,界面设计师可以以一种模糊的概念来将它传达给代码编写者,比如说这个地方可能有一个矩形,我想这样你的代码编写者应该能够理解,而代码编写者也可以这样一种伪代码的方式来将信息传递给界面设计者。比如说点击某个按钮后我会实现哪些功能,然后你的界面可能应该做哪些改变等,用伪代码的方式可能会这样表达:
当用户点击这个按钮后,
我会让中间的部份隐藏并且载入一部份新的界面;
这无疑你们俩都能很好的理解。这样界面设计师可以对整个过程和他所该考虑的因素都可以了如指掌。而不是茫然和一味的“蛮干”。
和界面设计师相比,代码编写者(程序设计师)可能只是将某些定义好的界面以简单的外形代替,然后开始他的代码编写,假如俩人中一个人要做某些影响对方的改动和或者有某些疑问,那么这时就应该和对方交流。)
当然,也可以界面设计师先设计好界面,然后程序设计师再开始编写代码。但请仍牢记这一点。在界面设计师开始设计界面之前和程序设计之间的交流和达成共识足够重要。以及前期的框架和功能定义。这样做的好处仅仅在于在界面设计开始设计界时到设计完毕的那段时间内你的程序设计师可以分开身去做别的工作。并且程序设计师可以在编写代码的时候得到更为精确的坐标数据(如一个按钮的大小和准确位置,这可能在比另外一种用随便以几何外形代替来得精确和直观)而且在界面设计师反复更改它的某些设计方案和设计细节时程序设计师不必也跟着反复修改它的代码。但即使是采用这种方法,在你的界面设计师完成它的界面设计方案后,即使与原来的共识相比没有什么变动,也应该向程序设计师仔细的描述这些设计方案。也许他也会向程序设计师传达些诸如这样的概念,假如你在这个地方这么做的话,那么可能效果会更好。
记住,沟通和信息交流足够重要。你可以想像一个各自为政的项目会是多么的糟糕。
假如你是一个人,那么你可以省去两人交流和达成共识的时间。因为你自已在脑中就可以通过“左右互博术”想好了。而将不将它们记在纸上或电脑上这取决你的习惯或者记忆力,相对而言,也写下来会好些。因为包括我在内,绝大多数的人的记忆都还不是可以达到过目不忘的境界。
假如你是一位初学者,可能上面的这几段话在现阶段对你而言并没有多大的用处,至少在学习这章是这样的,但请记住:在你成为中、高级Flasher的时候逐渐运用这些方法。
我会在从这章开始后的播放器制作采用这种策略,这也有助你理清思路。
首先:这个从V1版升而来的播放器应该具有下面的一些功能。
能够有一个进度条,以显示当前MP3播放的进度,并且它还是可以使用的(这也意味着它可以由用户拖动),从程度设计师的角度来说,它是一个可以水平拖动的按钮。那么根据程序设计师提出的按钮应该有一个滑过时的界面说法,界面设计师可能要为这个按钮设计一个在鼠标滑过时的状态。
同时它应该还有两个文本区以显示MP3当前播放时的时间位置和它的总时间长度。
那么,现在界面设计师可以开始它的设计稿了。我不会在这里向你讲解在FireWorks是如何设计它的。这是最终的设计方案:
我们继续我们的程序设计师部份:
配合打开你下载的flash源文件或者你自已根据PNG源文件自已重新开始设计。
我想在V1版中的两个按钮(播放、停止)是可以略过的了。假如不明白,你可以回过头去看第一章的内容。
我们先完成“显示MP3当前播放时的时间位置和它的总时间长度”部份。
1、在_root主场景部份建立两个动态文本框,并分别将它们命名为soundTimeNow、soundTimeTotal(我推荐你使用命名的方法,而不是使用指定变量的方法)
将它的字体设为:superpoint _square(假如你没有,可以到
http://www.dafont.com/ ;上下载。
然后这里我将动态文本的颜色设为蓝色(#005CB9)。
superpoint _square这种字体很酷,但你还应该将它们包含进swf文件中,否则它们还是显示成那种古老的字体。按下动态文本属性栏中的“字符”按钮,在弹出的对话框中设置好你要导出的字体种类。在这里我只想导出数字和“:”号,因为我只需要这些东西,你的设置看起来像这个样子:
好了,既然你已完成了flash中的界面部份。开始我们的代码编写部分。
我们来看完成的代码以及它们的含义:
function updateSoundTime() {
var tmp1 = Math.floor(mySound.duration/60000);
var tmp2 = Math.floor(mySound.duration/1000-tmp1*60);
if (tmp2<10) {
tmp2 = "0"+tmp2;
}
var tmp3 = Math.floor(mySound.position/60000);
var tmp4 = Math.floor(mySound.position/1000-tmp3*60);
if (tmp4<10) {
tmp4 = "0"+tmp4;
}
soundTimeNow.text = tmp1+":"+tmp2;
soundTimeTotal.text = tmp3+":"+tmp4;
}
this.onEnterFrame = updateSoundTime;
我们先来看最后一句:this.onEnterFrame = updateSoundTime;
它指定电影在进入每帧执行updateSoundTime函数。事实上你也可以这样写:this.onEnterFrame = updateSoundTime();
但我们已经将变量定义为一个函数,
function updateSoundTime() {
...
}
所以后面的一对大括号大可以省去(有时候变量更像是一种指针)。而在某些场合不将大括号省去反而会发生错误。:)
我们来看每帧执行的函数:
var tmp1 = Math.floor(mySound.duration/60000);
var tmp2 = Math.floor(mySound.duration/1000-tmp1*60);
if (tmp2<10) {
tmp2 = "0"+tmp2;
}
var tmp3 = Math.floor(mySound.position/60000);
var tmp4 = Math.floor(mySound.position/1000-tmp3*60);
if (tmp4<10) {
tmp4 = "0"+tmp4;
}
soundTimeTotal.text = tmp1+":"+tmp2;
soundTimeNow.text = tmp3+":"+tmp4;
首先用var声明一个在函数内的局部变量tmp1。
(在函数或循环内将以后不用的变量用var声明为局部变量可以获得更快的速度,因为它们会在用完后自动从内存中踢除,这样可以让你的flash作品运行得更快,你应该在以后的代码编写中养成这种好习惯)
用它来保存分钟数,我们先获取当前MP3总的时间长度。它返回的单位是毫秒,这里我们要把它转换为分钟。
这是转换的过程:
1、
----------------
1分种=60秒;
1秒=1000毫秒;
所以1分种就等于60*1000=60000毫秒。
2、
----------------
mySound.position/60000
将所获得的时间位置除以这个转换率,那么你可以得到诸如2.15分这样的小数。
用Math.floor()方法将它取出整数部份就可以了,它就是你当前所在的分钟数。
注重:不要用Math.round()方法来代替Math.floor(),因为Math.round()会进行四舍五入的计算,而假如当你得到像2.65这样的小数时,Math.round(2.65)会得到3,这并不是想要的结果。相反,Math.floor()不管后面的小数部分是什么,它只取回整数部分。Math.floor(2.65)和Math.floor(2.28)都得到2。
来看秒数的转换过程:
var tmp2 = Math.floor(mySound.duration/1000-tmp1*60);
1、
------------------
mySound.duration/1000
得到总的秒数
2、
-----------------
mySound.duration/1000-tmp1*60
减去已在分钟中的秒数,剩下的就是要在秒区的显示的数字
tmp1*60
其实代码也可以写成这样:
var tmp2 = Math.floor(mySound.duration/1000)-tmp1*60;
换过一种思维方式:
var tmp2 = Math.floor(mySound.duration/1000)%60;
%为求模运算,a%b计算a 除以b的余数,如tmp1=10%3则tmp1为1,若tmp1=4.3%2.1则tmp1为0.1,这要与百分号区分开来。
这里的意思是以总体的秒数除以60得到的零头则是应该在秒数区显示的数了。
换过一种算法:
var tmp2 =(mySound.duration/60000- Math.floor(mySound.duration/60000))*60;
这段代码是从小数出发,先获得分钟的小数部份,再将它乘以60,得到余秒。
假如你觉得有点头晕,也不必害怕,我只是想告诉你,在 Flash 中实现同一种东西,可以有很多种方法。甚至是几十种。你也未必就一定要知道别人的方法,只是你实现了它,那么就用你自已的方法。对于不同层次的人,假如一种方法对你而言是轻易理解和辨认的,那么就使用它。你不必把你的代码写得有多么的怪异。而一个连自已都不懂的怪异代码你可能要为它另外加上一行注解(//这是...)。
相对而言,假如你的代码不是被执行很多次或者每帧都在执行。那么你可以不必去简化你的代码。而假如是,那么,简化你的代码和找到一个高执行效率的代码会更好些。
对比下面的代码:
a=10+10+10+10+10+10+589;
和a=60+589
无疑下一行的代码更加高效。
要对比两个代码的执行速度,你可以使用一个for循环,然后用一个较大的数值将这种差异放大,在最后执行完毕的时间得到它的执行完需要的总时间。getTimer();
假如有时间,那么,优化一下你的代码是好的。这也是一种好习惯。
继续下面的ActionScript:
if (tmp2<10) {
tmp2 = "0"+tmp2;
}
这里使用一个判定语句将秒转换成标准的两位格式以使你的秒数看起来不会像这样2:5,而应该是这样的2:05。
这是伪代码的理解方式:
假如tmp2小于10的话,
那么将tmp2的前面加上一个0。以把像5这样的数字换成05。
你应该注重一些细节。在if()的判定断条件中你应该确保你的tmp2是一个数字,而不是一个伪数字(字符串)。当然,在这里它是一个数字,但在这之后它就不是一个数字了。
tmp2 = "0"+tmp2;
“0"引号0代表一个字符串(所在在双引号中括起来的都表示字符串,即使里面是一个数字),当一个字符后面加上一数字时,那么flash只是简单的把后面的数字当作字符串来处理,也就是只是把它和前面的字符像用胶水那样将它们连接起来。
"0"+5得到的是0后面连接5,即05。它是一个字符串,记住:字符串+数字=字符串。
假如你将0中的双引号去掉(将它变成一个数字),那么我想你的0+5不会有太多的意义。它仍然还是5。
那么,假如你的tmp2假如是一个字符串会是什么样子的?
在Flash中执行下面的ActionScript:
tmpA = "0"+5;
trace(tmpA<10);
答案仍然是true,也就是真。你很幸运,在判定之前,Flash会自动帮你字像"05"这样的字符串转换成数字5。当然,它不影响你的数据tmpA本身。它仍然是一个字符串。下面的代码说明了这一点:
tmpA = "0"+5;
trace(tmpA<10);
trace(tmpA+15);
tace(tmpA+15)得出的结果是0515,而不是20。
当然,假如你的tmpA恰巧是"05"这样的类似数字的字符串,它不会出现什么问题。但小心一点,不要想当然的以为类似这样的东西都是这样子。
看下面的代码:
tmpA = " 0 "+5;
trace(tmpA<10);
它得到undefined,也就是未知道。flash无法判定它。因为现在" 0 5"已经无法成功的转换成一个数字,它还是一个字符串(注重0的两边各多了一个空格)。你所需要的只是注重这种情况。虽然它很少出现,但一旦出现,你将很难发现是这里出了问题。
这种情况下,它和“真正的”字符串得出的结果是一样的:
tmpA = "这只是一个"+"测试";
trace(tmpA<10);
这可能有点混乱,我不能说自动转换不是一个好功能,但它也会带来一些灾难性的后果:会让我们以常犯些小错误,而且很难发现这个错误。
幸好ActionScript 2.0 中类似于Java的严格变量类型审查解决了这个问题。虽然它会让你写代码的时候麻烦些,但至少你可以很清楚的知道这个变量的类型。
好了,让我们回到我们的主题上来,假如你还有点意尤未尽,那么,你可以去查找关于这一章的扩展 自动转换变量类型和判定:你的好处和灾难
代码soundTimeTotal.text = tmp1+":"+tmp2;将你所计算出来数字连接成易读的格式并将它显示在定义好的动态文本框中。
假如你想要显示毫秒,那么你只要将前面的因子1000换成1就可以,但记住,它会更消耗些CPU,虽然只是那么一点点。
同样的道理,我想关于当前MP3播放时的时间位置的那一部份你应该也可以很轻易理解它们。
假如你是一个很喜欢在测试时搞破坏的坏孩子。(这是个好习惯)那么你可能发现在你测试它的时候会有些问题:
当在你点击播放按钮一段时间后,假如你停止它。然后再点击你的播放按钮。你显示的当前MP3时间位置的时间信息不会从0:00开始!
这可能另你我都感到头疼。
是代码
var tmp1 = Math.floor(mySound.duration/60000);
var tmp2 = Math.floor(mySound.duration/1000-tmp1*60);
if (tmp2<10) {
tmp2 = "0"+tmp2;
}
var tmp3 = Math.floor(mySound.position/60000);
var tmp4 = Math.floor(mySound.position/1000-tmp3*60);
if (tmp4<10) {
tmp4 = "0"+tmp4;
}
soundTimeTotal.text = tmp1+":"+tmp2;
soundTimeNow.text = tmp3+":"+tmp4;
出了问题吗?可能是。
但事实证实它不是这部分代码出了问题。
让我们来学会一些判定问题的方法和培养一些直觉。
首先,学会观察你的问题出现的情况:只是在重复(或者说再次)点击播放按钮时才会出现问题。而无论试多少遍,在第一次点击播放按钮的时候不会有任何问题。而且它们的时间显示一直很正常。而即使你在第二次点击播放按钮后,它们的时间间隔跳动也很规律。(虽然显示的时间不对)
“在第一次点击播放按钮的时候不会有任何问题。”和“而即使你在第二次点击播放按钮后,它们的时间间隔跳动也很规律。”这是两条很重要的信息。事实上它隐藏了你的上面的关于时间换算的代码是正确的。确实,无论你无何修改那段代码,这个问题也依然存在。(但这里你不要学会一个误区,认为你改进代码后你的问题依然存在就认为这里就没有问题。有时可能你改过后的代码仍然是错误的,这时你所要做的是:再次认真的审阅问题出现的情况,然后冷静的思考。重新判定问题所在)
你可能已注重到了下面的信息:
只是在重复(或者说再次)点击播放按钮时
在第二次点击播放按钮
注重一些关于Sound.position的信息
假如你猜测这是问题的要害所在,那么,你应该试试。
从这里判定这应该是一些初始化的问题。(至少在中间过程中不会这样)。那么考虑在代码中加上一些初始化的代码。考虑在上面的代码中加入,但因为它是处于onEnterFrame事件中,似乎有点不太可能。此时你可能会去查找一些关于Sound对象的帮助。
假如你注重了这里面的信息:
Sound.position 属性(只读);返回声音已播放的毫秒数。假如声音是循环的,则在每次循环开始时,位置将被重置为 0。
“重置为0“是个很重要的信息。这也意味着你的Sound在第二次加载时可能没有被重置。尝试一些重置的方法:
delete mySound;
mySound = new Sound();
它不会对你现有的东西有什么影响,它的含义是,先将原来的mySound对象(你的MP3)从内存中删除,然后重新建立一个。
既然它不会对你现有的东西有什么影响,为什么不试试呢?
这是改写后的播放按钮的完整代码:
on (release) {
delete mySound;
mySound = new Sound();
mySound.loadSound("UploadFile/mp3player/musics/1.mp3", true);
}
事实最终证实你的判定和修改是正确的:它不会再出现这种情况。
好了,从这里你也应该注重到了一些:内存中缓存对你的影响。
好了,开始我们的进度条部份:
关于如何制作一个类似的按钮你可以参考第一章的扩展部分: flash基本软件操作和界面设计技巧(应该让你的按钮更易于使用)
我将这个可以拖动的按钮做成一个电影剪辑(因为这样意味着可以被瞄准和控制坐标),并命名为bar,然后再将它转换成一个电影剪辑,并命名为playBar。这样一来,bar的默认X初始位置为0,这会方便以后的计算。
这是在按钮上的ActionScript:
on (press) {
startDrag(this, false, 0, 0, 170, 0);
}
on (release, releaseOutside) {
stopDrag();
}
这些ActionScript使你可以在按钮被按下(press)时可以被在X=0-170这个范围内拖动。this指代按钮所在TimeLine的影片剪辑bar,拖动它,也就相当于拖动了这个按钮。
on (release, releaseOutside) {
stopDrag();
}
使你在放开时停止这种拖动。
我们来看更新进度条位置的ActionScript:
playBar.bar._x = (mySound.position/mySOund.duration)*170;
这里,我们获得当前所在时间和总时间的比例值,用它乘以一个在最终位置时的值(在这里是X=170)。因为我们刚才将bar做成了一个影片剪辑,所以这里就可以不必再进行额外的差值运算。
因为我们应该每时每刻(在Flash中是进入每帧时)都更新它的位置,所以我将它放在更新时间显示的onEnterFrame事件中(也就是函数updateSoundTime)
这里会出现一个同步错误,假如你测试过你的mp3播放器,你会发现它当开始播放mp3后,你的进度条。不能被拖动,因为你的_root上每帧都会更新进度条的值,所以“即使你拖动了它,它也马上会被刷新而变成playBar.bar._x = (mySound.position/mySOund.duration)*170;这里的值。
要解决这个问题,你可以使用这种方法:用一个变量来监控它的状态。
具体的做法是:
在进度条被按下时将变量_root.dragBar设为1;然后在放开后将它设为0;
这是改进后在按钮上的代码:
on (press) {
_root.dragBar = 1;
startDrag(this, false, 0, 0, 170, 0);
}
on (release, releaseOutside) {
_root.dragBar = 0;
stopDrag();
}
然后改进你的进入每帧时更新进度条的代码,使它在_root.dragBar不等于1的时候才更新进度条的位置。
这是改进后的代码:
if (_root.dragBar != 1) {
playBar.bar._x = (mySound.position/mySOund.duration)*170;
}
现在它执行得很好。
到此为止,你只剩下最后一组任务了,现在应该解决在拖动这个滑块(刚才建立的那个按钮)后,让它到指定的位置播放。和你的暂停按钮。
事实上,你可以将这部份的代码写在按钮中,也可以将它写在_root中,封装在一个函数playSoundAt()中。然后由按钮调用。这里我们选择_root。
这是函数playSoundAt()的代码(它其实就是更新进度条位置的反运算,再加上flash中一个内建的Sound.start()方法,:)flash中内建的方法更像是一些驱动和接口)
function playSoundAt() {
var tmpA = Math.floor(playBar.bar._x/170*mySound.duration/1000);
mySound.stop();
mySound.start(tmpA);
_root.dragBar = 0;
}
注重Sound.start的单位是秒,而不是毫秒,所以你要将它除以1000以转换,用Math.floor()是为了避免你最后在Sound.start中使用的值会出现小数。
Wo...我需要告诉你一些关于Flash Player6和Flash Player7在处理MP3上的差异。在Flash Player6中,一个声音只有在加载时设为“事件声音”才能使用Sound.start拖动定位。而流式声音则不行。 这实在是个很残酷的功能。
这也意味着在Flash Player6中你只有把你的“播放”按钮改成这样才能使你的进度条在拖动时起作用,否则声音会“意外”地停止。
on (release) {
delete mySound;
mySound = new Sound();
mySound.loadSound("UploadFile/mp3player/musics/1.mp3", false);
}
事实上,用这种方法加载的声音(事件声音)需要在声音下载完才能播放。而且它它不会在声音下载完自动播放(Sound.onLoad事件也无法完成这个功能)。你需要用手动的方法来播放它。当然,代替手动的方法你可以建立一个每帧检测事件(Sound.getBytesLoaded 和 Sound.getBytesTotal ),假如下载完了,则开始播放它。
假如你加载的MP3在硬盘中,那么你可以简化这个MP3 Loading检测。因为在你硬盘中的MP3的加载几乎不需要延迟,所以你可以直接将代码写成这样:
on (release) {
delete mySound;
mySound = new Sound();
mySound.loadSound("
http://5istudio.flashk.com/FK/UploadFile/mp3player/musics/1.mp3"'' target="_blank" >http://5istudio.flashk.com/FK/UploadFile/mp3player/musics/1.mp3";;, true);
mySound.start();
}
而在Flash Player7 中无论你使用事件声音还是流式声音你都可以使用Sound.start来定位。当然,它带来的好处相当明显(非凡是在低带宽的环境中):可以边下载边播放,而你你可以拖动播放进度条。而在Flash Player6中,你只能忍痛在其中选择一种,而将要抛弃另外的那个功能。
当然,假如要在边下载边播放的环境中使播放更加顺畅,可以使用_soundbuftime属性,它指示了声音流缓冲的秒数。默认值为 5 秒。 你可以将它设为更高的值(_soundbuftime=10),以使它在更低的带宽中可以流畅的播放。至于在何种带宽环境下应该使用何种值我不能给你一个明确的答案,最好的方法就是你自已去试验它。为了更智能的使用这个属性以使不同的使用者都流畅的播放,你可以用一个方法来检测用户的带宽(在你加载MP3的时候就可以使用Sound.getBytesLoaded 和getTimer来检测用户的带宽,当然,假如你的服务器太慢则可能是你的服务器的带宽,记住水桶效应,但不管怎么说,这得到的都是当前状态下的传输速率),然后动态的设置_soundbuftime的值。
我推荐你使用Flash Player7来使用这个播放器,尽管它在Flash Player6中绝大部分也能工作。(很抱歉,我没有专门为Flash Player6考虑,因为它会增加教程的难度)
好了,回来。现在假如测试你的播放器会出现一些问题:当你拖动放开你的进度条时,它会在放开的时候有时会有些抖动。
为了节约些许的时间,我直接告诉你造成问题的原因:你无法确保你的更新进度条的代码在同一帧中比定位MP3时间的代码先执行还是后执行。
if (_root.dragBar != 1) {
playBar.bar._x = (mySound.position/mySound.duration)*170;
}
对比:
var tmpA = Math.floor(playBar.bar._x/170*mySound.duration/1000);
mySound.stop();
mySound.start(tmpA);
_root.dragBar = 0;
仅管你已经在定位MP3时间的代码中将_root.dragBar = 0在定位完后才释放更新进度条代码的执行权。但并不意味着执行mySound.start(tmpA);不需要一些时间。(事实上,这有时不尽相同,你可以从你的抖动的不定期看出来)
解决的办法我使用了setInterval()动作。有关setInterval()动作的具体说明请查找教程关于这章的扩展 setInterval:超越帧速率的限制。
这里使用的其实是一个setInterval()的非凡变种:将它变成延迟执行的方法。
这是最终的包括playSoundAt()的代码:
function playSoundAt() {
var tmpA = Math.floor(playBar.bar._x/170*mySound.duration/1000);
mySound.stop();
mySound.start(tmpA);
startLockUpdate();
}
function startLockUpdate() {
setInterval_me = setInterval(unLockLater, 500, true);
}
function unLockLater(n) {
_root.dragBar = 0;
if (n) {
clearInterval(setInterval_me);
}
}
我让_root.dragBar 在经过500毫秒(0.5秒)后才释放更新进度条代码的执行权。这时Flash已经运行了20帧。所以它不会再出现冲突问题。而你的用户对这0.5秒几乎不会有什么非凡的感觉。
当然,这个使用setInterval()实现的功能你也可以通过一个MC来实现它。但setInterval()带来的好处是你可以很轻易的更改延迟的时间和代码(因为它们都在一起,使用MC,你不得不再进入到MC中编辑)。
完成暂停按钮。
on (release) {
mySound.stop();
hasPause = 1;
_root.dragBar = 1;
}
它很简单。mySound.stop()将声音停止。
_root.dragBar = 1然后锁定更新进度条代码的执行权。
并记录一个暂停的状态hasPause = 1。
虽然暂停按钮很简单,但却会引起一些较大的代码变化。现在,你的播放按钮同时要控制两个按钮--暂停和停止。并跟据暂停和停止各安闲按下后再按下播放时实现不同的功能:
当暂停按下时只是继续播放MP3;
当停止按下时重新载入MP3,并将mySound初始化。
这是暂停按钮给播放按钮带来的变化(注重else if,它使你在按下暂停后再按下停止不会产生冲突):
on (release) {
if (hasStop == 1) {
delete mySound;
mySound = new Sound();
mySound.loadSound("
http://5istudio.flashk.com/FK/UploadFile/mp3player/musics/1.mp3"'' target="_blank" >http://5istudio.flashk.com/FK/UploadFile/mp3player/musics/1.mp3";;, true);
_root.dragBar = 0;
hasStop = 0;
} else if (hasPause == 1) {
playSoundAt();
_root.dragBar = 0;
hasPause = 0;
}
}
这是暂停按钮给停止按钮带来的变化:
on (release) {
mySound.stop();
playBar.bar._x = 0;
_root.dragBar = 1;
hasStop = 1;
}
关于初始化场景:
Stage.scaleMode = "noScale";
Stage.showMenu = 0;
Stage.scaleMode = "noScale";将场景的缩放设为100%模式;
Stage.showMenu = 0;将隐藏Flash的右键菜单中的控制项(你以后可以不必在DreamWeaver里设置),并将Flash独立播放器中的菜单隐藏。
这个V2.0版的播放器中可能引入了太多的概念以致你无法一下子全吸收它。这里是一些简要内容:
界面设计师和程序设计师和分工和合作
设计规划你的程序和项目的重要性
变通和多种方法
学会判定某些错误的要害所在
使用功能模块和状态控制
修改一个功能可能对其它部份造成的影响