如何移动一个cocos2d x 精灵变形-x精灵

您所在的位置: &
如何移动一个cocos2d-x精灵
如何移动一个cocos2d-x精灵
Walzer Wang
在前一章中我们介绍了如何添加一个cocos2d-x精灵中,为游戏场景添加了一个精灵。但一个英雄或许太过孤单,我们应该加入一些敌人,让他来打败。本文我们将讲述如何移动一个cocos2d-x精灵。
void addTarget()函数将会帮我们完成这一工作,敌人将会以随机的速度,从游戏场景左移动到右。
在HelloWorldScence.h里声明void
addTarget(),并在HelloWorldScene.cpp里添加以下的代码,(请不要忘记在HelloWorldScene.cpp的开头加入using
namespace cocos2d)
1// cpp with cocos2d-x
2void HelloWorld::addTarget()
4 CCSprite *target = CCSprite::spriteWithFile(&Target.png&,
5 CCRectMake(0,0,27,40) );
7 // Determine where to spawn the target along the Y axis
8 CCSize winSize = CCDirector::sharedDirector()-&getWinSize();
9 int minY = target-&getContentSize().height/2;
10 int maxY = winSize.height
11 - target-&getContentSize().height/2;
12 int rangeY = maxY - minY;
13 // srand( TimGetTicks() );
14 int actualY = ( rand() % rangeY ) + minY;
16 // Create the target slightly off-screen along the right edge,
17 // and along a random position along the Y axis as calculated
18 target-&setPosition(
19 ccp(winSize.width + (target-&getContentSize().width/2),
20 actualY) );
21 this-&addChild(target);
23 // Determine speed of the target
24 int minDuration = (int)2.0;
25 int maxDuration = (int)4.0;
26 int rangeDuration = maxDuration - minD
27 // srand( TimGetTicks() );
28 int actualDuration = ( rand() % rangeDuration )
31 // Create the actions
32 CCFiniteTimeAction* actionMove =
33 CCMoveTo::actionWithDuration( (ccTime)actualDuration,
34 ccp(0 - target-&getContentSize().width/2, actualY) );
35 CCFiniteTimeAction* actionMoveDone =
36 CCCallFuncN::actionWithTarget( this,
37 callfuncN_selector(HelloWorld::spriteMoveFinished));
38 target-&runAction( CCSequence::actions(actionMove,
39 actionMoveDone, NULL) );
1// objc with cocos2d-iphone
2-(void)addTarget
4 CCSprite *target = [CCSprite spriteWithFile:@&Target.png&
5 rect:CGRectMake(0, 0, 27, 40)];
7 // Determine where to spawn the target along the Y axis
8 CGSize winSize = [[CCDirector sharedDirector] winSize];
9 int minY = target.contentSize.height/2;
10 int maxY = winSize.height - target.contentSize.height/2;
11 int rangeY = maxY - minY;
13 int actualY = (arc4random() % rangeY) + minY;
15 // Create the target slightly off-screen along the right edge,
16 // and along a random position along the Y axis as calculated
17 target.position =
18 ccp(winSize.width + (target.contentSize.width/2),
19 actualY);
20 [self addChild:target];
22 // Determine speed of the target
23 int minDuration = 2.0;
24 int maxDuration = 4.0;
25 int rangeDuration = maxDuration - minD
27 int actualDuration = (arc4random() % rangeDuration)
30 // Create the actions
31 id actionMove =
32 [CCMoveTo actionWithDuration:actualDuration
33 position:ccp(-target.contentSize.width/2, actualY)];
34 id actionMoveDone =
35 [CCCallFuncN actionWithTarget:self
36 selector:@selector(spriteMoveFinished:)];
37 [target runAction:[CCSequence actions:actionMove,
38 actionMoveDone, nil]];
这里用callfuncN_selector(HelloWorld::spriteMoveFinished)回调了spriteMoveFinished方法,我们需要在HelloWorldScene.h里声明并如下来定义它,
1// cpp with cocos2d-x
2void HelloWorld::spriteMoveFinished(CCNode* sender)
4 CCSprite *sprite = (CCSprite *)
5 this-&removeChild(sprite, true);
1// objc with cocos2d-iphone
2-(void)spriteMoveFinished:(id)sender
4 CCSprite *sprite = (CCSprite *)
5 [self removeChild:sprite cleanup:YES];
关于随机函数。srand和rand是C标准库函数。对于每一个平台来说,你可以先获取毫秒级时间来得到一个随机数。在沃Phone上,这个函数是TimGetTickes(),而在iPhone上,你可以直接通过arc4random()函数来获得随机数。
2. Objc中的YES和NO,在cpp中变为true和false。
回调函数,在objc中用selector:@selector(spriteMoveFinished),但在cpp中实现就比较复杂了,你可以参考cocos2dx\include\selector_protocol.h里的声明。一共有5种回调函数类型
 schedule_selector
 callfunc_selector
 callfuncN_selector
 callfuncND_selector
 menu_selector
