您的位置:首页 > 移动开发 > Cocos引擎

cocos2dx 触摸测试一 单点和多点

2013-12-28 20:59 316 查看
打开刚创建的项目TouchesTest,等待xcode完成索引。

点击左上角向右箭头编译运行[快捷键CMD+R],注意运行的scheme是当前项目》模拟器,见下图。(默认的可能是cocos2dx》iOS Device,修改一下)

//
//  MySprite.h
//  TouchesTest
//
//  Created by HanHongmin on 13-12-28.
//
//

#ifndef __TouchesTest__MySprite__
#define __TouchesTest__MySprite__

#include "cocos2d.h"
using namespace cocos2d;

class MySprite:public CCSprite,public CCTouchDelegate{
public:
static MySprite* create(const char *pszFileName);

virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
// optional

virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);

// optional
virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);
virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent);
virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent);
virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent);
};

#endif /* defined(__TouchesTest__MySprite__) */


View Code
CMD+左键点击 CCSprite去看看父类的这个方法都干了什么。

点进去后是CCSprite.h文件,找到static CCSprite* create(const char *pszFileName)这个方法,光标移动到create上,右键Jump to Definition转到定义,CCSprite.cpp。

我们拷贝CCSprite的这个方法的定义,照葫芦画瓢去MySprite定义我们的create方法

MySprite* MySprite::create(const char* pszFileName){
MySprite *pobSprite = new MySprite();
if (pobSprite && pobSprite->initWithFile(pszFileName))
{
pobSprite->autorelease();
return pobSprite;
}
CC_SAFE_DELETE(pobSprite);
return NULL;
}


这回HelloWorldScene.cpp不报错了,运行一下。可以看到图片出来了,但是触摸没反应,控制台也没有log。

因为我们的触摸事件压根就没有注册。

MySprite.h中声明方法:

virtual void onEnter();

virtual void onExit();

这两个方法从何而来呢,我们去查查CCSprite的API。http://www.cocos2d-x.org/reference/native-cpp/V2.2.1/d4/de7/classcocos2d_1_1_c_c_sprite.html

CMD+F输入onEnter找到方法,我们可以看到这个方法是CCSprite从CCNode继承而来的。具体这两个方法干什么用,大家google一下吧。

去MySprite.cpp中定义这两个方法

void MySprite::onEnter(){
CCLog("onEnter");
}

void MySprite::onExit(){
CCLog("onExit");
}


运行一下,我们可以在控制台看到打印了onEnter。

修改这两个方法:

void MySprite::onEnter(){
CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this, 0);//多点触控
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);//单点触控
CCSprite::onEnter();
}
void MySprite::onExit(){
CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
CCSprite::onExit();
}


在此运行,点图片并拖拽,发现控制台多了一些打印信息。

将ccTouchBegan方法return true再试试。另外,分别注释掉多点和单点的事件注册,再各种试。

需要注意的一点是,ccTouchBegan方法返回结果会导致的不同情况。

可以这样,我们在触摸图片内部的时候,使用单点系列事件,触摸图片以外的区域使用多点系列事件。(其实多点是包含单点的,刚才各种试的时候你应该能发现,因为我想,你应该和我一样只用了一个鼠标....那么,单点拖动多点缩放时都可以在图片内部区域实现的,我们下一篇再说吧)

那么怎么判断触点在图片内外呢?

修改ccToucheBegan方法

bool MySprite::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){
CCLog("ccTouchBegan");
CCRect rect = this->boundingBox();
if(rect.containsPoint(pTouch->getLocation())){
CCLog("ccTouchBegan in Img");
return true;
}else{
CCLog("ccTouchBegan out of Img");
return false;
}
}


在此运行,看看图片内外的触摸是否和我们想的一样。

我们现在来实现,图片的拖动。

修改ccToucheMoved方法

void MySprite::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent){
CCLog("ccTouchMoved");
CCPoint start = pTouch->getPreviousLocation();
CCPoint end = pTouch->getLocation();
//计算位移,直接使用point充当position的话,会有偏差,比如点住图片的一角进行拖动,setPosition的时候是依据AnchorPoint进行设置的
CCPoint sub = ccpSub(end, start);
CCPoint newPosition = ccpAdd(this->getPosition(),sub);
this->setPosition(newPosition);
}


我们现在来实现,多点图片的缩放。

思路:我们就实现两指吧,在began的时候记录两指的距离并记录下来,比如名字为beganDistance,move的时候在实时计算距离,比如名字叫moveDistance。

moveDistance/beganDistance就是缩放比啦。

在MySprite.h的文件后面声明一个float变量

protected:
float _beganDistance;


修改cpp的ccTouchesBegan方法

void MySprite::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent){
CCDictionary* touchesDic = CCDictionary::create();
CCSetIterator iter = pTouches->begin();
for (; iter != pTouches->end(); iter++){
CCTouch* pTouch = (CCTouch*)(*iter);
touchesDic->setObject(pTouch, CCString::createWithFormat("%d",pTouch->getID())->getCString());
}

//两个手指
if (touchesDic->count() == 2){
CCLog("****ccTouchesBegan*");
CCArray* keys = touchesDic->allKeys();
CCTouch *touch1 = (CCTouch*)touchesDic->objectForKey(((CCString*)keys->objectAtIndex(0))->getCString());
CCTouch *touch2 = (CCTouch*)touchesDic->objectForKey(((CCString*)keys->objectAtIndex(1))->getCString());

CCPoint pt = touch1->getLocation();
CCPoint pt2 = touch2->getLocation();

_beganDistance = ccpDistance(pt,pt2);
}
}


