****************************************************************************
时间:2015-02-02
作者:Sharing_Li
转载注明出处:http://www.jb51.cc/article/p-mvooejfu-rx.html
上一篇博客,我们讲解了抽奖界面的设计,其中着重讲解了下沿椭圆运动的动作类EllipseBy。本篇将讲解抽奖概率的设计。
转盘抽奖的方式有两种:第一种是先转转盘,转到谁就是谁。第二种是我先计算你抽中了什么奖品,然后再转到相应的奖品上(我擦,这不是暗箱操作吗!!)。
我们先看看第一种抽奖方式:
这个转盘有三个奖品,因为三个扇形面积一样,所以中奖概率一样,都是1/3。如果我们想改变每种奖品的抽奖概率,可以通过改变扇形的面积,比如概率是1/4,那么扇形的面积是整个圆的1/4。如下图:
如果我们想动态的改变抽奖的概率怎么办,一种方法是可以更换转盘的底图,但是显然这样做不好。我们想想,现实生活中,奸商是怎么暗箱操作的,比如拿个吸铁石,放到转盘后面来影响转盘指针的停留位置。这种方法我们可以借鉴一下(我不是奸商~),比如,我们给转盘上每一个扇形设置一个阻碍因子,获奖概率越大,阻碍因子越大。所以,当转盘转动的时候,指针每进入一个扇形区域,就将转盘的速度减去这个扇形的阻碍因子。这样我们就可以动态的改变抽奖的概率,不过这种“暗箱操作”精度不高,不好控制。后面讲第二种抽奖方式的时候,再来详细的讨论。先来看看怎么判断抽中了谁?
有两种方法:
第一种是判断旋转指针的针头停留的位置在哪个扇形区域内,也就是点与不规则形状之间是否碰撞,可以参考这篇文章:http://www.2cto.com/kf/201401/272331.html
第二种是根据每个扇形的角度来判断,整个圆的角度是360,假如一共有三个扇形,每个扇形的角度区间为[0,100]、[100,280]、[280,360]。我们可以通过getRotation来获得转盘转了多少度,然后进行取模运算,%360,再看看得到的结果在三个扇形哪个区间内就可以了。
以上说的方法虽然比较贴合实际生活,但并不是特别适合放到游戏开发当中,我们更希望更精确的控制抽奖概率,或者根据玩家的抽奖次数来动态的改变抽奖概率。那么接下来就说第二种抽奖方式了,即先计算后中奖。这种方法所有扇形的面积都相等。
作为一名游戏开发者,我们是希望让抽奖一切随缘,还是一切尽在自己的掌握当中?假如奖品中有极品装备,特别是数量非常稀少,如果玩家运气好,一下就抽中了怎么办?在游戏当中,一般抽奖,每天第一次都是免费的,之后的抽奖需要消耗虚拟币,只要涉及到虚拟币消耗的地方,我们就需要细心地设计,毕竟关系到咱们游戏开发者的收入。这里简单介绍两种方法。
第一种,假如有4个奖品A、B、C、D,我们指定每种奖品的抽奖次数N,N的意思是至少抽了N次,你才能抽中该奖品,然后再定义一个M,用来统计玩家抽了多少次。例如这4个奖品的N值分别是Na:1、Nb:2、Nc:10、Nd:50,M初始值为1,那么第一次抽,M++,M > Na,必定抽中A,第二次抽,M++,M > Nb,必中B;继续抽奖,M++,Nb < M = 4 < Nc,在小于M值的奖品中,即Na和Nb中随机选择一个。直到M = 11 > Nc,抽中C,然后继续抽,在Na、Nb和Nc中随机选择一个,然后依次类推。另外,如果有的奖品的N值相同,那么就在这些奖品中随机选一个。当M的值大于所有奖品的N值时,一些稀有的、值钱的奖品就会变得更加容易抽中。那么我们可以这样做,比如把这里的奖品D当作稀有奖品,当第一次抽中之后,我们改变奖品D对应的N值,N = N + N / 2,当然,你要是黑心一点就这样设置N = N * 3,(估计玩家要群殴你了。。。)。确定抽中的奖品之后,然后计算出需要旋转多少度,指针才停留在该奖品的扇形区域上,最后调用RotateBy就可以了。
上面这种方法比较精确,并且非常灵活。我们再来看看第二种方法。
假如有A、B、C、D、E一共5个奖品,每种奖品的中奖率分别是:Ra:80%、Rb:30%、Rc:50%、Rd:30%、Re:10%,我们定义一个int型的基数,值可以随意取,但要合适。这里我们设置为100,然后就可以得到每个奖品的中奖区间为:A:[0,80]、B:[80,110]、C:[110,160]、D:[160,190]、E:[190,200],然后我们在区间[0,200]之间随机取一个数,看看这个数在哪个区间,那么对应的奖品就被抽中。然后我们再来看看怎么通过玩家的抽奖次数改变概率的大小。我们定义一个系数p,值可以随意取,我们这里取2,然后我们得到区间的可变值V = 抽奖次数M * p,那么原来的抽奖概率变为:A:[0,80 + V]、B:[80,110 + V]、C:[110,160 + V]、D:[160,190 + V]、E:[190 + V,200],这样做会有重叠区域,比如V = 10时,如果我获得的随机数等于85,A、B都在范围,这时候随机取一个值就可以了。同样,确定了抽中的奖品之后,再计算需要转的角度,然后调用RotateBy。
到这里,中奖的方法已经介绍完毕。有一点需要大家注意,就是随机数获取的算法,一定要更接近于自然随机。这里大致讲解一下一些随机算法,见代码:
- //第一种
- //随机效果一般,每次进入游戏的时候,值都是一样的
- m_randData=CCRANDOM_0_1()*200;
- log("1st------------->%f",m_randData);
- //第二种
- //随机效果不好,虽然每次进入游戏,值都不一样,但是生成的随机数是递增的,而且相邻两个数之间的变化不大
- srand(unsigned(time(NULL)));
- m_randData=rand()%200;
- log("2rd------------->%f",0); background-color:inherit">//第三种
- //随机效果较好,每次进入游戏的值都不一样,生成的随机数无规律,相邻的两个数变化较大
- timevaltv;
- cocos2d::gettimeofday(&tv,NULL);
- unsignedlongintseed=tv.tv_sec*1000+tv.tv_usec/1000;
- srand(seed);
- m_randData=rand()%200;
- log("3nd------------->%f",m_randData);
- //第四种
- //C++11的特性,要包含头文件<random>,随机效果不错。
- std::uniform_real_distribution<double>u(0,200);
- std::default_random_enginee(rand());
- for(inti=0;i<5;i++)
- {
- log("4th------------->%f",u(e));
- }
关于随机算法,我们也可以自己来实现,不一定非得用API提供的,这里我就不深入探讨了,内容太多,以后有时间再写。
至此,全篇内容已经讲解完毕,欢迎留言交流。
原文链接:https://www.f2er.com/cocos2dx/344537.html