[Cocos2D-X]单、多点触屏以及父子节点坐标系之间的关系

本文详细介绍了Cocos2D-X中节点与子节点坐标系的关系,包括简要介绍各种坐标系、父子节点坐标系转换规则。同时讲解了单点触摸的基本步骤和实例,以及多点触摸的实现,包括缩放功能的详细操作。通过阅读,读者可以理解Cocos2D-X中触摸事件处理和节点坐标转换的原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.节点与子节点的坐标系之间的关系


1.1简要介绍各种坐标系:


1. OpenGL坐标系:原点在屏幕左下角,x轴向右,y轴向上。
2. 屏幕坐标系:原点在屏幕左上角,x轴向右,y轴向下。
                       因此在Cocos2D-X中对触摸事件做出响应前,需要首先把触摸点转化到OpenGL坐标系。

3. 节点坐标系:每个节点都有独立的坐标系。当节点移动或者改变方向时,和该节点相关联的坐标系(它的子节点坐标系)将随之移动或者改变方向。都是相对的,相对于基准的。


1.2父子节点坐标系之间的关系:


   CCNode类的设置位置使用的是父节点的节点坐标系。它和OpenGL坐标系的方向也是一致的,x轴向右,y轴向上,原点在父节点坐标系的左下角

    

   如果将父节点的锚点设置为(0.5,0.5),则其子节点的坐标原点在屏幕中央。  (感谢舍予天涯提出错误)。

   现纠正错误如下:

   锚点为指定贴图上和所在节点原点(即在父节点所形成的坐标系中设置位置的点)重合的点的位置,与贴图上点所比较的并非父节点的左下角,应该说是贴图所在节点的左下角(即子节点本身的原点)

    综合来说,锚点是贴图上的某一点,与父节点坐标系并无关系,而仅仅是相对于贴图本身所在节点在父坐标系中的位置(即子节点的原点)。

    只有在使用贴图的情况下,锚点才有意义。

    CCNode类的默认锚点为(0,0),即节点的左下角。而CCSprite类的默认锚点为(0.5,0.5)。

   


