Cocos2dx lottery page and prize winning probability design (1): cocos2dx Lucky Draw
**************************************** ************************************
Time: 2015-02-01
Author: Sharing_Li
Reprinted Source: http://blog.csdn.net/sharing_li/article/details/43268877
**************************************** ************************************
In different games, there are often a variety of lottery activities, such as a free lottery each time you log on to the game, a card hero in a card game that draws different colors, and a weapon lottery of different quality, ten connections and so on. Today, we will explain to you that the traditional lottery method is the transfer of the turntable lottery, including the drawing interface animation design and drawing probability design. As there are a little more content, I will explain it in two articles. This article first introduces the interface design of the turntable lottery method. Not to mention nonsense. First, go:
(... Highlight my titanium alloy eye !)
Let's take a look at the general functional requirements:
1. a turntable, a pointer, can be a turntable or a pointer, this article is a turntable.
2. When the turntable is turned, the speed is fast, slow, and then stopped.
3. When the turntable is being turned, various particle effects are animated, including the ring-like flashing stars and small comet moving through an elliptical trajectory.
4. After winning the prize, an animation is displayed.
After reading the functional requirements, let's see how to write the code:
First look at the simple initialization code:
Bool LotteryTurnTest: init () {if (! Layer: init () {return false;} auto bgSize = Director: getInstance ()-> getWinSize (); m_pBg = Sprite :: create ("LotteryTurn/bg_big.png"); m_pBg-> setPosition (Vec2 (bgSize. width/2, bgSize. height/2); this-> addChild (m_pBg); // Add the title auto plabel = Label: createWithTTF ("LotteryTurnTest", "fonts/Marker Felt. ttf ", 30); plabel-> setPosition (Vec2 (bgSize. width/2, bgSize. height * 0.9); m_pBg-> addChild (plabel); // Add the turntable m_turnBg = Sprite: create ("LotteryTurn/turn_bg.png "); m_turnBg-> setPosition (Vec2 (bgSize. width/2, bgSize. height/2); m_pBg-> addChild (m_turnBg); // Add pointer auto arrNor = Sprite: create ("LotteryTurn/turn_arrow.png"); auto arrSel = Sprite :: create ("LotteryTurn/blank"); arrSel-> setColor (Color3B (190,190,190); m_turnArr = MenuItemSprite: create (arrNor, arrSel, CC_CALLBACK_1 (LotteryTurnTest: onBtnCallback, this); m_turnArr-> setPosition (Vec2 (bgSize. width/2, bgSize. height * 0.557); m_turnArr-> setScale (0.7); auto pMenu = Menu: createWithItem (m_turnArr); pMenu-> setPosition (Vec2: ZERO ); m_pBg-> addChild (pMenu); // Add the simple interface auto awardLayer = LayerColor: create (Color4B (0,100,); awardLayer-> setPosition (Point :: ZERO); awardLayer-> setTag (100); m_pBg-> addChild (awardLayer, 10); awardLayer-> setVisible (false); return true ;}
Click the button to get a random rotation angle. The turntable starts to rotate. Note that when the turntable is being switched, the button is set to an invalid state to avoid multiple clicks.
// Prevent multiple clicks m_turnArr-> setEnabled (false); srand (unsigned (time (NULL); float angleZ = rand () % 720 + 720; auto pAction = EaseExponentialOut: create (RotateBy: create (4, Vec3 (0, 0, angleZ); m_turnBg-> runAction (Sequence: create (pAction, CallFunc :: create (CC_CALLBACK_0 (LotteryTurnTest: onTurnEnd, this), NULL ));
Here, we use EaseExponentialOut to control the rotation speed of the turntable.
Of course, when the turntable is being switched, various particle effects are starting to take action. Here we will go to the next part of the article to explain it. Let's take a look at the animation after winning the prize:
// Pop up the prize (LayerColor *) m_pBg-> getChildByTag (100)-> setVisible (true); auto award = Sprite: create ("LotteryTurn/award.png "); award-> setAnchorPoint (Vec2 (0.5, 0); award-> setPosition (Vec2 (m_pBg-> getPositionX (), m_pBg-> getPositionY () * 2 )); this-> addChild (award); auto bounce = EaseBounceOut: create (MoveBy: create (2, Vec2 (0,-m_pBg-> getPositionX () * 2 ))); award-> runAction (Sequence: createWithTwoActions (bounce, CallFuncN: create ([=] (Node * node) {award-> removeFromParentAndCleanup (true); (LayerColor *) m_pBg-> getChildByTag (100)-> setVisible (false); m_turnArr-> setEnabled (true );})));
Let's take a look at the particle effect in the turntable. There are two types. The star flickering effect of the first ring is relatively simple, and it is enough to set the distance from the center, here we will mainly explain the effect of small comet particles rotating with an elliptical trajectory.
Since the trajectory of an ellipse is actually a real-time update of the position of the particle, how can we calculate the coordinates of the ellipse? I think some people have forgotten it (and I have forgotten it too ...), Directly ask du Niang:
The center of the ellipse is the center of the turntable, so it is a standard elliptical equation:
The corresponding parameter equation is:
The answer will come out, as long as we change the parameters in real timePhiThen, the coordinates on the elliptic will be updated in real time. Now that we know the principle, let's take a look at how to design such an elliptical class. Since we are moving along an elliptical trajectory, why not design this Action as the Action in the cocos2dx engine? In use, we only need to call runAction. We can refer to the design of the cocos2dx engine runtime class.
Let's look at the header file:
# Ifndef _ ELLIPSEBY_H _ # define _ ELLIPSEBY_H _ # include "cocos2d. h "USING_NS_CC; # define PI 3.14159 // struct EllipseConfig {// float ellipseA; // float ellipseB; // Center Coordinate Vec2 cenPos of the elliptic; // determines whether to rotate bool isAntiClockwise counterclockwise. // the position where the target starts to rotate. The default position is in the right of the long axis of the elliptic, that is, the value is 0 float startAngle; // float selfAngle of the target;}; class EllipseBy: public ActionInterval {public: EllipseBy ();~ EllipseBy (); // initialization function. The parameter t is the duration, and config is the elliptical parameter static EllipseBy * create (float t, const EllipseConfig & config); bool initWithDuration (float t, const EllipseConfig & config); // update the current elliptical coordinate virtual void update (float time) override every frame; // call virtual void startWithTarget (Node * target) override before the action starts; // copy virtual EllipseBy * clone () const override; // reverse virtual EllipseBy * reverse () const override; protected: // obtain the current vertex on the elliptic Coordinate inline Vec2 & getPosWithEllipse (float t) {float angle = 2 * PI * (m_config.isAntiClockwise? T: (1-t) + m_config.startAngle/360); return Vec2 (m_config.ellipseA * cos (angle), m_config.ellipseB * sin (angle);} private: EllipseConfig m_config ;}; # endif
We have defined EllipseConfig, the structure of an elliptical parameter. The first four are easy to understand. The last two are startAngle, which is the position where the starting rotation particle appears. The value is the angle value. As shown in the following example:
SelfAngle refers to the overall angle of the entire ellipse, which is similar to the rotation attribute of the genie. As shown in the following example:
Next, let's take a look at the three functions inherited from the parent class: startWithTarget, clone, and reverse.
StartWithTarget is used to set who wants to execute the action and call it before the action starts. The latter two are the copy of the action and the other two are the reverse order of the action, because it is a pure virtual function in the parent class, it must be inherited and implemented.
Let's take a look at the getPosWithEllipse function. This function uses the parameter equation of the ellipse to obtain the position of the current target on the elliptic. Because it is constantly called, it is declared as an inline function.
Finally, let's look at some implementation code of the cpp file:
EllipseBy * EllipseBy::clone() const{auto pAction = new EllipseBy();pAction->initWithDuration(_duration, m_config);pAction->autorelease();return pAction;}EllipseBy * EllipseBy::reverse() const{EllipseConfig resConfig = m_config;resConfig.isAntiClockwise = !m_config.isAntiClockwise;return EllipseBy::create(_duration, m_config);}void EllipseBy::startWithTarget(Node *target){ActionInterval::startWithTarget(target);}void EllipseBy::update(float time){if (_target){Vec2 curPos = this->getPosWithEllipse(time);float tmpAngle = m_config.selfAngle / 180 * PI;float newX = curPos.x * cos(tmpAngle) + curPos.y * sin(tmpAngle);float newY = curPos.y * cos(tmpAngle) - curPos.x * sin(tmpAngle);_target->setPosition(m_config.cenPos + Vec2(newX,newY));}}
The most important part is the update function. The coordinate curPos obtained by getPosWithEllipse is0If we set the angle of the ellipse, we need to adjust the coordinates of curPos. There are the following formulas:
If the ellipse is rotated by itselfβ, That is, selfAngle =βThe following coordinates are: newX = xcosβ+ Ysinβ, NewY = ycosβ-Xsinβ
Here we will give you a simple analysis of the formula, first look at the figure:
Here, the black ellipse is not set to selfAngle. When selfAngle is setβThen it becomes a blue ellipse. Because the center of the two ovans is the center of the center, the distance from the point to the center of the oval is the same, that is, the length of the middle red line is equal to that of the Green Line. Then, using the stock theorem is as follows:
A ^ 2 + B ^ 2 = x ^ 2 + y ^ 2 = x ^ 2*1 + y ^ 2*1
Cos & * cos & + sin & * sin & = 1, so:
Above formula = x ^ 2 * (cos (β) ^ 2 + sin (β) ^ 2) + y ^ 2 * (cos (β) ^ 2 + sin (β) ^ 2)
Then, we can get the following formula:
A ^ 2 + B ^ 2 = (xcosβ+ Ysinβ) ^ 2 + (ycosβ-Xsinβ) ^ 2
Therefore: a = xcosβ+ Ysinβ, B = ycosβ-Xsinβ
Finally, we only need to call the following method to perform the same action as using the engine:
// Rotate EllipseConfig config; config. ellipseA = 100; config. ellipseB = 50; config. cenPos = m_turnBg-> getPosition (); config. isAntiClockwise = true; config. startAngle = 0; config. selfAngle = 45; m_pElliRtt_1-> runAction (RepeatForever: create (EllipseBy: create (2.5, config )));
At this point, the content of this article has been explained, and the next article will explain the design of the lottery probability.
Resource download: http://download.csdn.net/detail/sharing_li/8414387
Article 2: http://blog.csdn.net/sharing_li/article/details/43405569