赞
踩
动作(Action)的功能就和字面含义一样,它通过改变一个Node对象的属性,让它表现出某种动作。动作对象能实时的改变Node的属性,任何一个对象只要它是Node的子类都能被改变。比如,你能通过动作对象把一个精灵从一个位置移动到另外一个位置。
通过MoveTo和MoveBy方法:
//在两秒内,移动一个精灵到(50,10)的位置
auto moveTo = MoveTo::create(2,Vec2(50,10));
mySprite1->runAction(moveTo);
//在两秒内,相对于当前对象的位置移动到右侧20的位置,横坐标不变
auto moveBy = moveBy::create(2,Vec2(20,0));
mySprite2->runAction(moveBy);
Action* moveAction = MoveBy::create(2.f,Vec2(visibleSize.width/2,0));
里氏替换原则:任何基类可以出现的地方,子类一定可以出现。
sprite->runAction(moveAction);
注意:同一个动作不能执行两次!!
sprite->stopActionByTag(1000);
sprite->stopAllAcitons();
你能注意到,每一个动作都会两个方法By和To。两种方法方便你在不同的情况使用,By算的上是相对于节点对象的当前位置,To算得上是绝对位置,不考虑当前节点对象在哪。如果你想动作的表现是相对于Node当前位置的,就用By,相对的想让动作的表现是按照坐标的绝对位置就用To,看一个例子:
auto MySprite = Sprite::create("mysprite.png");
mySprite->setPosition(Vec(200,256));
//MoveBy - 让精灵在两秒内,在原来x的位置移动500的距离,纵坐标不变
//MoveBy是相对的,原来的x为200,加上移动的距离500,即移动至x=700的位置
auto moveBy = MoveBy::create(2,Vec2(500,mySprite->getPositionY()));
//MoveTo - 让精灵在两秒内直接移动到x为300,y为256的位置
//MoveTo是绝对的,无论如何都会移动(300,256)的位置,不管当前精灵在任何位置
auto MoveTo = MoveTo::create(2,Vec2(300,mySprite->getPositionY()));
//Delay - 制造一小会儿的延迟
auto delay = DelayTime::create(1);
//执行以上三个动作
auto seq = Sequence::create(moveBy,delay,moveTo,nullptr);
mySprite->runAction(seq);
使用MoveTo、MoveBy完成节点对象在一个设置的时间后移动。
auto mySprite = Sprite::create("mysprite.png");
//在2秒内,将精灵移动到特定的位置
auto moveTo = MoveTo::create(2,Vec2(50,0));
mySprite->runAction(moveTo);
//在2秒内,将精灵移动到当前位置的右侧50像素位置,纵坐标不变
auto moveBy = MoveBy::create(2,Vec2(50,0));
mySprite->runAction(moveBy);
使用RotateTo、RotateBy完成节点对象在设置的时间后顺时针旋转指定角度。
auto mySprite = Sprite::create("mysprite.png");
//在2秒内旋转特定的角度
auto rotateTo = RotateTo::create(2.0f,40.0f);
mySprite->runAction(rotateTo);
//在2秒内,基于当前的角度,顺时针旋转40度
auto rotateBy = RotateBy::create(2.0f,40.0f);
mySprite->runAction(rotateBy);
使用ScaleBy、ScaleTo完成节点对象的比例缩放。
auto mySprite = Sprite::create("mysprite.png");
//在2秒内,基于当前的大小,均匀的放大3倍
auto scaleBy = ScaleBy::create(2.0f,3.0f);
mySprite->runAction(scaleBy);
//在2秒内,基于当前大小,x轴缩放到原来的3倍,y轴缩放到原来的3倍
auto scaleBy = ScaleBy::create(2.0f,3.0f,3.0f);
mySprite->runAction(scaleBy);
//在2秒内,均匀缩放绝对大小的3倍
auto scaleTo = ScaleTo::create(2.0f,3.0f);
mySprite->runAction(scaleTo);
//在2秒内,x轴缩放绝对大小的3倍,y轴缩放绝对大小的3倍
auto scaleTo = ScaleTo::create(2.0f,3.0f,3.0f);
mySprite->runAction(scaleTo);
使用FadeIn、FadeOut完成节点对象的淡入,淡出。FadeIn修改节点对象的透明度属性,从完全透明到完成不透明,FadeOut相反。
auto mySprite = Sprite::create("mysprite.png");
//在1秒内让精灵消失
auto fadeIn = FadeIn::create(1.0f);
mySprite->runAction(fadeIn);
//在2秒内让精灵显示
auto fadeOut = FadeOut::create(2.0f);
mySprite->runAction(fadeOut);
使用TintTo、TintBy,将一个实现了NodeRGB协议的节点对象进行色彩混合。
auto mySprite = Sprite::create("mysprite.png");
//用指定的RGH值表示一个节点
auto tintTo = TintTo::create(2.0f,120.0f,232.0f,254.0f);
mySprite->runAction(tintTo);
//对原有RGB值进行增量来表示该节点
auto tintBy = TintBy::create(2.0f,120.0f,232.0f,254.0f);
mySprite->runAction(tintBy);
使用Animate对象可以很容易的通过每隔一个短暂时间进行图像替代的方式,实现一个翻页效果。
示例1:
auto mySprite = Sprite::create("mysprite.png");
//创建动画框架
Vector<SpriteFrame*> animFrames;
animFrames.pushBack(SpriteFrame::create("Blue_Front1.png"),Rect(0,0,65,81));
animFrames.pushBack(SpriteFrame::create("Blue_Front2.png"),Rect(0,0,65,81));
animFrames.pushBack(SpriteFrame::create("Blue_Front3.png"),Rect(0,0,65,81));
animFrames.pushBack(SpriteFrame::create("Blue_Front4.png"),Rect(0,0,65,81));
animFrames.pushBack(SpriteFrame::create("Blue_Front5.png"),Rect(0,0,65,81));
animFrames.pushBack(SpriteFrame::create("Blue_Front6.png"),Rect(0,0,65,81));
animFrames.pushBack(SpriteFrame::create("Blue_Front7.png"),Rect(0,0,65,81));
animFrames.pushBack(SpriteFrame::create("Blue_Front8.png"),Rect(0,0,65,81));
animFrames.pushBack(SpriteFrame::create("Blue_Front9.png"),Rect(0,0,65,81));
animFrames.pushBack(SpriteFrame::create("Blue_Front10.png"),Rect(0,0,65,81));
animFrames.pushBack(SpriteFrame::create("Blue_Front11.png"),Rect(0,0,65,81));
animFrames.pushBack(SpriteFrame::create("Blue_Front12.png"),Rect(0,0,65,81));
//利用动画框架创建动画
Animation* animation = Animation::createWithSpriteFrames(animFrams,0.1f);
Animate* animate = Animate::create(animation);
//循环反复执行动画
mySprite->runAction(RepeatForever::create(animate));
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("hlb1.plist");
Sprite* sprite1 = Sprite::createWithSpriteFrameName("hlb1_1.png");
this->addChild(sprite1);
sprite1->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
//动画实例
Vector<SpriteFrame*> images;
for (int i = 1; i <= 15; i++)
images.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("hlb1_" + Value(i).asString() + ".png"));
Animation* _animation = Animation::createWithSpriteFrames(images, 2.0f / 23);
sprite1->runAction(RepeatForever::create(Animate::create(_animation)));
示例2:
加载图集资源
auto cache = SpriteFrameCache::getInstance();
cache->addSpriteFrameWithFile("vampire/vampire.plist");
创建帧动画精灵
Sprite* vampireSprite = Sprite::createWithSpriteFrameName("1");
创建帧动画
Vector<SpriteFrame*> images;
for(int i=1;i<=8;i++)
{
iamges.pushBack(cache->getSpriteFrameByName(Value(i).asString()));
}
Animation* _animation = Animation::createWithSpriteFrames(images,1.f/8);
vampireSprite->runAction(RepeatForever::create(Animate::create(_animation)));
变速动作可以让节点对象具有加速度,产生平滑同时相对复杂的动作,所以可以用变速动作来模仿一些物理运动,这样比实际使用物理引擎的i性能消耗更低,使用起来也简单。当然也可以将变速动作应用到动画菜单和按钮上,实现想要的效果。
Cocos2d-x支持上图中的大部分变速动作,实现起来也很简单。例子:一个精灵从屏幕顶部落下然后不断跳动:
//创建一个精灵
auto mySprite = Sprite::create("mysprite.png");
//创建一个移动让精灵消失
auto move = MoveBy::create(2,Vec2(200,dirs->getVisibleSize()->height - newSprite2->getContetSize().height));
//创建一个弹跳
auto move_ease_in = EaseBounceIn::create(move->clone());
auto move_ease_in_back = move_ease_in->reverse();
//创建一个延迟
auto delay = DelayTime::create(0.25f);
//创建一个执行顺序
auto seq1 = Sequence::create(move_ease_in,delay,move_ease_in_back,delay->clone(),nullptr);
//循环反复执行
mySprite->runAction(RepeatForever::create(seq1));
动作序列(Sequence)是一种封装多个动作的对象,当这个对象执行时被封装的动作会顺序执行。
一个Sequence可以包含任何数量的动作对象,回调方法和其他序列。可以包含回调方法?没错!Cocos2d-x允许把一个方法添加进去CallFunc对象,然后将callFunc添加到Sequence,这样,在执行序列的时候就能触发方法调用。因此,你能在一个序列中添加一些个性化的功能,而不仅仅是添加Cocos2d-x提供的有限动作。下面是一个序列的动作执行示意图:
什么是回调函数包装器?
TIPS:回调函数一般是在特定的时间点或事件之后执行。
四种回调函数包装器
CallFunc::create(CC_CALLBACK_0(Node::removeFromParent,sprite));//函数指针
CallFuncN::create([sprite](){//lamda表达式,至少要传入一个节点
sprite->removeFromParent();
});
auto mySprite = Sprite::create("mysprite.png");
auto jump = JumpBy::create(0.5,Vec2(0,0),100,1);
auto rotate = RotateTo::create(2.0f,10);
//创建回调方法
auto callbackJump = CallFunc::create([](){
log("Jumped!");
});
auto callbackRotate = CallFunc::create([](){
log("Rotated!");
});
auto seq = Sequence::create(jump,callbackJump,rotate,callbackRotate,nullptr);
mySprite->runAction(seq);
Spawn和Sequence是非常相似的,区别是Spawn同时执行所有的动作。Spawn对象可以添加任意数量的动作和其它Spawn对象。
Spawn的效果和同时运行多个动作的runAction()方法是一致的,但是它的独特之处是Spawn能被放到Sequence中,结合Spawn和Sequence能实现非常强大的动作效果。
例如,创建两个动作:
//创建两个动作
auto mySprite = Sprite::create("mysprite.png");
auto moveBy = MoveBy::create(10,Vec2(400,100));
auto fadeTo = FadeTo::create(2.0f,120.0f);
使用Spawn:
//使用Spawn运行
auto mySpawn = Spawn::createWithTwoActions(moveBy,fadeTo);
mySprite->runAction(mySpawn);
同时调用方法runAction():
//使用runAction()运行上面程序
mySprite->runAction(moveBy);
mySprite->runAction(fadeTo);
上面两种方式的效果是一样的,现在看把一个Spawn添加到一个Sequence中是怎样的一种情景,动作的执行流程会看起来像这样:
auto mySprite = Sprite::create("mysprite.png");
auto moveBy = MoveBy::create(10,Vec2(400,100));
auto fadeTo = FadeTo::create(2.0f,120.0f);
auto scaleBy = ScaleBy::create(2.0f,3.0f);
auto mySpawn = Spawn::createWithTwoActions(scaleBy,fadeTo);
auto seq = Sequence::create(moveBy,mySpawn,moveBy,nullptr);
mySprite->runAction(seq);
克隆(clone)的功能和字面含义一样,如果你对一个节点对象使用了clone()
方法,你就获得了这个节点对象的拷贝。
为什么要使用clone()方法?因为当Action对象运行时会产生一个内部状态,记录着节点属性的改变。当你想将一个创建的动作,重复使用到不同的节点对象时,如果不用**clone()**方法,就无法确定这个动作的属性到底是怎么样的(因为被使用过,产生了内部状态),这会造成难以预料的结果。
我们来看示例,假如你有一个坐标位置是(0,0)的heroSprite,执行这一个动作:
MoveBy::create(10,Vec2(400,100));
你的heroSprite就在10s的时间中,从(0,0)移动到了(400,100),heroSprite有了一个新位置(400,100),更重要的是动作对象也有了节点位置相关的内部状态了。现在假如你有一个坐标位置是(200,200)的emenySprite。你还是用这个相同的动作,emenySprite就会移动到(800,200)的坐标位置(会使用当前的内部状态作为起点,再次基于当前坐标x轴移动400,y轴移动100),并不是你期待的结果。因为第二次将这个动作应用的时候,它已经又内部状态了。使用**clone()**能避免这种情况,克隆获得一个新的动作对象,新的对象没有之前的内部状态。
以下是错误示例:
auto heroSprite = Sprite::create("herosprite.png");
auto enemySprite = Sprite::create("enemySprite.png");
auto MoveBy = MoveBy::create(10,Vec2(400,100));
heroSprite->runAction(moveBy);
//moveBy内部状态记录的坐标作为起始坐标
enemySprite->runAction(moveBy);
使用clone()
的正确情况:
auto heroSprite = Sprite::create("herosprite.png");
auto enemySprite = Sprite::create("enemysprite.png");
auto moveBy = MoveBy::create(10,Vec2(400,100));
heroSprite->runAction(moveBy);
enemySprite->runAction(moveBy->clone());
倒转(Reverse)的功能也和字面意思一样,调用reverse()可以让一系列动作按相反的方向执行。reserve()不是只能简单的让一个Action对象反向执行,还能让Sequence和Spawn倒转。
倒转使用起来很简单:
mySprite->runAction(mySpawn->reverse());
以下示例:
auto mySprite->Sprite::create("mysprite.png");
mySprite->setPosition(50,56);
auto moveBy = MoveBy::create(2.0f,Vec2(500,0));
auto scaleBy = ScaleBy::create(2.0f,2.0f);
auto delay = DelayTime::create(2.0f);
auto delaySequence = Sequence::create(delay,delay->clone(),delay->clone(),delay->clone(),nullptr);
auto sequence = Sequence::create(moveBy,delay,scaleBy,delaySequence,nullptr);
mySprite->runAction(sequence);
mySprite->runAction(sequence->reverse());
执行步骤如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。