如何使用它们,根据所用函数的定义来决定。比如使用CCTimer::initWithTarget函数,它的第二个参数是SEL_SCHEDULE类型,到selector_protocol.h里查一下,可以看到对应的是schedule_selector(_SELECTOR)宏,所以调用时就需要在类里头实现一个void
MyClass::MyCallbackFuncName(ccTime)函数,然后把schedule_selector(MyClass::MyCallbackFuncName)作为CCTimer::initWithTarget的第二个参数传入。
之后,我们应该定时地为游戏加入敌人,把以下代码加入到init()函数的返回值前。
1// cpp with cocos2d-x
2// Call game logic about every second
3this-&schedule( schedule_selector(HelloWorld::gameLogic), 1.0 );
1// objc with cocos2d-iphone
2// Call game logic about every second
3[self schedule:@selector(gameLogic:) interval:1.0];
然后在HelloWorldScence.cpp里实现gameLogic()。请注意gameLogic()应该声明为pubilc,否则是无法回调的。
1// cpp with cocos2d-x
2void HelloWorld::gameLogic(ccTime dt)
4 this-&addTarget();
1// objc with cocos2d-iphone
2-(void)gameLogic:(ccTime)dt
4 [self addTarget];
好了,所有事情都做完了,编译并运行,好好享用你的成果。
498)this.width=498;' onmousewheel = 'javascript:return big(this)' src="http://www.cocos2d-x.org/attachments/download/220" alt="" />
498)this.width=498;' onmousewheel = 'javascript:return big(this)' src="http://www.cocos2d-x.org/attachments/download/217" alt="" />
498)this.width=498;' onmousewheel = 'javascript:return big(this)' src="http://www.cocos2d-x.org/attachments/download/219" alt="" />
498)this.width=498;' onmousewheel = 'javascript:return big(this)' src="http://www.cocos2d-x.org/attachments/download/214" alt="" />
【编辑推荐】
【责任编辑: TEL:(010)】
关于的更多文章
Cocos2d是一个开源框架,用于构建2D游戏、演示程序和其他图形界
随着云计算、物联网、大数据、移动互联网的大发展,你应该知道这些。
关于App营销,了解哪类App最能引起用户关注,以及不同
在iOS开发过程中,尤其是对于新手来说,都会遇到或多
Web App开发中会面临越来越“重”的问题,如果在开始
本书是按照全国计算机技术与软件专业技术资格(水平)考试《网络管理员考试大纲》的要求,参照《网络管理员教程》及近年来考试试
Windows Phone专家
Android开发专家
51CTO旗下网站匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。在Cocos2d-x3.0里面如何使用拖拽精灵分享
程序截图:
  许多读者想要一个关于如何在Cocos2d-x里面使用touch事件来拖拽精灵(sprite)的教程。既然你们这么要求,我就满足你们啦!
  在这个教程中,你将学到下列内容:
使用touch事件拖拽精灵的基本方法
如何通过touch事件来滚动视图本身 =1- 如何方便地计算坐标
  为了使事件变得有趣,你将要移动一些非常可爱的动画图片,它是由原文作者创作的,背景则是由 创建。
  这个教程假设你已经有一些基本的cocos2d-x的知识,同时已经安装了一份cocos2d-x的版本。如果你对cocos2d-x还不熟悉,你可能需要先去学习一下基础教程。
  好了,不多说,准备好键盘,开始吧!
Getting Started
  在实现touch事件之前,首先你需要创建一个基本的Cocos2d-x场景来显示背景和这些动物精灵。
  创建名为“DragDrop”的工程。
  接下来,继续,下载你需要的。原教程采用480x320(iPhone3GS)的分辨率调试,但本文采用960x640(iPhone4),所以我把原教程“blue-shooting-stars.png”分辨率从802x320转换成了了。我改好了放在上面链接的包里,下载完后,解压,然后把这些图片拖到Resources分组下面。确保“ Copy items into destination group’s folder (if needed)”被选中,然后点击Add。
  在你把图片导入到工程之后,在Xcode中展开Classes分组,然后选择HelloWorld.h。给HelloWorld类增加三个成员变量:
cocos2d::Sprite *
cocos2d::Sprite * selS
cocos2d::Vector&cocos2d::Sprite *& movableS
  你将使用这些变量来追踪你的背景图片、当前选中的精灵以及一个在处理touch事件时需要移动的精灵的数组。
  现在,回到HelloWorldScene.cpp,找到init方法,把它替换成下面的代码:
bool HelloWorld::init()
if ( !Layer::init() )
Size winSize = Director::getInstance()-&getWinSize();
Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::RGB565);
background = Sprite::create("blue-shooting-stars.png");
background-&setAnchorPoint(Point(0, 0));
this-&addChild(background);
Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::DEFAULT);
std::string images[] = {"bird.png", "cat.png", "dog.png", "turtle.png"};
int images_length = 4;
for(int i =0; i & images_ ++i)
std::string image = images[i];
Sprite *sprite = Sprite::create(image);
float offsetFraction = ((float)(i+1))/(images_length+1);
sprite-&setPosition(winSize.width*offsetFraction, winSize.height/2);
this-&addChild(sprite);
movableSprites.pushBack(sprite);
selSprite = NULL;
  这里有一些新的知识点需要引入,让我们一步步来学习吧!
  这个方法的第一部分加载了一张本场景的背景图片(blue-shooting-stars.png)。注意,这里把图片的锚点(anchor point)设置成图片的左下角(0,0)点。
  在Cocos2d-x里面,当你设置一个精灵的位置的时候,实际上,你设置的是这个精灵的锚点的位置。默认情况下,图片的锚点就是图片的中点。因此,通过把精灵锚点设置成左下角,当你设置精灵位置的时候,实际上你就是指定了精灵的中心位置在左下角。
  这个方法并没有设置背景的位置,因此背景的位置默认情况下是(0,0)。因此,图片的实际位置就是在(0,0)。(因此设置精灵位置是相对于锚点来的,锚点在左下角,因此图片的左下角就位于屏幕的左下角)。因此,这个图片有1600个像素宽,那么超过的部分就在屏幕之外了。
  另外需要注意的一点就是,在加载图片之前,转换了一下像素格式。在默认情况下,cocos2d里面加载图片,它们是作为32位的图片加载进来的。这意味着每个像素占4个字节的内存空间。当你需要非常高质量的显示效果时,非常好!但是,有时候需要折中一下,因为以前的设备内存很有限,如果全部使用32的像素格式来加载图片的话,会造成内存消耗过多。
  当你加载大的图片的时候(比如背景图片),最佳实践是使用16位的像素格式来加载--也就是牺牲一点质量来减少内存开销。cocos2d里面有很多不同的像素格式--这个教程中,我们选择16位的像素格式,RGB565,因为背景一般不需要透明效果。(少了Alpha通道,RGBA就是有Alpha通道)
  init方法的另外一部分,就是循环遍历一个图片数组,然后创建精灵并且计算精灵放置的坐标。这些精灵会一字排开,显示在屏幕上。同时把这些精灵的引用保存在movableSprites数组里面,这个数组后面会使用到。
  就这么多!编译并运行,你将看到一排非常可爱的小动物,在等待你touch呢!
基于touch事件选取精灵
  现在,我们将编写一些代码基于用户的touch事件来决定哪一个精灵被选到了。
  本教程我们选择Cocos2d-x 3.0新增并且推荐的事件监听,让它能够接收touch事件。在init方法的最后添加下列代码:
auto listener = EventListenerTouchOneByOne::create();
listener-&setSwallowTouches(true);
listener-&onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
listener-&onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
listener-&onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
_eventDispatcher-&addEventListenerWithSceneGraphPriority(listener, this);
  注意,这是一种新的方式来处理touch事件。首先我们创建事件监听器,绑定onTouchBegan,onTouchMoved,onTouchEnded函数,后面再据情况而定实现它。
  接下来,在HelloWorldScene.cpp的底部添加一些新的方法:
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
Point touchLocation = this-&convertTouchToNodeSpace(touch);
this-&selectSpriteForTouch(touchLocation);
void HelloWorld::onTouchMoved(Touch* touch, Event* event)
void HelloWorld::onTouchEnded(Touch* touch, Event* event)
void HelloWorld::selectSpriteForTouch(Point touchLocation)
Sprite * newSprite = NULL;
for (Sprite *sprite : movableSprites)
if ( sprite-&getBoundingBox().containsPoint(touchLocation) )
newSprite =
if (newSprite != selSprite && NULL != newSprite)
if (NULL != selSprite)
selSprite-&stopAllActions();
selSprite-&runAction(RotateTo::create(0.1, 0));
RotateBy * rotLeft = RotateBy::create(0.1, -14.0);
RotateBy * rotCenter = RotateBy::create(0.1, 0.0);
RotateBy * rotRight = RotateBy::create(0.1, 14.0);
Sequence * rotSeq = Sequence::create(rotLeft, rotCenter, rotRight, rotCenter, NULL);
newSprite-&runAction(RepeatForever::create(rotSeq));
selSprite = newS
  第一个方法(selectSpriteForTouch)是一个帮助方法,这个方法遍历movableSprites数组中的所有精灵,查找第一个精灵位置与touch点位置相交的精灵。
  注意,Node可通过函数getBoundingBox返回精灵的边界矩形。这比你自己手动计算精灵的边界矩形要好多了。因为,第一,它更简单;第二,它考虑了精灵的位置坐标变换。(比如锚点变了,要执行相应的矩阵变换,具体可以参考源代码,这些就不再细说了。)
  如果找到一个匹配的精灵,那么就让这个精灵执行一些动画,这样用户就知道哪个精灵被选中了。如果动画还没执行完,又选中另一个精灵了,那么就中断前一个精灵的动画。这里的动画效果,使用了一系列的Action来实现的。
  最后,onTouchBegan方法基于用户的touch事件调用上面的方法。注意,这里把touch坐标点转换成了结点坐标系。为了实现这个目的,通过调用Node的一个辅助函数,convertTouchToNodeSpace。这个方法做了以下两件事:
