Cocos2d-x人物动作类实例

我们玩的游戏一般都可以看到精灵的运动,游戏的世界就是一个运动的世界,而所有的这些动作都可以分为一些基本的动作和动作的组合,今天就来学习一下动作类CCAction,首先看一下类之间的继承关系。

CCAction类下派生了三个动作类,执行动作的类是CCNode以及它的子类,通过函数runAction()来执行动作,其中CCFiniteTimeAction之下是常用的瞬时动作和延时动作。动作从本质上来说就是改变节点的属性,瞬时动作就是改变这些属性不需要时间,瞬时就完成了,而延时动作改变这些属性需要一些时间,可以通过参数来设置这个时间,下面是瞬时动作和延时动作的例子,解释看源代码。点击下图查看效果。

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

    CC_BREAK_IF(! CCLayer::init());

		//创建一个精灵
		CCSprite * sprite = CCSprite::create("image.png");
		sprite->setPosition(ccp(240,160));
		//最后一个参数是精灵的tag,以便在众多的子节点中,通过getChildByTag()找到该节点
		this->addChild(sprite,0,0);

		//创建菜单
		CCMenuItemFont * fontMenu1 = CCMenuItemFont::create("start");
		CCMenuItemFont * fontMenu2 = CCMenuItemFont::create("stop");
		//和move函数相互绑定
		CCMenuItemToggle * toggleMenu = CCMenuItemToggle::createWithTarget(this,menu_selector(HelloWorld::move),
			fontMenu1,fontMenu2,NULL);
		CCMenu * menu = CCMenu::create(toggleMenu,NULL);
		menu->setPosition(ccp(420,40));
		this->addChild(menu);

    bRet = true;
  } while (0);

  return bRet;
}

void HelloWorld::move(CCObject* pSender)
{
	//通过tag获得添加的精灵
	CCSprite * sprite = (CCSprite *)this->getChildByTag(0);
	CCMenuItemToggle * toggleMenu = (CCMenuItemToggle *)pSender;

	//瞬时动作CCPlace,改变了精灵的坐标,可以用sprite->setPosition(ccp(60,160))代替,但写成动作可以加入到动作序列中
	CCPlace * action1 = CCPlace::create(ccp(60,160));
	//瞬时动作,使精灵做X轴的翻转
	CCFlipX * action2 = CCFlipX::create(true);

	if(toggleMenu->getSelectedIndex() == 1)
	{
		//通过runAction精灵执行动作
		sprite->runAction(action2);
	}
	else if(toggleMenu->getSelectedIndex() == 0)
	{

	}
}

void HelloWorld::move(CCObject* pSender)
{
	//通过tag获得添加的精灵
	CCSprite * sprite = (CCSprite *)this->getChildByTag(0);
	CCMenuItemToggle * toggleMenu = (CCMenuItemToggle *)pSender;

	//延时动作,第一个参数是执行动作所需要的时间,moveTo是绝对的,就是移动到哪个坐标,而moveBy是相对的
	//传入的ccp(10,0)是一个向量,精灵沿着x轴移动了10个像素
	CCMoveTo * moveTo = CCMoveTo::create(2.0,ccp(240,180));
	CCMoveBy * moveBy = CCMoveBy::create(2.0,ccp(10,0));
	//rotate按照一定的角度旋转,to强调的是结果,现在是0度,会旋转到90度,如果现在是90度,还是会在90度
	CCRotateTo * rotateTo = CCRotateTo::create(2.0,90);
	//by强调旋转的相对角度,不论现在多少度都会旋转90度,以to和by结尾的动作类都是相同的道理
	CCRotateBy * rotateBy = CCRotateBy::create(2.0,90);

	if(toggleMenu->getSelectedIndex() == 1)
	{
		//通过runAction精灵执行动作
		//sprite->runAction(moveTo);
		//sprite->runAction(moveBy);
		sprite->runAction(rotateBy);
	}
	else if(toggleMenu->getSelectedIndex() == 0)
	{

	}
}

以by结尾的延时动作都可以通过reverse()获得它的反动作。

