大概需求就是:通过给力不同,体现更多或者更少的转动时间及更快的转动速率。当然每次启动转盘最终得到的奖品我们是预先定好了,并非由flash前端控制,而是与后端程序通信得到具体的奖品代号。
如果你信过任何看似真实的抽奖,先不要忙着愤怒,先说一下为什么需要由后端程序选择抽奖结果 :lol: : 首先,转盘上一共8个产品,只要是登陆并发布任务的用户均可参与抽奖活动,大奖是IPAD一台,最小奖也是5元现金。看似你只有2/8的几率会抽到“谢谢”,当然,现在你不会相信轮盘上的几率了。因为奖品数量有限,我们需要在指定的时间送完指定的奖品并结束这次活动。最终,大奖IPAD的概率不是1/8(没有任何公司能承受)。大概透露一下是由后端控制的大概几千分之一的几率。
需求如上,普通的转盘相信看这篇文章的童鞋都能非常容易的写出来,就不叙述了,现在需要解决的问题有3个:
问一.如何使转盘在未知圈数(360°)的转动后停止到指定点,并要求动画自然。
问二.力度如何与转动时间和最快速度相关联。
问三.项目中力度条是一个弧线,如何使“给力”的指针在被用户拖动时跟随弧线运动。
(在上面我并没有提及关于力度设置的条如何制作,跟普通图形loading功能制作类似,只是使用了蒙版,大家都明白的,就忽略此项)
下面是一个已完成核心的DEMO,里面的每次选中奖品是通过随机数产生:
+-------------------------我是分割线:By Auntion---------------------------------+
解一, 如何使转盘在未知圈数(360°)的转动后停止到指定点,并要求动画自然:
首先,需要自己定义一个最小和最大的转动圈数的定义:
//两个常量
private const lapsMin:int = 5;
private const lapsMax:int = 10;
然后,你需要得到当前用户选择的力度,加力度范围我们暂定在0-100
//根据力度条的总长度和当前长度得到对应的百分比,你们懂的。
Math.floor((this.powerY+(this.powerTxt.height/2))/this.powerSize.height*100)
最后根据力度和圈数限制取得我们需要的实际转动圈数:
//this.n_power为当前的力度
Math.floor((this.n_power/100)*this.lapsMax + this.lapsMin);
到这里,我们已经得到了需要转动的圈数,很easy,现在需要把转动的圈数转换成实际用到的角度
//一圈肯定是360度没错了,那么:
this.n_laps * 360
光有这些还不够,还需要根据指定的奖品编号得到最终需要补充的角度值,才能准确的转动到我们需要的奖品上面,也就是先得到当前奖品的所在角度范围(最大角度和最小角度),也就是说,你必须把每个奖品的角度范围给事先储存起来,如:
//产品角度分布
private const distribution:Array = [
[0, 45], //第一项产品, 威客力
[45, 90], //第二项产品, 谢谢
[90, 135], //第三项产品, 公仔
[135, 180], //第四项产品, 36行
[180, 225], //第五项产品, 谢谢
[225, 270], //第六项产品, 现金5元
[270, 315], //第七项产品, 公仔
[315, 360] //第八项产品, ipad
];
之后再根据下标,取得数组中的某个指定产品的角度范围,从范围中取得一个随机值,作为最终的目标角度,并且做一些处理,防止转盘指针最终指到产品间的线上,这里还有一个特殊处理,你需要对最终的角度范围根据360度取反值,因为这个转盘其实相对正方向的360度是在作反向旋转的。如果你的奖品指针不是指向0度的位置,在最后也同样需要加上指针的偏移角度。
//Base.randRange是一个取范围随机数的静态方法
//this.arrowAngle是指针的偏移角度
//如下的+10和-10就是防止指针到线上而对最大和最小角度范围各+10和-10度
(360 - Base.randRange(this.distribution[this.n_target][0]+10, this.distribution[this.n_target][1]-10)) + this.arrowAngle
到此,已经得到根据圈数换算出来的角度,和产品的目标角度(范围随机值)。把他们相加,即得到最终的旋转角度。也就是这次抽奖最终的结果。
最后你只需要,使用一个缓动公式和Event.ENTER_FRAME即可开始让转盘旋转。
下为本次使用的四次方的缓动(t^4):
//在这里,为保证转动自然,从着力的角度来说,需要在转盘开始时也从慢到快,结束时
//是由快到慢,在动画的中间部分是该次旋转的速度峰值,即:
//如下代码的if是判断是在该过程的前一半还是后一半,在前一半时间,缓入方程有效,后//一半时间,缓出方程有效。
if ((t/=d*0.5) < 1) return c*0.5*t*t*t*t + b;
return -c*0.5 * ((t-=2)*t*t*t - 2) + b;
+-------------------------我是分割线:By Auntion---------------------------------+
解二,力度如何与转动时间和最快速度相关联:
上已提到的缓动公式,中存在t,b,c,d值,我们需要先了解他们各自含义:
t: 当前时间;
b: 初始值;
c: 变化量;
d: 持续时间。
现在先说力度和最大速度的关联。你需要先把力度转换为最大峰值(根据你的当前的情况来定义转换的算法),然后在该公式中加入最大值的限制,也就是每一次执行该公式前,先判断是否达到峰值,达到峰值则保持该值的衡量运动并限定时间,当衡量运动时间达到达到持续时间的一定量时则开始衰减(这一点在公式中已完成在一半时开始衰减:(t/=d*0.5) < 1)
然后说说力度与执行时间的关联。也就是对d值的修改,很简单,不多做叙述,我是如下完成的:
//如下代码计算出时间,单位为秒
3*this.n_laps/20 + 15
+-------------------------我是分割线:By Auntion---------------------------------+
解三,项目中力度条是一个弧线,如何使“给力”的指针在被用户拖动(Drag)时跟随弧线运动:
这个问题相对整个项目虽然不是最繁琐的,应该是最让人头痛的。
目前我们有一条力度弧线(请参见附件图片),他不是一个规则的顶底两端X点对齐的弧线(有一些角度偏移)。而已知条件就是它的宽高,也不知道偏移角度,要使一个MC跟随这个弧线运动,也就是在用户拖动“给力”图标时,他的y轴始终被限制在力度条的高度之内,他的x轴适中紧贴力度条的边缘。
其本来应该得到这条弧线的弧度进而计算出这条弧线不同y点的x点值。但是我想了许久,根据现有条件没办法算出来,于是用了一个笨办法实现,用已知的条件加上视觉判断倾斜值达成效果,演算法如下:
(结束点向外系数*曲线宽度/曲线高度的平方) * (y轴的平方) - (开始点向外系数*曲线宽度/曲线高度) * y轴;
上面所指的“结束点向外系数”和 “开始点向外系数” 是根据视觉判断而定义的结束点的x位置和开始点的x位置。
最后只需要用当前值减去或者加上当前“给力”图标与力度条的距离,使其紧靠即可。如:
var x:Number =
(1.5*this.powerNow.width/(this.powerNow.height*this.powerNow.height))
*
(this.powerTxt.y*this.powerTxt.y)
-
(0.6*this.powerNow.width/this.powerNow.height)
*
this.powerTxt.y;
this.powerTxt.x = x - 37;
+-------------------------我是分割线:By Auntion---------------------------------+
以上三个问题都解决了,那么这个转盘的核心部分也完成得差不多了。
一些常见的问题在本文中并没有提出,例如(如何拖动,进度条,百分比计算等,ENTER_FRAME对动画的具体实现等)。
演示的只是一个最初的没有网络通信及与JS交互的初版。在最后,也用到了URLLoader进行服务器通信,及用到ExternalInterface.call进行JS交互,还有一个关于沙箱规则的处理问题在这里没有提出,相信很多人在做as3的开发中如果使用到外部通信,一定烦死了沙箱规则。
下次我会专门开个文章,对我自己对沙箱规则的回避方式进行一个描述,让您不再受沙箱困扰。哈哈
by auntion 2011-11-15
mail: Auntion@gmail.com
联系: QQ 82874972
如果你对这篇文章有任何疑问可以通过如上联系方式找到我。
原创文章,请尊重打字的辛劳和作者的权益,转载时请不要删除这里的作者信息。
收藏本站 设为主页