2.单点触摸


  2.1基本步骤


   1.首先在初始化函数中加入setTouchEnabled;
   2.然后重写registerWithTouchDispatcher、ccTouchBegan、ccTouchMoved、ccTouchEnded和ccTouchCancelled等函数;
   3.在registereWithTouchDispatcher函数中通过导演类获得分发触摸类,并调用触摸的代理addTargetedDelete函数允许本布景层接收触摸事件。
      addTargetdDelete函数的第一个参数是加入代理的对象,第二个参数是触摸的优先级,最后一个参数代表是否“吞噬”所有的触摸点(如果在本布景层吞噬掉相应的触摸点,那么比它权限低的以及CCStandardTouchDelegate标准触摸代理无论是多高的权限全都收不到触摸发布——简而言之,单点触屏的权限比多点的高)。

  2.2实例:父节点中的某个子节点随手指移动


   1.首先在init函数中初始化一个父节点,叫anode,其下有两个子节点,分别为pSprite和hero。这里我们想让hero子节点随手指移动。
      在init函数中的部分代码如下(详见上传的代码 http://download.youkuaiyun.com/detail/yupingliu/6267063   
   //触屏检测
	setTouchEnabled(true);
	isControl = false;
   ...
   //新建父节点
   anode = CCNode::create();
   anode->setAnchorPoint(ccp(0.5, 0.5));
   anode->setPosition(ccp(winSize.width/2, winSize.height/2));
   this->addChild(anode, 0);
	
        //新建子节点pSprite
        pSprite = CCSprite::create("HelloWorld.png");
	pSprite->setScale(0.5);
        // position the sprite on the center of the screen
	//pSprite和hero作为anode的子节点,所以基于anode的坐标系,以anode的锚点为原点
	pSprite->setPosition(ccp(0, 0));
	//新建子节点hero
	hero = CCSprite::create("r2.png");
	hero->setPosition(ccp(0, 0));

   //节点缩放比例
   nodeScale = 1;

   anode->addChild(pSprite, 0);
   anode->addChild(hero, 0);
   //是否多点触屏
   isMultiPoint = false;

   2.重写registereWithTouchDispatcher函数。   
void HelloWorld::registerWithTouchDispatcher(){
   
	CCDirector* pDirector = CCDirector::sharedDirector();
	//单点触摸
	pDirector->getTouchDispatcher()->addTargetedDelegate(this, 0, false);
	//多点触摸
	pDirector->getTouchDispatcher()->addStandardDelegate(this, 0);
}

   3.ccTouchBegan函数中函数中判断触摸点是否在hero的矩形范围内,若在这个范围内,则将布尔型的全局变量设置为true。   
//单点触摸
bool HelloWorld::ccTouchBegan(CCTouch* touch, CCEvent* event)
{

	CCPoint heropos = hero->getPosition();
	//获得触摸点在屏幕坐标系下的坐标
	CCPoint location = touch->getLocationInView();
	//将其转化为OpenGl坐标
	location = CCDirector::sharedDirector()->convertToGL(location);
	//再对应到anode节点自己的坐标系
	location = anode->convertTouchToNodeSpace(touch);

	//锚点似乎在中心哦
	CCRect heroRect = CCRectMake(heropos.x - (hero->getContentSize().width/2), heropos.y - (hero->getContentSize().height/2), hero->getContentSize().width, hero->getContentSize().height);

	if (nodeScale != 1)
	{
		heroRect.setRect(heropos.x - ((hero->getContentSize().width) * nodeScale / 2), heropos.y - ((hero->getContentSize().height) * nodeScale / 2), (hero->getContentSize().width) * nodeScale, (hero->getContentSize().height) * nodeScale);
	}

	//1.首先在ccTouchBegan函数中判断触摸点是否在主角的图片矩形范围内,若在这个范围内,则将布尔型的全局变量设置为true
	
	if (heroRect.containsPoint(location))
	{
		isControl = true;
		CCLOG("yes");
	}
	

	return true;
}

   4.在ccTouchMoved中,若布尔型的全局变量为true,说明在ccTouchBegan中触点已经控制hero,并根据触摸点的横纵坐标设置hero位置。
void HelloWorld::ccTouchMoved(CCTouch* touch, CCEvent* event)
{
	//在ccTouchMoved中,若布尔型的全局变量为true,说明在ccTouchBegan中触点已经控制主角,并根据触摸点的横纵坐标设置主角位置
	if (isControl)
	{
		CCPoint location = touch->getLocationInView();
		location = CCDirector::sharedDirector()->convertToGL(location);
		location = anode->convertTouchToNodeSpace(touch);
		hero->setPosition(ccp(location.x, location.y));
	}

}
   
   5.在ccTouchEnded和ccTouchCancelled中,将布尔型全局变量设置为false。
//3.在ccTouchEnded和ccTouchCancelled中,将布尔型全局变量设置为false即可
void HelloWorld::ccTouchEnded(CCTouch* touch, CCEvent* event)
{
	isControl = false;

}

void HelloWorld::ccTouchCancelled(CCTouch* touch, CCEvent* event)
{
	isControl = false;
}

   6.详细代码见 http://download.youkuaiyun.com/detail/yupingliu/6267063.

3.多点触摸


3.1基本步骤

 
   多点触摸的实现步骤和单点触摸类似,只是需要从CCSet里获得触点类CCTouch。

3.2实例:缩放功能的实现


  1.在初始化函数中加入setTouchEnabled(true)使得触摸可以被使用。
  2.重写registereWithTouchDispatcher等5个函数。
  3.在ccTouchesBegan中检测,如果触摸点的个数大于两个,那么取前两个点,使用两点间距离公式(横纵坐标差的平方和开根号)计算这两个点的距离。
//多点触摸
void HelloWorld::ccTouchesBegan(CCSet* pTouches, CCEvent* pEvent)
{
	//在ccTouchesBegan中检测,如果触摸点的个数大于两个,那么取前两个点,使用两点间距离公式(横纵坐标差的平方和开根号)计算这两个点的距离
	if (pTouches->count() >= 2)
	{
		CCSetIterator iter = pTouches->begin();
		CCPoint mPoint1 = ((CCTouch*)(*iter))->getLocationInView();
		mPoint1 = CCDirector::sharedDirector()->convertToGL(mPoint1);
		iter ++;
		CCPoint mPoint2 = ((CCTouch*)(*iter))->getLocationInView();
		mPoint2 = CCDirector::sharedDirector()->convertToGL(mPoint2);

		distance = sqrt((mPoint1.x - mPoint2.x) * (mPoint1.x - mPoint2.x) + (mPoint1.y - mPoint2.y) * (mPoint1.y - mPoint2.y));

	}

}

  4.在ccTouchMoved中检测,如果触摸点的个数大于两个,那么继续计算这两个点的距离。
//多点触摸
void HelloWorld::ccTouchesBegan(CCSet* pTouches, CCEvent* pEvent)
{
	//在ccTouchesBegan中检测,如果触摸点的个数大于两个,那么取前两个点,使用两点间距离公式(横纵坐标差的平方和开根号)计算这两个点的距离
	if (pTouches->count() >= 2)
	{
		CCSetIterator iter = pTouches->begin();
		CCPoint mPoint1 = ((CCTouch*)(*iter))->getLocationInView();
		mPoint1 = CCDirector::sharedDirector()->convertToGL(mPoint1);
		iter ++;
		CCPoint mPoint2 = ((CCTouch*)(*iter))->getLocationInView();
		mPoint2 = CCDirector::sharedDirector()->convertToGL(mPoint2);

		distance = sqrt((mPoint1.x - mPoint2.x) * (mPoint1.x - mPoint2.x) + (mPoint1.y - mPoint2.y) * (mPoint1.y - mPoint2.y));

	}

}

  5.然后通过距离比计算得到缩放比例,调用精灵类的setScale设置缩放比例。
void HelloWorld::ccTouchesMoved(CCSet* pTouches, CCEvent* pEvent)
{
	//在ccTouchesMoved中检测,如果触摸点的个数大于两个,那么继续计算这两个点的距离
	if (pTouches->count() >=2)
	{
		CCSetIterator iter = pTouches->begin();
		CCPoint mPoint1 = ((CCTouch*)(*iter))->getLocationInView();
		mPoint1 = CCDirector::sharedDirector()->convertToGL(mPoint1);
		iter ++;
		CCPoint mPoint2 = ((CCTouch*)(*iter))->getLocationInView();
		mPoint2 = CCDirector::sharedDirector()->convertToGL(mPoint2);

		float mDistance = sqrt((mPoint1.x - mPoint2.x) * (mPoint1.x - mPoint2.x) + (mPoint1.y - mPoint2.y) * (mPoint1.y - mPoint2.y));

		CCLOG("distance = %f", distance);
		CCLOG("mDistance = %f", mDistance);
		

		//然后通过距离比计算得到缩放比例
		mScale = mDistance / distance;
		CCLOG("mScale = %f", mScale);
		distance = mDistance;

		isMultiPoint = true;
	}

}


 本文参考了《Cocos2D-X权威指南》一书中的介绍触摸事件的一些内容以及实例,并做了一些修改。

 本文不详尽或错误之处,请各位不吝言辞,多多指教~谢谢~

              作者:Louise http://blog.youkuaiyun.com/yupingliu

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值