得到touch视图(也就是屏幕)的touch点位置为OpenGL坐标点(使用getLocation方法)
转换OpenGL坐标系为指定结点的坐标系(使用convertToNodeSpace方法)
  这是一个非常常用的转换过程,所以提供这个方法可以节约很多时间。
  编译并运行代码,并且用手触摸这些动物。当你点中一个精灵的时候,它就会以一种非常可爱的方式旋转,表明它被你选中啦!
基于touch事件移动精灵和背景层
  是时候让小动物移动了!基本的思想就是实现onTouchMoved回调函数,然后计算本次touch点到上一次touch点之间的距离。如果一个动物被选中,将按照计算出来的touch偏移量来移动它。如果动物没有被选中,那就移动整个层,因此用户可以从左至右滚动层。
  在编写代码之前,让我们花点时间来讨论一下,如何在Cocos2d-x里面滚动一个层。
  首先,看到下面两张图片:
  如你所见,你设置背景锚点在左下角(0,0),前景其它部分就在屏幕之外。黑色框框表示当前可见的区域,也就是屏幕范围。
  因此,如果你将图片往右边滚动100个像素,你可以把整个Cocos2d-x的层往左移动100个像素,如第二张图所示。
  同时,你要确保不会移得太多。比如,你不能够把层往右移动,因为那样左边就是空白的了。
  现在,你了解了一些背景信息,让我们看看代码怎么写吧!在文件的最后添加下列新的方法:
void HelloWorld::onTouchMoved(Touch* touch, Event* event)
Point touchLocation = this-&convertTouchToNodeSpace(touch);
Point oldTouchLocation = touch-&getPreviousLocation();
oldTouchLocation = this-&convertToNodeSpace(oldTouchLocation);
Point translation = touchLocation - oldTouchL
this-&panForTranslation(translation);
Point HelloWorld::boundLayerPos(Point newPos)
Size winSize = Director::getInstance()-&getWinSize();
Point retval = newP
/* if(retval.x & 0)
retval.x = 0;
if(retval.x & -background-&getContentSize().width+winSize.width)
retval.x = -background-&getContentSize().width+winSize.
retval.x = MIN(retval.x, 0);
retval.x = MAX(retval.x, -background-&getContentSize().width+winSize.width);
retval.y = this-&getPosition().y;
void HelloWorld::panForTranslation(Point translation)
if (selSprite)
Point newPos = selSprite-&getPosition() +
selSprite-&setPosition(newPos);
Point newPos = this-&getPosition() +
this-&setPosition( this-&boundLayerPos(newPos) );
  方法(boundLayerPos),用来确保你在滚动层的时候不会超出背景图片的边界。你传递一个目标点坐标,然后相应地修改x值,保证不会超出边界。如果你不是很理解的话,可以拿出纸和笔,结合上面给出的图片,自己动手画一画。那两句MAX和MIN代码等价于注释的代码。
  方法(panForTranslation)基于传入的目标点位置移动精灵(如果有精灵被选中就移动之,否则移动整个层)。具体的做法就是设置精灵或者层的位置。
  方法(onTouchMoved)是一个回调函数,它在你拖动屏幕上的手指时调用。像之前一样,把touch坐标转换成局部node坐标。因为没有一个辅助方法可以把前一个层的touch坐标转换成node坐标,因此,我们需要手工地调用那2个方法来执行这个操作。
  然后,计算touch偏移量,通过把当前的点坐标减去上一个点坐标,然后调用panForTranslation方法。
  编译并运行,现在,你可以通过拖拽来移动精灵和层啦!
  这里有本教程的。
  到目前为止,你应该知道如何在Cocos2d-x里面使用touch事件来移动精灵了
  如果大家看教程有什么不明白的地方,都可以拿出来,大家一起讨论,共同提高!
闽ICP备号-6cocos2d-x 让精灵按照自己设定的运动轨迹行动 - Bill Yuan - 博客园
正确性、健壮性、可靠性、效率、易用性、可读性、可复用性、兼容性、可移植性...
posts - 837, comments - 26, trackbacks - 0, articles - 0
& & & & 在cocos2d中,系统提供了CCMove、CCJump、CCBezier(贝塞尔曲线)等让精灵移动的action,但是有时候,为了让程序看上不不是那么的呆板,或者为了实现某些特定的功能,我们需要让精灵按照我们自己设定的路径(曲线运动)来移动。这就是这位篇文章我们需要讨论的话题。
& & & &&自己开始也很纠结cocos2dx没有提供更多的action动作,比如说我们要做个抛物线什么的,虽然可以用贝塞尔曲线来模拟。
用贝塞尔曲线扔个飞镖什么的倒是还不错,但当你需要重复执行action时,问题就出来了,再第二次重复贝塞尔曲线动作到时候,精灵就会飞到别的地方去了。(出现这个问题的原因,猜测贝塞尔曲线是没有起点和终点了,在第一次执行了动作之后,之前的曲线动作并没有被释放,第二次再延续这个动作,就会延为执行的那段曲线移动,当然,只是猜测,未深入研究。后来觉得不是这个原因,但具体原因未明。)
& & & &&如果我们要做一个椭圆的轨迹,有人说用3~4条贝塞尔曲线来模拟,但实验证明,在两天贝塞尔曲线的衔接点Action会有停顿,所以效果简直可以用鲁迅先生的&目不忍视&来形容。
& & & &&于是,我们考虑自己定义曲线的路径,让精灵按照我们自己的定义来行动。
& & & &&将自己设定的路径封装成一个action,让精灵执行,这里以椭圆轨迹为例。
先来两张效果图:
& & & &&单独建一个自己的动作模块:LRActionInterval。{LRActionInterval.h&LRActionInterval.cpp}
& & & &&基于cocos2d-x的CCActionInterval来封装自己的动作,所以:
LRActionInterval.h
#include "CCActionInterval.h"//包含系统延时类动作头文件
using namespace cocos2d;
&想一想确定一个椭圆的条件,初中老师告诉我们,去顶一个椭圆我们需要知道他的空间位置(中心点坐标)、长半轴(a)、和短半轴(b)(或者知道半焦距(c))。也就是我们需要三个量来确定一个椭圆,所以在LRActionInterval.h中定义一个包含三个成员的结构来作为我们生成椭圆的参数:
// 定义一个结构来包含确定椭圆的参数
typedef struct _lrTuoyuanConfig {
//中心点坐标
CCPoint centerP
//椭圆a长,三角斜边
//椭圆c长,三角底边
} lrTuoyuanC
&然后定义我们的椭圆的类:
__declspec(dllexport) LRTuoyuanBy : public CCActionInterval
//用&动作持续时间&和&椭圆控制参数&初始化动作
bool initWithDuration(ccTime t, const lrTuoyuanConfig& c);
virtual void update(ccTime time);//利用update函数来不断的设定坐标
//用&动作持续时间&和&椭圆控制参数&创建动作
static LRTuoyuanBy *actionWithDuration(ccTime t, const lrTuoyuanConfig& c);
protected:
lrTuoyuanConfig m_sC
CCPoint m_startP
CCPoint s_startP
接下来是我们的实现部分:
LRActionInterval.cpp
& & & &&其实设定路径就是不断的刷新,将路径上的点赋给执行action的对象。
因此,既然我们要做一个椭圆的轨迹,我们就需要得到椭圆上每个点的坐标值,然后将其赋给执行action的对象。获得椭圆的轨迹,再次回想初中老师的教导&&椭圆标准方程:x^2/a+y^2/b=1。
& & & &&但这是个2次方程,李勇这个方程求x、y的值的时候会需要开方,而开方后还需要确定正负,虽然可以实现功能,但是给自己增加了不少代码量,也会浪费不少笔芯。所以我们要找一个更简单的公式&&椭圆参数方程。
& & & &&参数方程:x=acos(&)y=bsin(&);利用这个一次方程可以直观的计算出当前坐标点。
& & & &&由椭圆的参数方程我们可以分别写出返回X/Y坐标值的函数:
static inline float tuoyuanXat( float a, float bx, float c, ccTime t )//返回X坐标
//参数方程
return -a*cos(2*3.1415926*t)+a;
static inline float tuoyuanYat( float a, float by, float c, ccTime t )//返回Y坐标
float b = sqrt(powf(a, 2) - powf(c, 2));//因为之前定义的参数是焦距c而不是短半轴b,所以需要计算出b
//参数方程
return b*sin(2*3.1415926*t);
然后实现根据中心左边、a、c确定椭圆:
//TuoyuanBy
LRTuoyuanBy* LRTuoyuanBy::actionWithDuration(ccTime t, const lrTuoyuanConfig& c)//利用之前定义的椭圆的三个参数初始化椭圆
LRTuoyuanBy *pTuoyuanBy = new LRTuoyuanBy();
pTuoyuanBy-&initWithDuration(t, c);
pTuoyuanBy-&autorelease();
return pTuoyuanBy;
bool LRTuoyuanBy::initWithDuration(ccTime t, const lrTuoyuanConfig& c)
if (CCActionInterval::initWithDuration(t))
m_sConfig =
return true;
return false;
void LRTuoyuanBy::update(ccTime time)
if (m_pTarget)
CCPoint s_startPosition =m_sConfig.centerP//中心点坐标
float a = m_sConfig.aL
float bx = m_sConfig.centerPosition.x;
float by = m_sConfig.centerPosition.y;
float c = m_sConfig.cL
float x = tuoyuanXat(a, bx, c, time);//调用之前的坐标计算函数来计算出坐标值
float y = tuoyuanYat(a, by, c, time);
m_pTarget-&setPosition(ccpAdd(s_startPosition, ccp(x-a, y)));//由于我们画计算出的椭圆你做值是以原点为中心的,所以需要加上我们设定的中心点坐标
&这样我们只需要在程序中像使用CCBezier一样使用LRTuoyuan,让精灵执行这个Action,他就会沿着我们设定的椭圆运动了。当然,只要你给出你自己的运动函数轨迹,精灵就会按照你自己设定的轨迹运动。1730人阅读
cocos2d-x 3.0(46)
程序截图:
  许多读者想要一个关于如何在cocos2d-x里面使用touch事件来拖拽精灵(sprite)的教程。既然你们这么要求,我就满足你们啦!
  在这个教程中,你将学到下列内容:
使用touch事件拖拽精灵的基本方法
如何通过touch事件来滚动视图本身
如何方便地计算坐标
  为了使事件变得有趣,你将要移动一些非常可爱的动画图片,它是原文作者的创作的,背景则是由创建。
  这个教程假设你已经有一些基本的cocos2d-x的知识,同时已经安装了一份cocos2d-x的版本。如果你对cocos2d-x还不熟悉,你可能需要先学习一下编者改编的
  好了,不多说,准备好键盘,开始吧!
  在实现touch事件之前,首先你需要创建一个基本的cocos2d-x场景来显示背景和这些动物精灵。
  创建名为“DragDrop”的工程。
  接下来,继续,下载你需要的。原教程采用480x320(iPhone3GS)的分辨率调试,但本文采用960x640(iPhone4),所以我把原教程“blue-shooting-stars.png”分辨率从802x320转换成了了。我改好了放在上面链接的包里,下载完后,解压,然后把这些图片拖到Resources分组下面。确保“
Copy items into destination group’s folder (if needed)”被选中,然后点击Add。
  在你把图片导入到工程之后,在Xcode中展开Classes分组,然后选择HelloWorld.h。给HelloWorld类增加三个成员变量:
cocos2d::Sprite * background;
cocos2d::Sprite * selSprite;
cocos2d::Vector&cocos2d::Sprite *& movableSprites;
  你将使用这些变量才追踪你的背景图片、当前选中的精灵以及一个在处理touch事件时需要移动的精灵的数组。
  现在,回到HelloWorldScene.cpp,找到init方法,把它替换成下面的代码:
bool HelloWorld::init()
if ( !Layer::init() )
return false;
Size winSize = Director::getInstance()-&getWinSize();
Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::RGB565);
background = Sprite::create(&blue-shooting-stars.png&);
background-&setAnchorPoint(Point(0, 0));
this-&addChild(background);
Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::DEFAULT);
std::string images[] = {&bird.png&, &cat.png&, &dog.png&, &turtle.png&};
int images_length = 4;
for(int i =0; i & images_length; ++i)
std::string image = images[i];
Sprite *sprite = Sprite::create(image);
float offsetFraction = ((float)(i+1))/(images_length+1);
sprite-&setPosition(winSize.width*offsetFraction, winSize.height/2);
this-&addChild(sprite);
movableSprites.pushBack(sprite);
selSprite = NULL;
return true;
  这里有一些新的知识点需要引入,让我们一步步来学习吧!
  这个方法的第一部分加载了一张本场景的背景图片(blue-shooting-stars.png)。注意,这里把图片的锚点(anchor point)设置成图片的左下角(0,0)点。
  在cocos2d-x里面,当你设置一个精灵的位置的时候,实际上,你设置的是这个精灵的锚点的位置。默认情况下,图片的锚点就是图片的中点。因此,通过把精灵锚点设置成左下角,当你设置精灵位置的时候,实际上你就是指定了精灵的中心位置在左下角。
  这个方法并没有设置背景的位置,因此背景的位置默认情况下是(0,0)。因此,图片的实际位置就是在(0,0)。(因此设置精灵位置是相对于锚点来的,锚点在左下角,因此图片的左下角就位于屏幕的左下角)。因此,这个图片有1600个像素宽,那么超过的部分就在屏幕之外了。
  另外需要注意的一点就是,在加载图片之前,转换了一下像素格式。在默认情况下,cocos2d里面加载图片,它们是作为32位的图片加载进来的。这意味着每个像素占4个字节的内存空间。当你需要非常高质量的显示效果时,非常好!但是,有时候需要折中一下,因为以前的设备内存很有限,如果全部使用32的像素格式来加载图片的话,会造成内存消耗过多。
  当你加载大的图片的时候(比如背景图片),最佳实践是使用16位的像素格式来加载--也就是牺牲一点质量来减少内存开销。cocos2d里面有很多不同的像素格式--这个教程中,我们选择16位的像素格式,RGB565,因为背景一般不需要透明效果。(少了Alpha通道,RGBA就是有Alpha通道)
  init方法的另外一部分,就是循环遍历一个图片数组,然后创建精灵并且计算精灵放置的坐标。这些精灵会一字排开,显示在屏幕上。同时把这些精灵的引用保存在movableSprites数组里面,这个数组后面会使用到。
  就这么多!编译并运行,你将看到一排非常可爱的小动物,在等待你touch呢!
基于touch事件选取精灵
  现在,我们将编写一些代码基于用户的touch事件来决定哪一个精灵被选到了。
  本教程我们选择cocos2d-x 3.0新增并且推荐的事件监听,让它能够接收touch事件。在init方法的最后添加下列代码:
auto listener = EventListenerTouchOneByOne::create();
listener-&setSwallowTouches(true);
listener-&onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
listener-&onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
listener-&onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
_eventDispatcher-&addEventListenerWithSceneGraphPriority(listener, this);
  注意,这是一种新的方式来处理touch事件。首先我们创建事件监听器,绑定onTouchBegan,onTouchMoved,onTouchEnded函数,后面再据情况而定实现它。
  接下来,在HelloWorldScene.cpp的底部添加一些新的方法:
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
Point touchLocation = this-&convertTouchToNodeSpace(touch);
this-&selectSpriteForTouch(touchLocation);
return true;
void HelloWorld::onTouchMoved(Touch* touch, Event* event)
void HelloWorld::onTouchEnded(Touch* touch, Event* event)
void HelloWorld::selectSpriteForTouch(Point touchLocation)
Sprite * newSprite = NULL;
for (Sprite *sprite : movableSprites)
if ( sprite-&getBoundingBox().containsPoint(touchLocation) )
newSprite = sprite;
if (newSprite != selSprite && NULL != newSprite)
if (NULL != selSprite)
selSprite-&stopAllActions();
selSprite-&runAction(RotateTo::create(0.1, 0));
RotateBy * rotLeft = RotateBy::create(0.1, -14.0);
RotateBy * rotCenter = RotateBy::create(0.1, 0.0);
RotateBy * rotRight = RotateBy::create(0.1, 14.0);
Sequence * rotSeq = Sequence::create(rotLeft, rotCenter, rotRight, rotCenter, NULL);
newSprite-&runAction(RepeatForever::create(rotSeq));
selSprite = newSprite;
  第一个方法(selectSpriteForTouch)是一个帮助方法,这个方法遍历movableSprites数组中的所有精灵,查找第一个精灵位置与touch点位置相交的精灵。
  注意,Node可通过函数getBoundingBox返回精灵的边界矩形。这比你自己手动计算精灵的边界矩形要好多了。因为,第一,它更简单;第二,它考虑了精灵的位置坐标变换。(比如锚点变了,要执行相应的矩阵变换,具体可以参考源代码,这些就不再细说了。)
  如果找到一个匹配的精灵,那么就让这个精灵执行一些动画,这样用户就知道哪个精灵被选中了。如果动画还没执行完,又选中另一个精灵了,那么就中断前一个精灵的动画。这里的动画效果,使用了一系列的Action来实现的。
  最后,onTouchBegan方法基于用户的touch事件调用上面的方法。注意,这里把touch坐标点转换成了结点坐标系。为了实现这个目的,通过调用Node的一个辅助函数,convertTouchToNodeSpace。这个方法做了以下两件事:
得到touch视图(也就是屏幕)的touch点位置为OpenGL坐标点(使用getLocation方法) 
转换OpenGL坐标系为指定结点的坐标系(使用convertToNodeSpace方法)
  这是一个非常常用的转换过程,所以提供这个方法可以节约很多时间。
  编译并运行代码,并且用手触摸这些动物。当你点中一个精灵的时候,它就会以一种非常可爱的方式旋转,表明它被你选中啦!
基于touch事件移动精灵和背景层
  是时候让小动物移动了!基本的思想就是实现onTouchMoved回调函数,然后计算本次touch点到上一次touch点之间的距离。如果一个动物被选中,将按照计算出来的touch偏移量来移动它。如果动物没有被选中,那就移动整个层,因此用户可以从左至右滚动层。
  在编写代码之前,让我们花点时间来讨论一下,如何在cocos2d-x里面滚动一个层。
  首先,看到下面两张图片:
  如你所见,你设置背景锚点在左下角(0,0),前景其它部分就在屏幕之外。黑色框框表示当前可见的区域,也就是屏幕范围。
  因此,如果你将图片往右边滚动100个像素,你可以把整个cocos2d-x的层往左移动100个像素,如第二张图所示。
  同时,你要确保不会移得太多。比如,你不能够把层往右移动,因为那样左边就是空白的了。
  现在,你了解了一些背景信息,让我们看看代码怎么写吧!在文件的最后添加下列新的方法:
void HelloWorld::onTouchMoved(Touch* touch, Event* event)
Point touchLocation = this-&convertTouchToNodeSpace(touch);
Point oldTouchLocation = touch-&getPreviousLocation();
oldTouchLocation = this-&convertToNodeSpace(oldTouchLocation);
Point translation = touchLocation - oldTouchLocation;
this-&panForTranslation(translation);
Point HelloWorld::boundLayerPos(Point newPos)
Size winSize = Director::getInstance()-&getWinSize();
Point retval = newPos;
/* if(retval.x & 0)
retval.x = 0;
if(retval.x & -background-&getContentSize().width+winSize.width)
retval.x = -background-&getContentSize().width+winSize.
retval.x = MIN(retval.x, 0);
retval.x = MAX(retval.x, -background-&getContentSize().width+winSize.width);
retval.y = this-&getPosition().y;
return retval;
void HelloWorld::panForTranslation(Point translation)
if (selSprite)
Point newPos = selSprite-&getPosition() + translation;
selSprite-&setPosition(newPos);
Point newPos = this-&getPosition() + translation;
this-&setPosition( this-&boundLayerPos(newPos) );
  方法(boundLayerPos),用来确保你在滚动层的时候不会超出背景图片的边界。你传递一个目标点坐标,然后相应地修改x值,保证不会超出边界。如果你不是很理解的话,可以拿出纸和笔,结合上面给出的图片,自己动手画一画。那两句MAX和MIN代码等价于注释的代码。
  方法(panForTranslation)基于传入的目标点位置移动精灵(如果有精灵被选中就移动之,否则移动整个层)。具体的做法就是设置精灵或者层的位置。
  方法(onTouchMoved)是一个回调函数,它在你拖动屏幕上的手指时调用。像之前一样,把touch坐标转换成局部node坐标。因为没有一个辅助方法可以把前一个层的touch坐标转换成node坐标,因此,我们需要手工地调用那2个方法来执行这个操作。
  然后,计算touch偏移量,通过把当前的点坐标减去上一个点坐标,然后调用panForTranslation方法。
  编译并运行,现在,你可以通过拖拽来移动精灵和层啦!
  这里有本教程的。
  到目前为止,你应该知道如何在cocos2d-x里面使用touch事件来移动精灵了
  如果大家看教程有什么不明白的地方,都可以拿出来,大家一起讨论,共同提高!
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:140275次
积分:1894
积分:1894
排名:千里之外
原创:42篇
转载:43篇
评论:26条
(2)(1)(1)(2)(49)(4)(6)(2)(1)(17)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'}

我要回帖

更多关于 cocos2d x 精灵弯曲 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信