cocos2dx之实现扑克牌翻转效果的三种方法

***************************************************************************************

转载出处:http://blog.csdn.net/sharing_li/article/details/44980493

***************************************************************************************


       最近写一款家乡的牌类游戏,自己玩玩,里面涉及到扑克牌的翻牌效果,这里简单来说一下:

       一说到翻转,我马上想到了OrbitCamera这个家伙,虽然很少用,但知道它有这个效果,但代码写到一半发现事实情况是这样的:



        我本意是打算将扑克牌背面转到90°,也就是与屏幕垂直,这个时候,再把扑克牌正面从90°位置转到0°即正面。但是同样是转到90°,各个背面的显示不一样。代码如下:

[cpp]  view plain  copy
  1. for (int j = 1; j <= 16; j++) {  
  2.         m_cardBg.at(j - 1)->runAction(Sequence::create(DelayTime::create(1)  
  3.                                       ,OrbitCamera::create(0.05 + j / 20.0, 1, 0, 0, 90, 0, 0),NULL));  
  4.   
  5.     }  

        纳闷,然后上网查了查文档,说OrbitCamera是沿屏幕中心进行球面轨迹的旋转,乍一看不知道说的啥,OrbitCamera::create函数的参数也很多,然后分析了一下,好像知道了个三二一,见下图:


      所谓的旋转90°也就是垂直球面指向球心。“上有政策,下有对策”,我这里弄了一个勉强的解决方案,也就是当动画运行到上图停止时,隐藏扑克牌背面,让事先隐藏(先用orbitcamera旋转90°再隐藏)的扑克牌正面图片显示出来,然后向相反的方向调用orbitcamera旋转90°。看效果图:


       在看看代码实现:

[cpp]  view plain  copy
  1. for (int j = 1; j <= 16; j++) {  
  2.         m_cardBg.at(j - 1)->runAction(Sequence::create(DelayTime::create(1)  
  3.                                       ,OrbitCamera::create(0.05 + j / 20.0, 1, 0, 0, 90, 0, 0)  
  4.                                        ,Hide::create()  
  5.                                        ,CallFunc::create([=]  
  6.                                                       {  
  7.                                                           m_cardVec.at(j - 1)->runAction(Sequence::create(  
  8.                                                                Show::create(),  
  9.                                                                OrbitCamera::create(0.05 + j / 20.0, 1, 0, 90, -90, 0, 0), NULL));  
  10.                                                       }),NULL));  
  11.           
  12.         m_cardVec.at(j - 1)->runAction(OrbitCamera::create(0.02, 1, 0, 0, 90, 0, 0));  
  13.     }  

        基本上有模有样了,这就是第一种方法。第二种方法其实也是用的orbitcamera实现的,勉强凑个数。先看下效果图:


      可以感觉的到,效果比之前的更流畅。并且只需在之前的代码基础上加上一行代码。第一种方法弄好后,我总感觉可以再优化,刚开始打算这样弄,以中间的一张图为比较对象,将每一张图的中点,球心,和中间一张图的中心,构成三角形,比较tan值,从而设置其要旋转的角度,但是最后失败了,效果不佳,放弃了。最后,我打算进入到OrbitCamera的源代码看看。最后看到OrbitCamera::update函数中调用了一个setEye函数,然后突然想到之前第二张分析图里的箭头都指向球心,感觉就像许多眼睛都盯着球心那个地方一样。然后继续跟踪:setEye—》ActionCamera::updateTransform—》Node::setAdditionalTransform,然后发现这句代码:_transformUpdated = _transformDirty = _inverseDirty =true;这个跟对象的绘制有关,然后在Node.cpp里找到visit函数,发现跟director在搞鬼,然后继续跳到director,然后真相大白了。见如下代码:

[cpp]  view plain  copy
  1. /** 
  2.      * @brief Possible OpenGL projections used by director 
  3.      */  
  4.     enum class Projection  
  5.     {  
  6.         /// Sets a 2D projection (orthogonal projection).  
  7.         _2D,  
  8.           
  9.         /// Sets a 3D projection with a fovy=60, znear=0.5f and zfar=1500.  
  10.         _3D,  
  11.           
  12.         /// It calls "updateProjection" on the projection delegate.  
  13.         CUSTOM,  
  14.           
  15.         /// Default projection is 3D projection.  
  16.         DEFAULT = _3D,  
  17.     };  

