一、摄像机动作


     在前面我们学习过了摄像机类CCCamera,动作中也有一个摄像机类CCOrbitCamera,它是摄像机环绕屏幕中心

转所形成的动作。

1、首先看CCOrbitCamera的使用。

CCOrbitCamera::create(float t,float radius,float deltaRadius,float angleZ,float deltaAngleZ,float angleX,float deltaAngleX)

作用:创建一个球面坐标轨迹进行旋转的动作。

参数1:旋转轨迹所需的时间。

参数2:起始半径。

参数3:半径差。

参数4:起始z角。

参数5:旋转z角差。

参数6:起始x角。

参数7:旋转x角差。



2、示例代码如下所示。


首先新建Cocos2D-X项目,取名为“CCActionOrbit”,然后在HelloWorldScene.cpp文件的init函数中添加如下代码。

[cpp] view plaincopyprint?

  1. bool HelloWorld::init()

  2. {

  3. bool bRet = false;

  4. do

  5. {

  6. CC_BREAK_IF(! CCLayer::init());


  7. //获得尺寸大小

  8. CCSize s = CCDirector::sharedDirector()->getWinSize();


  9. //创建精灵

  10. CCSprite* m_grossini = CCSprite::create("grossini.png");

  11. CCSprite* m_tamara = CCSprite::create("grossinis_sister1.png");

  12. CCSprite* m_kathia = CCSprite::create("grossinis_sister2.png");


  13. //设置精灵的位置

  14. m_grossini->setPosition( ccp(s.width/2, s.height/2));

  15. m_tamara->setPosition( ccp(s.width/4, s.height/2));

  16. m_kathia->setPosition( ccp(3 * s.width/4, s.height/2));


  17. //添加精灵到图层

  18. addChild(m_grossini, 1);

  19. addChild(m_tamara, 2);

  20. addChild(m_kathia, 3);


  21. CCActionInterval*  orbit1 = CCOrbitCamera::create(2,1, 0, 0, 180, 0, 0);

  22. CCSequence*  action1 = CCSequence::create(

  23. orbit1,

  24. orbit1->reverse(),

  25. NULL);


  26. CCActionInterval*  orbit2 = CCOrbitCamera::create(2,1, 0, 0, 180, -45, 0);

  27. CCSequence*  action2 = CCSequence::create(

  28. orbit2,

  29. orbit2->reverse(),

  30. NULL);


  31. CCActionInterval*  orbit3 = CCOrbitCamera::create(2,1, 0, 0, 180, 90, 0);

  32. CCSequence*  action3 = CCSequence::create(

  33. orbit3,

  34. orbit3->reverse(),

  35. NULL);


  36. m_kathia->runAction(CCRepeatForever::create(action1));

  37. m_tamara->runAction(CCRepeatForever::create(action2));

  38. m_grossini->runAction(CCRepeatForever::create(action3));


  39. CCActionInterval*  move = CCMoveBy::create(3, ccp(100,-100));

  40. CCActionInterval*  move_back = move->reverse();

  41. CCSequence*  seq = CCSequence::create(move, move_back, NULL);

  42. CCAction*  rfe = CCRepeatForever::create(seq);


  43. m_kathia->runAction(rfe);

  44. m_tamara->runAction((CCAction*)(rfe->copy()->autorelease()));

  45. m_grossini->runAction((CCAction*)(rfe->copy()->autorelease()));


  46. bRet = true;

  47. } while (0);


  48. return bRet;

  49. }

bool HelloWorld::init()
{
    bool bRet = false;
    do 
    {
        CC_BREAK_IF(! CCLayer::init());

       //获得尺寸大小
		CCSize s = CCDirector::sharedDirector()->getWinSize();

		//创建精灵
        CCSprite* m_grossini = CCSprite::create("grossini.png");
		CCSprite* m_tamara = CCSprite::create("grossinis_sister1.png");
		CCSprite* m_kathia = CCSprite::create("grossinis_sister2.png");

		//设置精灵的位置
		m_grossini->setPosition( ccp(s.width/2, s.height/2));
		m_tamara->setPosition( ccp(s.width/4, s.height/2));
        m_kathia->setPosition( ccp(3 * s.width/4, s.height/2));
       
		//添加精灵到图层
		addChild(m_grossini, 1);
		addChild(m_tamara, 2);
		addChild(m_kathia, 3);
      
		CCActionInterval*  orbit1 = CCOrbitCamera::create(2,1, 0, 0, 180, 0, 0);
		CCSequence*  action1 = CCSequence::create(
        orbit1,
        orbit1->reverse(),
        NULL);

		CCActionInterval*  orbit2 = CCOrbitCamera::create(2,1, 0, 0, 180, -45, 0);
		CCSequence*  action2 = CCSequence::create(
        orbit2,
        orbit2->reverse(),
        NULL);

		CCActionInterval*  orbit3 = CCOrbitCamera::create(2,1, 0, 0, 180, 90, 0);
		CCSequence*  action3 = CCSequence::create(
        orbit3,
        orbit3->reverse(),
        NULL);
	
		m_kathia->runAction(CCRepeatForever::create(action1));
		m_tamara->runAction(CCRepeatForever::create(action2));
		m_grossini->runAction(CCRepeatForever::create(action3));

		CCActionInterval*  move = CCMoveBy::create(3, ccp(100,-100));
		CCActionInterval*  move_back = move->reverse();
		CCSequence*  seq = CCSequence::create(move, move_back, NULL);
		CCAction*  rfe = CCRepeatForever::create(seq);

		m_kathia->runAction(rfe);
		m_tamara->runAction((CCAction*)(rfe->copy()->autorelease()));
		m_grossini->runAction((CCAction*)(rfe->copy()->autorelease()));

        bRet = true;
    } while (0);

    return bRet;
}