void HelloWorld::move(CCObject* pSender)
{
	//通过tag获得添加的精灵
	CCSprite * sprite = (CCSprite *)this->getChildByTag(0);
	CCMenuItemToggle * toggleMenu = (CCMenuItemToggle *)pSender;

	//第二个参数是跳跃的向量,第三个参数是跳跃的高度,第四个参数是跳跃的次数
	CCJumpBy * jumpBy = CCJumpBy::create(2.0,ccp(100,30),50,4);
	//以by结尾的延时动作都可以通过reverse()获得它的反动作
	CCActionInterval * jumpBack = jumpBy->reverse();

	if(toggleMenu->getSelectedIndex() == 1)
	{
		//通过runAction精灵执行动作
		sprite->runAction(jumpBy);
	}
	else if(toggleMenu->getSelectedIndex() == 0)
	{
		sprite->runAction(jumpBack);
	}
}

延时动作中还有俩个重复动作的函数,就是重复不断的执行某一个动作,看下他们的继承关系。

下面是实现的源代码。

void HelloWorld::move(CCObject* pSender)
{
	//通过tag获得添加的精灵
	CCSprite * sprite = (CCSprite *)this->getChildByTag(0);
	CCMenuItemToggle * toggleMenu = (CCMenuItemToggle *)pSender;

	//第一个参数传入重复的动作,第二个参数传入重复的次数
	CCRepeat * repeat = CCRepeat::create(rotateBy,4);
	//永远重复执行一个动作
	CCRepeatForever * repeatForever = CCRepeatForever::create(rotateBy);

	if(toggleMenu->getSelectedIndex() == 1)
	{
		//通过runAction精灵执行动作
		sprite->runAction(repeatForever);
	}
	else if(toggleMenu->getSelectedIndex() == 0)
	{

	}
}

下面再列举一下基本常用的瞬时动作和延续动作。
瞬时动作:
放置Place:效果类似于 setPosition = ccp(x, y)。
隐藏Hide:效果类似于setVisible:false。
显示Show:效果类似于setVisible:true。
可见切换:ToggleVisibility。
延时动作:
移动到CCMoveTo
移动CCMoveBy
跳跃到CCJumpTo设置终点位置和跳跃的高度和次数。
跳跃CCJumpBy设置终点位置和跳跃的高度和次数。
贝塞尔CCBezierBy支持 3 次贝塞尔曲线:P0-起点,P1-起点切线方向,P2-终点切线方向,P3-终点。
放大到CCScaleTo设置放大倍数,是浮点型。
放大CCScaleBy
旋转到CCRotateTo
旋转CCRotateBy
闪烁CCBlink设定闪烁次数
色调变化到CCTintTo
色调变换CCTintBy
变暗到CCFadeTo
由无变亮CCFadeIn
由亮变无CCFadeOut
每个函数的具体用法请大家自行试验。
接下来说一下同步动作序列和顺序动作序列。同步动作序列,就是几个动作同时执行,顺序动作序列,就是传入的几个动作按照顺序顺序执行。以下是他们的继承关系图。

接下来看一下实现的源代码

void HelloWorld::move(CCObject* pSender)
{
	//通过tag获得添加的精灵
	CCSprite * sprite = (CCSprite *)this->getChildByTag(0);
	CCMenuItemToggle * toggleMenu = (CCMenuItemToggle *)pSender;

	//创建如下几个动作

	CCMoveBy * move = CCMoveBy::create(2.0,ccp(100,0));
	CCRotateBy * rotate = CCRotateBy::create(2.0,720);

	CCFiniteTimeAction * moveBack = move->reverse();
	CCFiniteTimeAction * rotateBack = rotate->reverse();

	CCFlipY * flip = CCFlipY::create(true);

	//同步动作序列,传入的几个动作同时执行,执行的整个时间是最长的一个动作的执行时间,参数类型是CCFiniteTimeAction
	//传入的动作(动作的实质就是改变节点的属性)所影响的属性不要有冲突
	CCSpawn * spawn = CCSpawn::create(move,rotate,NULL);
	CCSpawn * spawnBack = CCSpawn::create(moveBack,rotateBack,NULL);

	//顺序动作序列,传入的几个动作按照传入的顺序顺序执行,执行的整体时间是所有动作的时间之和
	CCSequence * sequence = CCSequence::create(move,rotate,flip,NULL);
	CCSequence * sequenceBack = CCSequence::create(moveBack,rotateBack,flip->reverse(),NULL);

	if(toggleMenu->getSelectedIndex() == 1)
	{
		sprite->runAction(spawn);
		//sprite->runAction(sequence);
	}
	else if(toggleMenu->getSelectedIndex() == 0)
	{
		sprite->runAction(spawnBack);
		//sprite->runAction(sequenceBack);
	}
}