修改cpp的ccTouchesMoved方法

void MySprite::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent){
CCDictionary* touchesDic = CCDictionary::create();
CCSetIterator iter = pTouches->begin();
for (; iter != pTouches->end(); iter++){
CCTouch* pTouch = (CCTouch*)(*iter);
touchesDic->setObject(pTouch, CCString::createWithFormat("%d",pTouch->getID())->getCString());
}

//两个手指
if (touchesDic->count() == 2){
CCLog("****ccTouchesMoved*");
CCArray* keys = touchesDic->allKeys();
CCTouch *touch1 = (CCTouch*)touchesDic->objectForKey(((CCString*)keys->objectAtIndex(0))->getCString());
CCTouch *touch2 = (CCTouch*)touchesDic->objectForKey(((CCString*)keys->objectAtIndex(1))->getCString());

CCPoint pt = touch1->getLocation();
CCPoint pt2 = touch2->getLocation();

float moveDistance = ccpDistance(pt,pt2);
this->setScale(this->getScale()*(moveDistance/_beganDistance));
}
}


运行试一下,这要用真机了呀~

两指测试发现没啥反应,那应该是两指判断这里出现了问题。

两个方法的刚开始位置加上打印看看

CCLog("ccTouchesMoved touches point count:%i",pTouches->count());


再试,发现参数中只有一个点。想,这不应该啊,一定是哪里有设置没有开启多点。

搜一下,找到原因。

在左侧导航树ios/AppController.mm文件,方法

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions


中开启,加入一行代码

[__glView setMultipleTouchEnabled:YES];


再试。先不管图片缩放效果行不行,先看控制台日志输出,1,2,3,4,5个手指都有日志。

OK,缩放有问题,那就是写的不对呗。来一起看看

改了改,缩放效果凑合实现了,但是不够达标

void MySprite::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent){
CCLog("ccTouchesBegan touches point count:%i",pTouches->count());
CCDictionary* touchesDic = CCDictionary::create();
CCSetIterator iter = pTouches->begin();
for (; iter != pTouches->end(); iter++){
CCTouch* pTouch = (CCTouch*)(*iter);
touchesDic->setObject(pTouch, CCString::createWithFormat("%d",pTouch->getID())->getCString());
}

//两个手指
if (touchesDic->count() == 2){

CCArray* keys = touchesDic->allKeys();
CCTouch *touch1 = (CCTouch*)touchesDic->objectForKey(((CCString*)keys->objectAtIndex(0))->getCString());
CCTouch *touch2 = (CCTouch*)touchesDic->objectForKey(((CCString*)keys->objectAtIndex(1))->getCString());

CCPoint pt = touch1->getLocation();
CCPoint pt2 = touch2->getLocation();
if(pt.x==pt2.x&&pt.y==pt2.y){
CCLog("两点一样");
return;
}

_beganDistance = ccpDistance(pt,pt2);
CCLog("****ccTouchesBegan,distance:%f",_beganDistance);
}
}
void MySprite::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent){
//CCLog("ccTouchesMoved touches point count:%i",pTouches->count());
CCDictionary* touchesDic = CCDictionary::create();
CCSetIterator iter = pTouches->begin();
for (; iter != pTouches->end(); iter++){
CCTouch* pTouch = (CCTouch*)(*iter);
touchesDic->setObject(pTouch, CCString::createWithFormat("%d",pTouch->getID())->getCString());
}

//两个手指
if (touchesDic->count() == 2){
//CCLog("****ccTouchesMoved*");
CCArray* keys = touchesDic->allKeys();
CCTouch *touch1 = (CCTouch*)touchesDic->objectForKey(((CCString*)keys->objectAtIndex(0))->getCString());
CCTouch *touch2 = (CCTouch*)touchesDic->objectForKey(((CCString*)keys->objectAtIndex(1))->getCString());

CCPoint pt = touch1->getLocation();
CCPoint pt2 = touch2->getLocation();

float moveDistance = ccpDistance(pt,pt2);
CCLog("_beganDistance:%f,moveDistance:%f",_beganDistance,moveDistance);
if(_beganDistance!=0){
CCLog("curScale:%f,change:%f",this->getScale(),moveDistance/_beganDistance);
this->setScale(this->getScale()*(moveDistance/_beganDistance));
_beganDistance = moveDistance;
}else{
CCLog("开始距离为0");
}

}
}


最后这点算法和效果都不好,就不在继续修改了,

主要是两个手指不同时触摸,即一前一后先后到屏幕上,这时候touchesBegan执行了2次单点并未算出新的_beganDistance,而执行touchesMove的时候用的还是上一次move最后的_beganDistance,导致突然放大或者缩小。

下一篇换个办法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: