Cocos2dx: three methods for implementing playing card flip effect: cocos2dx playing card
**************************************** **************************************** *******
Time: 2015-04-10
Author: Sharing_Li
Reprinted with the source: http://blog.csdn.net/sharing_li/article/details/44980493
**************************************** **************************************** *******
I recently wrote a card game in my hometown. I am playing it myself. It involves the flop effect of playing cards. Here I will simply say:
When it comes to flip, I immediately thought of the OrbitCamera guy. Although it is rarely used, I know it has this effect, but half of the Code is written to find that the fact is like this:
I intend to turn the back of the playing card to 90 °, that is, perpendicular to the screen. At this time, I will turn the front of the playing card from 90 ° to 0 °, that is, the front. But it is also converted to 90 °, the display on each back is different. The Code is as follows:
for (int j = 1; j <= 16; j++) { m_cardBg.at(j - 1)->runAction(Sequence::create(DelayTime::create(1) ,OrbitCamera::create(0.05 + j / 20.0, 1, 0, 0, 90, 0, 0),NULL)); }
Wondering, I checked the documents online and said that OrbitCamera is rotating the spherical track along the center of the screen. At first glance, I don't know what to say. There are many parameters for the OrbitCamera: create Function, then, I analyzed it. It seems that I have learned three or two items. For details, see:
The so-called rotation 90 ° means that the vertical sphere points to the ball center. "There are policies and countermeasures." I got a stubborn solution here, that is, when the animation stops running, it hides the back of the playing card, show the front picture of the playing card that is hidden beforehand (rotated 90 ° with orbitcamera) and call orbitcamera to rotate 90 ° in the opposite direction. See:
Let's look at the code implementation:
for (int j = 1; j <= 16; j++) { m_cardBg.at(j - 1)->runAction(Sequence::create(DelayTime::create(1) ,OrbitCamera::create(0.05 + j / 20.0, 1, 0, 0, 90, 0, 0) ,Hide::create() ,CallFunc::create([=] { m_cardVec.at(j - 1)->runAction(Sequence::create( Show::create(), OrbitCamera::create(0.05 + j / 20.0, 1, 0, 90, -90, 0, 0), NULL)); }),NULL)); m_cardVec.at(j - 1)->runAction(OrbitCamera::create(0.02, 1, 0, 0, 90, 0, 0)); }
This is the first method. The second method is actually implemented using orbitcamera, and the number is barely merged. Let's take a look at it first:
You can feel that the effect is smoother than before. You only need to add a line of code based on the previous code. After the first method is completed, I always feel that I can optimize it again. At the beginning, I plan to make it like this. Take a picture in the middle as a comparison object and set the midpoint, ball, and, and the center of the Middle graph, which forms a triangle, compares the tan value, and sets the angle to rotate, but finally fails, the effect is not good, give up. Finally, I plan to go to the OrbitCamera source code. Finally, we can see that the OrbitCamera: update function calls a setEye function. Then we suddenly think that the arrows in the second analysis chart all point to the ball center, just like a lot of eyes staring at the Ball center. Continue to trace: setEye-ActionCamera: updateTransform-Node: setAdditionalTransform, and find the code: _ transformUpdated = _ transformDirty = _ inverseDirty = true; this is related to object painting, and then in Node. find the visit function in cpp and find that it is playing tricks with ctor. Then, continue to jump to director, and the truth is displayed. See the following code:
/** * @brief Possible OpenGL projections used by director */ enum class Projection { /// Sets a 2D projection (orthogonal projection). _2D, /// Sets a 3D projection with a fovy=60, znear=0.5f and zfar=1500. _3D, /// It calls "updateProjection" on the projection delegate. CUSTOM, /// Default projection is 3D projection. DEFAULT = _3D, };
void Director::setProjection(Projection projection){ Size size = _winSizeInPoints; setViewport(); switch (projection) { case Projection::_2D: { loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);#if CC_TARGET_PLATFORM == CC_PLATFORM_WP8 if(getOpenGLView() != nullptr) { multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, getOpenGLView()->getOrientationMatrix()); }#endif Mat4 orthoMatrix; Mat4::createOrthographicOffCenter(0, size.width, 0, size.height, -1024, 1024, &orthoMatrix); multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, orthoMatrix); loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); break; } case Projection::_3D: { float zeye = this->getZEye(); Mat4 matrixPerspective, matrixLookup; loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); #if CC_TARGET_PLATFORM == CC_PLATFORM_WP8 //if needed, we need to add a rotation for Landscape orientations on Windows Phone 8 since it is always in Portrait Mode GLView* view = getOpenGLView(); if(getOpenGLView() != nullptr) { multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, getOpenGLView()->getOrientationMatrix()); }#endif // issue #1334 Mat4::createPerspective(60, (GLfloat)size.width/size.height, 10, zeye+size.height/2, &matrixPerspective); multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, matrixPerspective); Vec3 eye(size.width/2, size.height/2, zeye), center(size.width/2, size.height/2, 0.0f), up(0.0f, 1.0f, 0.0f); Mat4::createLookAt(eye, center, up, &matrixLookup); multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, matrixLookup); loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); break; } case Projection::CUSTOM: // Projection Delegate is no longer needed // since the event "PROJECTION CHANGED" is emitted break; default: CCLOG("cocos2d: Director: unrecognized projection"); break; } _projection = projection; GL::setProjectionMatrixDirty(); _eventDispatcher->dispatchEvent(_eventProjectionChanged);}
Then I added the following code during initialization to solve the problem:
Director::getInstance()->setProjection(cocos2d::DisplayLinkDirector::Projection::_2D);
Remember to restore the animation to the default value, that is, _ 3D, to avoid affecting the display of other parts. Finally, let's look at the third method. With ScaleTo, you may wonder why this scaling function can be rotated. When we perform the following operations on the genie, setScaleX (-1 ), the Y axis is used as the axis of symmetry reversal. Why? Because-1 is scaled in the opposite direction. If it is-2, it is scaled twice in the opposite direction. In the same way, ScaleTo can be used as a flop. See the following implementation using ScaleTo:
The Code is as follows:
for (int j = 1; j <= 16; j++) { m_cardBg.at(j - 1)->runAction(Sequence::create(DelayTime::create(1) ,ScaleTo::create(0.05 + j / 20.0, -1,1), Hide::create() ,CallFunc::create([=] { m_cardVec.at(j - 1)->runAction(Sequence::create( Show::create(), ScaleTo::create(0.05 + j / 20.0, -1,1), NULL)); }),NULL)); m_cardVec.at(j - 1)->setFlippedX(true); }
This is the end. Resources are downloaded for free.