一、摄像机动作
在前面我们学习过了摄像机类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?
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;
}
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?
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;
}
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?
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;
}
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>
示例效果图。