[cpp]  view plain  copy
  1. void Director::setProjection(Projection projection)  
  2. {  
  3.     Size size = _winSizeInPoints;  
  4.   
  5.     setViewport();  
  6.   
  7.     switch (projection)  
  8.     {  
  9.         case Projection::_2D:  
  10.         {  
  11.             loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);  
  12. #if CC_TARGET_PLATFORM == CC_PLATFORM_WP8  
  13.             if(getOpenGLView() != nullptr)  
  14.             {  
  15.                 multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, getOpenGLView()->getOrientationMatrix());  
  16.             }  
  17. #endif  
  18.             Mat4 orthoMatrix;  
  19.             Mat4::createOrthographicOffCenter(0, size.width, 0, size.height, -1024, 1024, &orthoMatrix);  
  20.             multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, orthoMatrix);  
  21.             loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);  
  22.             break;  
  23.         }  
  24.               
  25.         case Projection::_3D:  
  26.         {  
  27.             float zeye = this->getZEye();  
  28.   
  29.             Mat4 matrixPerspective, matrixLookup;  
  30.   
  31.             loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);  
  32.               
  33. #if CC_TARGET_PLATFORM == CC_PLATFORM_WP8  
  34.             //if needed, we need to add a rotation for Landscape orientations on Windows Phone 8 since it is always in Portrait Mode  
  35.             GLView* view = getOpenGLView();  
  36.             if(getOpenGLView() != nullptr)  
  37.             {  
  38.                 multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, getOpenGLView()->getOrientationMatrix());  
  39.             }  
  40. #endif  
  41.             // issue #1334  
  42.             Mat4::createPerspective(60, (GLfloat)size.width/size.height, 10, zeye+size.height/2, &matrixPerspective);  
  43.   
  44.             multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, matrixPerspective);  
  45.   
  46.             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);  
  47.             Mat4::createLookAt(eye, center, up, &matrixLookup);  
  48.             multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, matrixLookup);  
  49.               
  50.             loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);  
  51.             break;  
  52.         }  
  53.   
  54.         case Projection::CUSTOM:  
  55.             // Projection Delegate is no longer needed  
  56.             // since the event "PROJECTION CHANGED" is emitted  
  57.             break;  
  58.   
  59.         default:  
  60.             CCLOG("cocos2d: Director: unrecognized projection");  
  61.             break;  
  62.     }  
  63.   
  64.     _projection = projection;  
  65.     GL::setProjectionMatrixDirty();  
  66.   
  67.     _eventDispatcher->dispatchEvent(_eventProjectionChanged);  
  68. }  
       然后我在初始化的时候加入下面的代码,问题就解决了:

[cpp]  view plain  copy
  1. Director::getInstance()->setProjection(cocos2d::DisplayLinkDirector::Projection::_2D);  

       记得动画播放完之后,要还原到默认值,也就是_3D,以免对其他部分的显示造成影响。最后看看第三种方法,用到了ScaleTo,大家可能疑惑为什么这个缩放函数可以进行旋转,当我们对精灵进行如下操作的时候,setScaleX(-1),作用是以Y轴为对称轴反转,为什么呢,因为-1就是从相反的方向进行缩放,如果是-2,就是从相反的方向缩放两倍。那么同理,ScaleTo就可以有翻牌的效果啦。看如下用ScaleTo实现的效果图:



      代码如下:

[cpp]  view plain  copy
  1. for (int j = 1; j <= 16; j++) {  
  2.         m_cardBg.at(j - 1)->runAction(Sequence::create(DelayTime::create(1)  
  3.                                                        ,ScaleTo::create(0.05 + j / 20.0, -1,1),  
  4.                                                        Hide::create()  
  5.                                                        ,CallFunc::create([=]  
  6.                                                                          {  
  7.                                                                              m_cardVec.at(j - 1)->runAction(Sequence::create(  
  8.                                                                                                                              Show::create(),  
  9.                                                                                                                              ScaleTo::create(0.05 + j / 20.0, -1,1), NULL));  
  10.                                                                          }),NULL));  
  11.           
  12.         m_cardVec.at(j - 1)->setFlippedX(true);  
  13.     }  

到这里结束了,免费下载资源


×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

其他翻牌效果参考

先看最终效果:

代码是原创,看到一个棋牌游戏后,自己想办法实现的。

在cocos2dx3.0以上都能直接使用。

使用很简单,传一个扑克牌背面图片路径,正面图片路径,x坐标,y坐标,完成后回调函数就行。


你可能感兴趣的:(游戏,cocos)