旋转的坐标描述采用了球坐标。球坐标采用球面半径、与x轴夹角、与z轴夹角这几个值来描述坐标点。如下图所示。


注意 :在使用摄像机旋转时,如果正在旋转的这个节点后面还有其它节点的话,可能会出现旋转的节点只有一部

分显示出来的这种情况。这时只需要关闭OpenGL的深度检测,获得导演类并调用setDepthTest设置为false即可,如

下面的代码所示:CCDirector::sharedDirector()->setDepthTest(false)。


3、示例效果图。


                       



二、基本样条动作


   在游戏中,有时会希望使用一些非常规轨迹能描述的运动轨迹,希望只是“告诉”游戏对象几个离散的点,游戏对

象就可以根据这些离散的点模拟出相应的路径。当然,有相应的公式模拟出这条曲线,那就是基本样条。Cocos2D-X

中有沿基本样条路径移动动作类CCCardinalSplineTo和其子类实现这样的功能,它的继承关系如下图所示。


     其中CCCardinalSplineTo和CCCardinalSplineBy的关系与之前以“To”和“By”结尾的类类似,CCCatmullRomTo

CCCatmullRomBy也是这样的。它们都是采用基本样条的公式;不同的是,CCCatmullRomTo和CCCatmullRomBy

拉力系数是0.5,而之前的CCCardinalSplineTo和CCCardinalSplineBy的拉力系数是可以自定义的。


1、画基本样条路径


<1> 首先来看CCCardinalSplineTo和CCCardinalSplineBy的使用。

① CCCardinalSplineTo::create(float duration,CCPointArray * points,float tension)

作用:创建一个样条曲线轨迹的动作。

参数1:完成轨迹所需的时间。

参数2:控制点的坐标数组。

参数3:拟合度。其值=0时,路径最柔和。

② CCCardinalSplineBy::create(float duration,CCPointArray * points,float tension)

作用:创建一个样条曲线轨迹的动作。

参数1:完成轨迹所需的时间。

参数2:控制点的坐标数组。

参数3:拟合度。其值=0时,路径最柔和。

CCCardinalSplineBy支持reverse()函数,可以获取其反向动作。

<2> 示例代码如下所示。


首先新建Cocos2D-X项目,取名为“CCActionSpline”,然后在HelloWorldScene.cpp文件的init函数中添加如下代码。

[cpp] view plaincopyprint?

  1. bool HelloWorld::init()

  2. {

  3. bool bRet = false;

  4. do

  5. {

  6. CC_BREAK_IF(! CCLayer::init());


  7. //获得尺寸大小

  8. CCSize s = CCDirector::sharedDirector()->getWinSize();


  9. //创建精灵

  10. CCSprite* m_tamara = CCSprite::create("grossinis_sister1.png");

  11. CCSprite* m_kathia = CCSprite::create("grossinis_sister2.png");


  12. //设置精灵的位置

  13. m_kathia->setPosition( ccp(s.width/3, s.height/2));

  14. m_tamara->setPosition( ccp(2*s.width/3, s.height/2));


  15. //添加精灵到图层        

  16. addChild(m_tamara, 2);

  17. addChild(m_kathia, 3);


  18. CCPointArray *array = CCPointArray::create(20);


  19. array->addControlPoint(ccp(0, 0));

  20. array->addControlPoint(ccp(s.width/2-30, 0));

  21. array->addControlPoint(ccp(s.width/2-30, s.height-80));

  22. array->addControlPoint(ccp(0, s.height-80));

  23. array->addControlPoint(ccp(0, 0));


  24. //

  25. // sprite 1 (By)

  26. //

  27. // Spline with no tension (tension==0)

  28. //


  29. CCCardinalSplineBy *action = CCCardinalSplineBy::create(3, array, 0);

  30. CCActionInterval *reverse = action->reverse();


  31. CCFiniteTimeAction *seq = CCSequence::create(action, reverse, NULL);


  32. m_tamara->setPosition(ccp(50, 50));

  33. m_tamara->runAction(seq);


  34. //

  35. // sprite 2 (By)

  36. //

  37. // Spline with high tension (tension==1)

  38. //


  39. CCCardinalSplineBy *action2 = CCCardinalSplineBy::create(3, array, 1);

  40. CCActionInterval *reverse2 = action2->reverse();


  41. CCFiniteTimeAction *seq2 = CCSequence::create(action2, reverse2, NULL);


  42. m_kathia->setPosition(ccp(s.width/2, 50));

  43. m_kathia->runAction(seq2);


  44. array->retain();


  45. bRet = true;

  46. } while (0);


  47. return bRet;

  48. }

