cocos2dx之抽獎介面與獲獎機率的設計(二),cocos2dx抽獎
****************************************************************************
時間:2015-02-02
作者:Sharing_Li
轉載註明出處:http://blog.csdn.net/sharing_li/article/details/43405569
****************************************************************************
上一篇部落格,我們講解了抽獎介面的設計,其中著重講解了下沿橢圓運動的動作類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",m_randData);//第三種//隨機效果較好,每次進入遊戲的值都不一樣,產生的隨機數無規律,相鄰的兩個數變化較大timeval tv;cocos2d::gettimeofday(&tv,NULL);unsigned long int seed = 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_engine e(rand());for (int i = 0; i < 5; i++){log("4th------------->%f",u(e));}
關於隨機演算法,我們也可以自己來實現,不一定非得用API提供的,這裡我就不深入探討了,內容太多,以後有時間再寫。
至此,全篇內容已經講解完畢,歡迎留言交流。