- A+
所属分类:cocos2dx
图像渲染和动画——动作
Contents
动作
有时限动作(FiniteTimeAction)
- 即时动作(ActionInstant)和持续动作(ActionInterval)
即时动作(ActionInstant)
- 即时动作只能够立刻完成的动作,这类动作是在下一帧立刻完成的动作,如设定位置、设定缩放等。
这里需要注意的是下一帧立刻完成,而不是当前帧。这是由于引擎的动作实现是在一个大的main>这里需要注意的是下一帧立刻完成,而不是当前帧。这是由于引擎的动作实现是在一个大的main loop里面去执行每个动作的update方法。
执行runAction方法只是把动作加入ActionManager而已。
常用即时动作
Place: 该动作用于将节点放置到某个指定位置。
auto placeAction = Place::create(Vec2::ZERO);
- FlipX: 水平翻转
- FlipY: 垂直翻转
- Show: 显示节点
- Hide: 隐藏节点
CallFunc
- CallFunc系列动作包括CallFunc、CallFuncN两个动作,用来在动作中进行方法调用。
一个简单动作的例子(节点显示,然后移动到(0,0)接着水平翻转,再移动回初始位置并隐藏,之后执行匿名函数输出actionMoveDone)
void TestScene1::onTouchEnded( Touch* touch, Event* event )
{
log("onTouchEnded");
auto sprite2 = static_cast<Sprite*>(this->getChildByName("sprite2"));
if (sprite2)
{
auto moveBy = MoveBy::create(0.4f, Vec2::ZERO - sprite2->getPosition());
auto actionMoveDone = CallFunc::create([&](){
log("actionMoveDone");
});
auto actionSeq = Sequence::create(Show::create(), MoveTo::create(0.4f, Vec2::ZERO), FlipX::create(true), moveBy->reverse(), Hide::create(), actionMoveDone, nullptr);
sprite2->runAction(actionSeq);
}
}
moveBy有reverse方法,而moveTo的reverse不可用,因为其_positionDelta值需等到startWithTarget的时候才会进行赋值。想要使用,除非在动作执行完毕后用。
持续动作(ActionInterval)
- 属性变化动作
属性变化动作通过属性值的逐渐变化来实现动画效果。
- MoveTo, MoveBy: 用于使节点做直线运动,设置了动作时间和终点位置,在规定时间内会移动到终点。
- JumpTo, JumpBy: 使节点以一定的轨迹跳跃到指定位置。
- BezierTo, BezierBy: 使节点进行曲线运动,运动的轨迹由贝塞尔曲线描述。
- ScaleTo, ScaleBy: 产生缩放效果,使节点的缩放系数随时间线性变化。
- RotateTo, RotateBy: 产生旋转效果。
贝塞尔曲线: 每条贝塞尔曲线都包含一个起点和一个终点。在一条曲线中,起点和终点各自包含一个控制点,而控制点到端点的连线称作控制线。控制点决定了曲线的形状,包含角度和长度两个参数。
视觉特效动作
该类用来实现特殊视觉效果
- FadeIn, FadeOut, FateTo: 产生淡入淡出效果,和透明变化效果。
- TintTo, TintBy: 设置色调变化,这个动作较少使用。
- Blink: 使节点闪烁。
动画动作(Animate)
以帧动画形式实现动画效果。
- 两种方式创建动画动作
1. 手工动画(Manual animation)
auto animation = Animation::create(); for( int i = 1; i != 15; ++i) { char szName[100] = {0}; sprintf(szName, "grossini_dance_%02d.png", i); animation->addSpriteFrameWithFile(szName); } animation->setDelayPerUnit(2.8f / 14.0f); animation->setRestoreOriginalFrame(true); auto animate = Animate::create(animation);
2. 文件动画(File animation)
auto cache = AnimationCache::getInstance(); cache->addAnimationsWithFile("animations-2.plist"); auto animation1 = cache->getAnimation("dance_1"); auto animate1 = Animate::create(animation1); arrayOfActions.pushBack(animate1);
延时动作(DelayTime)
用来提供一段空白期。
复合动作
- Repeat, RepeatForever:反复执行某个动作。
- Spawn:使一批动作同时执行。
- Sequence: 让各种动作有序执行。
变速动作
- Speed:用于线性的改变某个动作的速度。
- ActionEase:可以实现动作的速度又快到慢、速度随时间改变的匀速运动。该类包含5类运动,指数缓冲、Sine缓冲、弹性缓冲、跳跃缓冲和回震缓冲。每类运动都包含3个不同时期的变换:In、Out和InOut。
- 动作使用例子(推荐使用lambda,可以使代码更简洁)
void TestScene1::onTouchEnded( Touch* touch, Event* event )
{
log("onTouchEnded");
auto visibleSize = Director::getInstance()->getVisibleSize();
auto sprite2 = static_cast<Sprite*>(this->getChildByName("sprite2"));
if (sprite2)
{
auto moveTo = MoveTo::create(0.5f, Vec2::ZERO);
auto easeSinIn = EaseSineIn::create(moveTo);
auto moveBy = MoveBy::create(0.5f, Vec2(visibleSize.width/2, visibleSize.height/2));
auto jumpTo = JumpTo::create(0.5f, Vec2(visibleSize.width/2, visibleSize.height/2), 5, 1);
auto jumpBy = JumpBy::create(0.5f, Vec2(visibleSize.width/2, visibleSize.height/2), 5, 1);
auto rotateTo = RotateTo::create(1.8f, 180);
auto rotateBy = RotateBy::create(1.8f, 180);
auto scaleTo = ScaleTo::create(2.0f, 3);
auto scaleBy = ScaleBy::create(2.0f, 2);
auto repeat = Repeat::create(rotateBy, 3);
auto fadeOut = FadeOut::create(0.8f);
auto fadeIn = FadeIn::create(0.8f);
auto fadeTo = FadeTo::create(0.8f, 200);
auto tintTo = TintTo::create(2.4f, 128, 128, 128);
auto tintBy = TintBy::create(2.4f, 255, 255, 255);
auto blink = Blink::create(2.4f, 12);
auto delayTime = DelayTime::create(1.2f);
// 创建动画的第一种方式:手工动画
auto animation = Animation::create();
for( int i = 1; i != 15; ++i)
{
char szName[100] = {0};
sprintf(szName, "grossini_dance_%02d.png", i);
animation->addSpriteFrameWithFile(szName);
}
animation->setDelayPerUnit(2.8f / 14.0f);
animation->setRestoreOriginalFrame(true);
auto animate = Animate::create(animation);
// 创建动画的第二种方式:文件动画
auto cache = AnimationCache::getInstance();
cache->addAnimationsWithFile("animations-2.plist");
auto animation1 = cache->getAnimation("dance_1");
auto animate1 = Animate::create(animation1);
// 贝塞尔曲线
ccBezierConfig bezier;
bezier.controlPoint_1 = Vec2(0, visibleSize.height);
bezier.controlPoint_2 = Vec2(visibleSize.width, 0);
bezier.endPosition = Vec2(visibleSize.width, visibleSize.height);
auto bezierTo = BezierTo::create(4.8f, bezier);
// 同时执行MoveTo和ScaleTo
auto spawn = Spawn::create(
MoveTo::create(2.0f, Vec2(visibleSize.width/2, visibleSize.height/2)),
scaleTo, nullptr);
auto actionDone = CallFuncN::create([animate](Node* sender){
log("actionDone"); // sender的值会在startWithTarget的时候被设置
auto repeatForever = RepeatForever::create(animate);
auto speed = Speed::create(repeatForever, 0.5f);
sender->runAction(speed);
// PS: speed不能放入Sequence
});
// Sequence的第一种创建方式cocos2d::Vector<cocos2d::FiniteTimeAction*>
cocos2d::Vector<cocos2d::FiniteTimeAction*> arrayOfActions;
arrayOfActions.pushBack(Place::create(Vec2::ZERO));
arrayOfActions.pushBack(bezierTo);
arrayOfActions.pushBack(spawn);
arrayOfActions.pushBack(rotateTo);
arrayOfActions.pushBack(scaleBy);
arrayOfActions.pushBack(repeat);
arrayOfActions.pushBack(fadeOut);
arrayOfActions.pushBack(fadeIn);
arrayOfActions.pushBack(fadeTo);
arrayOfActions.pushBack(tintTo);
arrayOfActions.pushBack(animate);
arrayOfActions.pushBack(delayTime);
arrayOfActions.pushBack(blink);
arrayOfActions.pushBack(tintBy);
arrayOfActions.pushBack(animate1);
arrayOfActions.pushBack(actionDone);
// Sequence的第二种创建方式FiniteTimeAction *action1, ...
auto actionSeq1 = Sequence::create(Show::create(), easeSinIn, moveBy,
moveBy->reverse(), jumpTo, jumpBy,
CallFuncN::create([arrayOfActions](Node* sender){
auto actionSeq2 = Sequence::create(arrayOfActions);
sender->runAction(actionSeq2); // sender在startWithTarget里被设置
}), nullptr);
sprite2->runAction(actionSeq1);
}
}
说明
最后附上lambda表达式的一点说明和控制台输出显示的方法。
- lambda表达式的一点说明:
- [] 不截取任何变量
- [&] 截取外部作用域中所有变量,并作为引用在函数体中使用
- [=] 截取外部作用域中所有变量,并拷贝一份在函数体中使用
- [=, &foo] 截取外部作用域中所有变量,并拷贝一份在函数体中使用,但是对foo变量使用引用。
- [bar] 截取bar变量并且拷贝一份在函数体重使用,同时不截取其他变量
- [this] 截取当前类中的this指针。如果已经使用了&或者=就默认添加此选项。
- 控制台输出显示的方法:
AllocConsole(); freopen("CONOUT$", "w", stdout);