bool HelloWorld::init()
{
    bool bRet = false;
    do 
    {
        CC_BREAK_IF(! CCLayer::init());

         //获得尺寸大小
		CCSize s = CCDirector::sharedDirector()->getWinSize();

		//创建精灵
		CCSprite* m_tamara = CCSprite::create("grossinis_sister1.png");
		CCSprite* m_kathia = CCSprite::create("grossinis_sister2.png");

		//设置精灵的位置
		m_kathia->setPosition( ccp(s.width/3, s.height/2));
        m_tamara->setPosition( ccp(2*s.width/3, s.height/2));
       
		//添加精灵到图层		
		addChild(m_tamara, 2);
		addChild(m_kathia, 3);

		CCPointArray *array = CCPointArray::create(20);
    
		array->addControlPoint(ccp(0, 0));
		array->addControlPoint(ccp(s.width/2-30, 0));
		array->addControlPoint(ccp(s.width/2-30, s.height-80));
		array->addControlPoint(ccp(0, s.height-80));
		array->addControlPoint(ccp(0, 0));
    
		//
		// sprite 1 (By)
		//
		// Spline with no tension (tension==0)
		//
    
		CCCardinalSplineBy *action = CCCardinalSplineBy::create(3, array, 0);
		CCActionInterval *reverse = action->reverse();
    
		CCFiniteTimeAction *seq = CCSequence::create(action, reverse, NULL);
    
		m_tamara->setPosition(ccp(50, 50));
		m_tamara->runAction(seq);
    
		//
		// sprite 2 (By)
		//
		// Spline with high tension (tension==1)
		//
    
		CCCardinalSplineBy *action2 = CCCardinalSplineBy::create(3, array, 1);
		CCActionInterval *reverse2 = action2->reverse();
    
		CCFiniteTimeAction *seq2 = CCSequence::create(action2, reverse2, NULL);
    
		m_kathia->setPosition(ccp(s.width/2, 50));
		m_kathia->runAction(seq2);
   
		array->retain();

        bRet = true;
    } while (0);

    return bRet;
}

   首先定义一个点数组,把路径的点放入数组中。创建基本样条动作时,三个参数分别是动作时间、点数组、拉力系

数。 CCCardinalSplineTo和CCCardinalSplineBy的区别是,由于第一个是绝对的,第二个是相对的,第二个定义点

数组的时候,第一个点最好设置为(0,0),否则起始点会被忽略掉。可以重写布景层的draw函数来把路径画出来。

<3> 示例效果图。

           

2、画Catmull-Rom样条路径

<1> 首先来看CCCatmullRomTo和CCCatmullRomBy的使用。

CCCatmullRomTo::create(float dt,CCPointArray * points)

作用:创建一个样条插值轨迹。

参数1:完成轨迹的时间。

参数2:控制点的坐标数组。


CCCatmullRomBy::create(float dt,CCPointArray * points)

作用:创建一个样条插值轨迹。

参数1:完成轨迹的时间。

参数2:控制点的坐标数组。

CCCatmullRomBy支持reverse()函数,可以获取其反向动作。


<2> 示例代码如下所示。


    首先新建Cocos2D-X项目,取名为“MyCCActionCatmullRom”,然后在HelloWorldScene.cpp文件的init函数中添加如下代码。