接下来介绍CCAction的另外来个子类,CCFollow实现镜头跟随的效果,类似于我们在横版过关游戏中看到的人物永远在屏幕中间,而背景在移动,不过它们的实现具体是不是靠这个类就不知道了。CCSpeed可以实现快进和慢放的效果,就是改变了执行的速度。以下是源代码。

void HelloWorld::move(CCObject* pSender)
{
	//通过tag获得添加的精灵
	CCSprite * sprite = (CCSprite *)this->getChildByTag(0);
	CCMenuItemToggle * toggleMenu = (CCMenuItemToggle *)pSender;

	//创建如下几个动作

	CCMoveBy * move = CCMoveBy::create(2.0,ccp(100,0));
	CCRotateBy * rotate = CCRotateBy::create(2.0,720);

	CCFiniteTimeAction * moveBack = move->reverse();
	CCFiniteTimeAction * rotateBack = rotate->reverse();

	CCFlipY * flip = CCFlipY::create(true);

	//同步动作序列,传入的几个动作同时执行,执行的整个时间是最长的一个动作的执行时间,参数类型是CCFiniteTimeAction
	//传入的动作(动作的实质就是改变节点的属性)所影响的属性不要有冲突
	CCSpawn * spawn = CCSpawn::create(move,rotate,NULL);
	CCSpawn * spawnBack = CCSpawn::create(moveBack,rotateBack,NULL);

	//顺序动作序列,传入的几个动作按照传入的顺序顺序执行,执行的整体时间是所有动作的时间之和
	CCSequence * sequence = CCSequence::create(move,rotate,flip,NULL);
	CCSequence * sequenceBack = CCSequence::create(moveBack,rotateBack,flip->reverse(),NULL);

	//CCFollow实现一个节点跟随一个节点运动,传入的参数是要跟随的节点
	CCFollow * follow = CCFollow::create(sprite);
	//执行这个动作的是要跟随的节点,一般是层,效果累世于横版过关游戏中的场景
	this->runAction(follow);

	if(toggleMenu->getSelectedIndex() == 1)
	{
		sprite->runAction(spawn);
		//sprite->runAction(sequence);
	}
	else if(toggleMenu->getSelectedIndex() == 0)
	{
		sprite->runAction(spawnBack);
		//sprite->runAction(sequenceBack);
	}
}

以下是CCSpeed的实现,在上述代码的基础上做了一点修改。

