Cocos2d-x人物动作类实例

栏目: 编程语言 · IOS · 发布时间: 7年前

内容简介:Cocos2d-x人物动作类实例

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

Cocos2d-x人物动作类实例

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

Cocos2d-x人物动作类实例

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)
	{

	}
}

Cocos2d-x人物动作类实例 Cocos2d-x人物动作类实例 Cocos2d-x人物动作类实例 Cocos2d-x人物动作类实例

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()获得它的反动作。

Cocos2d-x人物动作类实例

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);
	}
}

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

Cocos2d-x人物动作类实例 Cocos2d-x人物动作类实例

下面是实现的源代码。

Cocos2d-x人物动作类实例 Cocos2d-x人物动作类实例

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

每个函数的具体用法请大家自行试验。

接下来说一下同步动作序列和顺序动作序列。同步动作序列,就是几个动作同时执行,顺序动作序列,就是传入的几个动作按照顺序顺序执行。以下是他们的继承关系图。

Cocos2d-x人物动作类实例 Cocos2d-x人物动作类实例

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

Cocos2d-x人物动作类实例 Cocos2d-x人物动作类实例

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可以实现快进和慢放的效果,就是改变了执行的速度。以下是源代码。

Cocos2d-x人物动作类实例

Cocos2d-x人物动作类实例

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家族类的使用方法,它们也是一个动作类,一般用在顺序动作序列中执行的最后一个动作,目的是调用一个函数,来完成一些功能。以下是这些类的继承关系。

Cocos2d-x人物动作类实例

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

Cocos2d-x人物动作类实例 Cocos2d-x人物动作类实例 Cocos2d-x人物动作类实例 Cocos2d-x人物动作类实例

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);
}

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Effective Java

Effective Java

Joshua Bloch / Addison-Wesley Professional / 2018-1-6 / USD 54.99

The Definitive Guide to Java Platform Best Practices—Updated for Java 9 Java has changed dramatically since the previous edition of Effective Java was published shortly after the release of Jav......一起来看看 《Effective Java》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换