cocos2dx之實現撲克牌翻轉效果的三種方法

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

時間:2015-04-10

作者:Sharing_Li

轉載註明出處:http://blog.csdn.net/sharing_li/article/details/44980493

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


       最近寫一款家鄉的牌類遊戲,自己玩玩,裏面涉及到撲克牌的翻牌效果,這裏簡單來說一下:

       一說到翻轉,我馬上想到了OrbitCamera這個傢伙,雖然很少用,但知道它有這個效果,但代碼寫到一半發現事實情況是這樣的:



        我本意是打算將撲克牌背面轉到90°,也就是與屏幕垂直,這個時候,再把撲克牌正面從90°位置轉到0°即正面。但是同樣是轉到90°,各個背面的顯示不一樣。代碼如下:

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));

    }

        納悶,然後上網查了查文檔,說OrbitCamera是沿屏幕中心進行球面軌跡的旋轉,乍一看不知道說的啥,OrbitCamera::create函數的參數也很多,然後分析了一下,好像知道了個三二一,見下圖:


      所謂的旋轉90°也就是垂直球面指向球心。“上有政策,下有對策”,我這裏弄了一個勉強的解決方案,也就是當動畫運行到上圖停止時,隱藏撲克牌背面,讓事先隱藏(先用orbitcamera旋轉90°再隱藏)的撲克牌正面圖片顯示出來,然後向相反的方向調用orbitcamera旋轉90°。看效果圖:


       在看看代碼實現:

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));
    }

        基本上有模有樣了,這就是第一種方法。第二種方法其實也是用的orbitcamera實現的,勉強湊個數。先看下效果圖:


      可以感覺的到,效果比之前的更流暢。並且只需在之前的代碼基礎上加上一行代碼。第一種方法弄好後,我總感覺可以再優化,剛開始打算這樣弄,以中間的一張圖爲比較對象,將每一張圖的中點,球心,和中間一張圖的中心,構成三角形,比較tan值,從而設置其要旋轉的角度,但是最後失敗了,效果不佳,放棄了。最後,我打算進入到OrbitCamera的源代碼看看。最後看到OrbitCamera::update函數中調用了一個setEye函數,然後突然想到之前第二張分析圖裏的箭頭都指向球心,感覺就像許多眼睛都盯着球心那個地方一樣。然後繼續跟蹤:setEye—》ActionCamera::updateTransform—》Node::setAdditionalTransform,然後發現這句代碼:_transformUpdated = _transformDirty = _inverseDirty =true;這個跟對象的繪製有關,然後在Node.cpp裏找到visit函數,發現跟director在搞鬼,然後繼續跳到director,然後真相大白了。見如下代碼:

/**
     * @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);
}
       然後我在初始化的時候加入下面的代碼,問題就解決了:

Director::getInstance()->setProjection(cocos2d::DisplayLinkDirector::Projection::_2D);

       記得動畫播放完之後,要還原到默認值,也就是_3D,以免對其他部分的顯示造成影響。最後看看第三種方法,用到了ScaleTo,大家可能疑惑爲什麼這個縮放函數可以進行旋轉,當我們對精靈進行如下操作的時候,setScaleX(-1),作用是以Y軸爲對稱軸反轉,爲什麼呢,因爲-1就是從相反的方向進行縮放,如果是-2,就是從相反的方向縮放兩倍。那麼同理,ScaleTo就可以有翻牌的效果啦。看如下用ScaleTo實現的效果圖:



      代碼如下:

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);
    }

到這裏結束了,下載資源

發佈了116 篇原創文章 · 獲贊 102 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章