void HelloWorld::move(CCObject* pSender)
{
	//通过tag获得添加的精灵
	CCSprite * sprite = (CCSprite *)this->getChildByTag(0);
	CCMenuItemToggle * toggleMenu = (CCMenuItemToggle *)pSender;

	//创建如下几个动作

	CCMoveBy * move = CCMoveBy::create(2.0,ccp(100,0));
	CCRotateBy * rotate = CCRotateBy::create(2.0,720);

	CCFiniteTimeAction * moveBack = move->reverse();
	CCFiniteTimeAction * rotateBack = rotate->reverse();

	CCFlipY * flip = CCFlipY::create(true);

	//同步动作序列,传入的几个动作同时执行,执行的整个时间是最长的一个动作的执行时间,参数类型是CCFiniteTimeAction
	//传入的动作(动作的实质就是改变节点的属性)所影响的属性不要有冲突
	CCSpawn * spawn = CCSpawn::create(move,rotate,NULL);
	CCSpawn * spawnBack = CCSpawn::create(moveBack,rotateBack,NULL);

	//顺序动作序列,传入的几个动作按照传入的顺序顺序执行,执行的整体时间是所有动作的时间之和
	CCSequence * sequence = CCSequence::create(move,rotate,flip,NULL);
	CCSequence * sequenceBack = CCSequence::create(moveBack,rotateBack,flip->reverse(),NULL);

	//CCFollow实现一个节点跟随一个节点运动,传入的参数是要跟随的节点
	CCFollow * follow = CCFollow::create(sprite);
	//执行这个动作的是要跟随的节点,一般是层,效果累世于横版过关游戏中的场景
	this->runAction(follow);

	//CCSpeed分装了一个动作类,第二个参数是要改变的速度的倍数
	CCSpeed * speed1 = CCSpeed::create(spawn,2.0);
	CCSpeed * speed2 = CCSpeed::create(spawnBack,2.0);

	if(toggleMenu->getSelectedIndex() == 1)
	{
		sprite->runAction(speed1);
		//sprite->runAction(sequence);
	}
	else if(toggleMenu->getSelectedIndex() == 0)
	{
		sprite->runAction(speed2);
		//sprite->runAction(sequenceBack);
	}
}

以下再来介绍一下CCCallFunc家族类的使用方法,它们也是一个动作类,一般用在顺序动作序列中执行的最后一个动作,目的是调用一个函数,来完成一些功能。以下是这些类的继承关系。

接下来贴上源代码,注释是对各个类的使用的详细讲解。

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

		CCSprite * sprite = CCSprite::create("image.png");
		sprite->setPosition(ccp(240,160));
		this->addChild(sprite,0,0);

		//创建一个菜单,添加一个run事件
		CCMenuItemFont * fontMenu = CCMenuItemFont::create("begin",this,menu_selector(HelloWorld::run));
		CCMenu * menu = CCMenu::create(fontMenu,NULL);
		menu->setPosition(ccp(400,40));
		this->addChild(menu);

    bRet = true;
  } while (0);

  return bRet;
}

void HelloWorld::run(CCObject* pSender)
{
	CCSprite * sprite = (CCSprite *)this->getChildByTag(0);

	//创建延时动作
	CCRotateBy * rotate = CCRotateBy::create(2.0,3*360);
	//CCCallFunc,为这个动作绑定一个函数,执行这个动作的时候会调用这个函数,创建以下四个动作的时候使用了不同的选择器,但名字和各个动作有关
	CCCallFunc * func = CCCallFunc::create(this,callfunc_selector(HelloWorld::show));
	//CCCallFuncN(N就是node的意思),与上边不同的是,绑定的函数需要一个参数,这个传入的参数就是执行这个动作的节点
	CCCallFuncN * funcN = CCCallFuncN::create(this,callfuncN_selector(HelloWorld::remove));
	int num = 10;
	//CCCallFuncND(D就是data的意思),这次绑定的函数,不仅需要绑定动作的节点作为参数传递,还带了一个void *类型的参数,代表可以是任何类型
	CCCallFuncND *funcND = CCCallFuncND::create(this,callfuncND_selector(HelloWorld::showData),(void *)num);
	CCSprite * sprite2 = CCSprite::create("image2.png");
	//CCCallFuncO(O就是object的意思)这次需要传入的参数是CCObject *类型的
	CCCallFuncO * funcO = CCCallFuncO::create(this,callfuncO_selector(HelloWorld::showSprite),sprite2);

	//创建顺序动作序列
	//CCSequence * sequence = CCSequence::create(rotate,func,funcND,NULL);
	//CCSequence * sequence = CCSequence::create(rotate,func,funcN,NULL);
	CCSequence * sequence = CCSequence::create(rotate,func,funcN,funcO,NULL);

	sprite->runAction(sequence);
}

//以下函数不要忘记在头文件中声明,注意每个函数的参数
void HelloWorld::show()
{
	CCLabelTTF * ttf = CCLabelTTF::create("action end","Arial",32);
	ttf->setPosition(ccp(240,260));
	this->addChild(ttf);
}