[cpp] view plaincopyprint?

  1. bool HelloWorld::init()

  2. {

  3. bool bRet = false;

  4. do

  5. {

  6. CC_BREAK_IF(! CCLayer::init());


  7. //获得尺寸大小

  8. CCSize s = CCDirector::sharedDirector()->getWinSize();


  9. //创建精灵

  10. CCSprite* m_tamara = CCSprite::create("grossinis_sister1.png");

  11. CCSprite* m_kathia = CCSprite::create("grossinis_sister2.png");


  12. //设置精灵的位置

  13. m_kathia->setPosition( ccp(s.width/3, s.height/2));

  14. m_tamara->setPosition(ccp(50, 50));


  15. //添加精灵到图层        

  16. addChild(m_tamara, 2);

  17. addChild(m_kathia, 3);




  18. CCPointArray *array = CCPointArray::create(20);


  19. array->addControlPoint(ccp(0, 0));

  20. array->addControlPoint(ccp(80, 80));

  21. array->addControlPoint(ccp(s.width - 80, 80));

  22. array->addControlPoint(ccp(s.width - 80, s.height - 80));

  23. array->addControlPoint(ccp(80, s.height - 80));

  24. array->addControlPoint(ccp(80, 80));

  25. array->addControlPoint(ccp(s.width / 2, s.height / 2));


  26. CCCatmullRomBy *action = CCCatmullRomBy::create(3, array);

  27. CCFiniteTimeAction *reverse = action->reverse();


  28. CCFiniteTimeAction *seq = CCSequence::create(action, reverse, NULL);


  29. m_tamara->runAction(seq);



  30. //

  31. // sprite 2 (To)

  32. //

  33. // The startPosition is not important here, because it uses a "To" action.

  34. // The initial position will be the 1st point of the Catmull Rom path

  35. //    


  36. CCPointArray *array2 = CCPointArray::create(20);


  37. array2->addControlPoint(ccp(s.width / 2, 30));

  38. array2->addControlPoint(ccp(s.width  -80, 30));

  39. array2->addControlPoint(ccp(s.width - 80, s.height - 80));

  40. array2->addControlPoint(ccp(s.width / 2, s.height - 80));

  41. array2->addControlPoint(ccp(s.width / 2, 30));


  42. CCCatmullRomTo *action2 = CCCatmullRomTo::create(3, array2);

  43. CCFiniteTimeAction *reverse2 = action2->reverse();


  44. CCFiniteTimeAction *seq2 = CCSequence::create(action2, reverse2, NULL);


  45. m_kathia->runAction(seq2);


  46. bRet = true;

  47. } while (0);


  48. return bRet;

  49. }

bool HelloWorld::init()
{
    bool bRet = false;
    do 
    {
        CC_BREAK_IF(! CCLayer::init());

        //获得尺寸大小
		CCSize s = CCDirector::sharedDirector()->getWinSize();

		//创建精灵
		CCSprite* m_tamara = CCSprite::create("grossinis_sister1.png");
		CCSprite* m_kathia = CCSprite::create("grossinis_sister2.png");

		//设置精灵的位置
		m_kathia->setPosition( ccp(s.width/3, s.height/2));
		m_tamara->setPosition(ccp(50, 50));
       
		//添加精灵到图层		
		addChild(m_tamara, 2);
		addChild(m_kathia, 3);

		
    
		CCPointArray *array = CCPointArray::create(20);
    
		array->addControlPoint(ccp(0, 0));
		array->addControlPoint(ccp(80, 80));
		array->addControlPoint(ccp(s.width - 80, 80));
		array->addControlPoint(ccp(s.width - 80, s.height - 80));
		array->addControlPoint(ccp(80, s.height - 80));
		array->addControlPoint(ccp(80, 80));
		array->addControlPoint(ccp(s.width / 2, s.height / 2));
    
		CCCatmullRomBy *action = CCCatmullRomBy::create(3, array);
		CCFiniteTimeAction *reverse = action->reverse();
    
		CCFiniteTimeAction *seq = CCSequence::create(action, reverse, NULL);
    
		m_tamara->runAction(seq);
    
    
		//
		// sprite 2 (To)
		//
		// The startPosition is not important here, because it uses a "To" action.
		// The initial position will be the 1st point of the Catmull Rom path
		//    
    
		CCPointArray *array2 = CCPointArray::create(20);
    
		array2->addControlPoint(ccp(s.width / 2, 30));
		array2->addControlPoint(ccp(s.width  -80, 30));
		array2->addControlPoint(ccp(s.width - 80, s.height - 80));
		array2->addControlPoint(ccp(s.width / 2, s.height - 80));
		array2->addControlPoint(ccp(s.width / 2, 30));
    
		CCCatmullRomTo *action2 = CCCatmullRomTo::create(3, array2);
		CCFiniteTimeAction *reverse2 = action2->reverse();
    
		CCFiniteTimeAction *seq2 = CCSequence::create(action2, reverse2, NULL);
    
		m_kathia->runAction(seq2);

        bRet = true;
    } while (0);

    return bRet;
}


<3> 示例效果图。