void HelloWorld::remove(CCNode * node)
{
	//没有通过getChildByTag()函数获得执行动作的精灵,而是使用remove传来的参数
	CCSprite * sprite = (CCSprite *)node;
	//true表示sprite不仅会移除,而且这个节点上的所有操作和回调都将删除
	sprite->removeFromParentAndCleanup(true);
	//通过以下的方法可以实现相同的效果,只是函数执行的对象不同
	//this->removeChild(sprite,true);
}

void HelloWorld::showData(CCNode * node,void * data)
{
	CCSprite * sprite = (CCSprite *)node;
	this->removeChild(sprite,true);
	CCLog("num = %d",data);
}

void HelloWorld::showSprite(CCObject * sender)
{
	CCSprite * sprite = (CCSprite *)sender;
	sprite->setPosition(ccp(240,160));
	this->addChild(sprite);
}
(0)

相关推荐

  • cocos2dx骨骼动画Armature源码剖析(一)

    cocos2dx从编辑器(cocostudio或flash插件dragonBones)得到xml或json数据,调用类似如下所示代码就可以展示出动画效果 ArmatureDataManager::getInstance()->addArmatureFileInfoAsync( "armature/Dragon.png", "armature/Dragon.plist", "armature/Dragon.xml", this, schedu

  • iOS开发中使用cocos2d添加触摸事件的方法

    CCLayer类是用来接收触摸输入的.不过你要首先启用这个功能才可以使用它.你通过设置isTouchEnabled为YES来让层接收触摸事件: 复制代码 代码如下: self.isTouchEnabled = YES; 此项设定最好在init方法中设置.你可以在任何时间将其设置为NO或者YES. 一旦启用isTouchEnabled属性,许多与接收触摸输入相关的方法将会开始被调用.这些事件包括:当新的触摸开始的时候,当手指在触摸屏上移动的时候,还有在用户手指离开屏幕以后.很少会发生触摸事件被取消

  • cocos2dx骨骼动画Armature源码剖析(三)

    cocos2dx里骨骼动画代码在cocos -> editor-support -> cocostudio文件夹中,win下通过筛选器,文件结构如下.(mac下没有分,是整个一坨) armature(目录): animation(目录):动画控制相关. CCProcessBase(文件): ProcessBase(类):CCTween和ArmatureAnimation的基类. CCTWeen(文件): Tween(类):控制flash里一个layer的动画. CCArmatureAnimat

  • Cocos2d-x 3.x入门教程(二):Node节点类

    千里之行,始于足下 上一篇文章<菜鸟学习Cocos2d-x 3.x--基础概念>中介绍了以下Cocos2d-x的基本结构和一些重要的类,而这里开始对这些重要的类进行单独的介绍与分析.开始吧~~~ Node节点类 Node类是Cocos2d-x中一个非常重要的类,它继承自类Ref,关于Ref类,Ref类是一个内存管理的类,我后续也会总结的,这里就不做多说了. Node类在Cocos2d-x中有多重要呢?任何需要画在屏幕上的对象都是节点类.最常用的节点类包括场景类(Scene).布景层类(Laye

  • Cocos2d-x中CCEditBox文本输入框的使用实例

    文本输入框这个东西相信大家不论做什么游戏总会用到吧,今天我们就来看看这个东西如何使用.文本输入框同样属于扩展库中的内容,所以你知道怎么做了吧.当用户要在文本框中输入内容,这一系列的过程我们需要一些函数的调用来获得我们想要的东西,包含这些函数的类需要实现CCEditBoxDelegate这个接口,下面我们来看看具体如何使用吧. #ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h"

  • Cocos2d-x中调用Lua及HelloWorld.lua源码分解

    Lua脚本,以前我不知道它有多强大,但是当我做了1年的手机网游之后,起码我发现了,更新客户端是一件很恐怖的事情(会导致大量玩家的流失,以及有一个漫长并且惊心动魄的审核过程),太扯了.于是,如果可以只更新脚本,那就不需要玩家重新下载客户端了,直接在线更新,嗯嗯,虽然我发现了这个,但是还没有实现.噗,代码写烂了,不好改.   所以啊,我已经做好准备了,如果下次用cocos2d-x开发,lua不可少啊~!   看看官方的例子吧,先来AppDelegate.cpp的applicationDidFinis

  • Cocos2d-x中实现弹出对话框示例

    在游戏中我们经常会看到弹出一个对话框让我们进行选择,今天我们就在cocos2dx中实现这个对话框.对话框说白了也是一个层,当我们点击某一个按钮的时候这个层被加进了当前的场景中,同时场景中的其他的层都是不可点击的,这个时候就涉及到触摸的优先级的一些问题,当然有些时候你也可以根据自己的需要让其他的层也可以点击,但是道理都是一样的,学会了这个其他的按照自己的要求去实现吧.下面我将弹出层单独分装成一个类,供我们调用. /*对话框场景类的头文件*/ #ifndef _POP_SCENE_H_ #defin

  • 详解iOS游戏开发中Cocos2D的坐标位置关系

    接触Cocos2D有段时间了,今天特意研究了下Cocos2D坐标系中各种位置关系,anchor属性,CCNode坐标和地图坐标转换. 先看一段代码: 复制代码 代码如下: -(id) init  {      // always call "super" init      // Apple recommends to re-assign "self" with the "super" return value      if( (self=[s

  • cocos2dx骨骼动画Armature源码剖析(二)

    上篇文章从总体上介绍了cocos2dx自带的骨骼动画,这篇文章介绍一下导出的配置数据各个字段的含义(也解释了DragonBone导出的xml数据每个字段的含义). skeleton节点 <skeleton name="Dragon" frameRate="24" version="2.2"> name:flash文件名字. frameRate:flash帧率. version:dragonbones版本号. armatures节点 首

  • 剖析iOS开发中Cocos2d-x的内存管理相关操作

    一,IOS与图片内存 在IOS上,图片会被自动缩放到2的N次方大小.比如一张1024*1025的图片,占用的内存与一张1024*2048的图片是一致的.图片占用内存大小的计算的公式是:长*宽*4.这样一张512*512 占用的内存就是 512*512*4 = 1M.其他尺寸以此类推.(ps:IOS上支持的最大尺寸为2048*2048). 二,cocos2d-x 的图片缓存 Cocos2d-x 在构造一个精灵的时候会使用spriteWithFile或者spriteWithSpriteFrameNa

  • Cocos2d-x触摸事件实例

    在玩手机游戏的时候,屏幕接收我们的触摸消息是必不可少的,根据我们的触摸事件,去实现相应的功能,这里我们就来学习一下cocos2d-x中的触摸是怎么实现的.触摸分为单点触摸和多点触摸,先来看单点触摸,就是接收一个点的触摸.代码将实现过程清楚的写了下来,仔细分析代码吧. bool HelloWorld::init() { bool bRet = false; do { CC_BREAK_IF(! CCLayer::init()); //开启触摸 this->setTouchEnabled(true)

  • Cocos2d-x 3.x入门教程(一):基础概念

    前言 接触游戏开发时间不长,之前一直都是写Lua,写Lua肯定是没有什么发展的啦,至少你要会写的.写客户端,肯定要看看Cocos2d-x了.从今天起,正式开始Cocos2d-X的学习之旅. 之前一直都是做C++开发的,转过来看Cocos2d-x,从语言上来说,没有多少问题.对于我来说,Cocos2d-x就是一个类库,就类似于MFC.ATL和QT一样,就是一个游戏类库,而我就按照学习类库使用的方法去学习Cocos2d-x.这篇文章叫基础概念,但是还是从整体来说说Cocos2d-x这个类库的. 基础

  • Cocos2d-x中使用CCScrollView来实现关卡选择实例

    类似关卡选择的这种功能游戏中经常看到,比如帮助场景,选择关卡,通过滑动的方式选择一些其他的东西等等.今天我们实现关卡的选择是使用CCScrollView这个类.当然还有一些其他的方法,比如使用cocostudio的page view也可以.我先说下整体的思路,CCScrollView这个类是继承自CCLayer的,本身的触摸事件有些bug,所以网上一般将这个层的touch事件处理为false,而使用它的父节点来处理触摸事件,我们也是采用这个做法.先定义一个LevelScene类,将CCScrol

随机推荐