zoukankan      html  css  js  c++  java
  • cocos2dx 触摸测试一 单点和多点

    打开刚创建的项目TouchesTest,等待xcode完成索引。

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

    我比较习惯让模拟器竖屏,修改之:点击左侧项目根节点,屏幕中间视图顶部Tab标签选General,往下找Deployment info,Device Orientation只勾选Protrait,Upside Down。

    重新运行看一下。

    开始修改代码测试,关于创建的模板项目HelloWorld的各部分说明就不说了,一搜一大堆。

    首先把我要用到的常用文件VisibleRect.h,VisibleRect.cpp添加到项目中。

    这两个文件在cocos2d-x-2.2.1/samples/Cpp/TestCpp/Classes下,具体这两个文件干嘛用的,看看他的源码就知道了

    如何添加到当前工程中?选择xcode左侧导航树的Classes,右键Add Files to xxx,在弹出的文件选择框中选中要添加的文件,勾选Destination,如下图

     点击Add完成添加文件。

    新建一个测试类,MySprite。

    如何新建?选中xcode左侧导航树Classes,右键New File,在弹出的文件模板选择框中左侧选择iOS C and C++,右侧icon选中C++ Class,点击Next。

    在接下来的输入框中,在Save as中输入文件名MySprite.cpp,如下图,点击Create完成新建文件。

    修改MySprite.h代码如下:

     1 //
     2 //  MySprite.h
     3 //  TouchesTest
     4 //
     5 //  Created by HanHongmin on 13-12-28.
     6 //
     7 //
     8 
     9 #ifndef __TouchesTest__MySprite__
    10 #define __TouchesTest__MySprite__
    11 
    12 #include "cocos2d.h"
    13 using namespace cocos2d;
    14 
    15 class MySprite:public CCSprite,public CCTouchDelegate{
    16 public:
    17     virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
    18     // optional
    19     
    20     virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
    21     virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
    22     virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);
    23     
    24     // optional
    25     virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);
    26     virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent);
    27     virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent);
    28     virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent);
    29 };
    30 
    31 #endif /* defined(__TouchesTest__MySprite__) */

    修改MySprite.cpp如下:

     1 //
     2 //  MySprite.cpp
     3 //  TouchesTest
     4 //
     5 //  Created by HanHongmin on 13-12-28.
     6 //
     7 //
     8 
     9 #include "MySprite.h"
    10 
    11 bool MySprite::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){
    12     CCLog("ccTouchBegan");
    13     return false;
    14 }
    15 // optional
    16 
    17 void MySprite::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent){
    18     CCLog("ccTouchMoved");
    19 }
    20 void MySprite::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent){
    21     CCLog("ccTouchEnded");
    22 }
    23 void MySprite::ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent){
    24     CCLog("ccTouchCancelled");
    25 }
    26 
    27 // optional
    28 void MySprite::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent){
    29     CCLog("****ccTouchesBegan*");
    30 }
    31 void MySprite::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent){
    32     CCLog("****ccTouchesMoved*");
    33 }
    34 void MySprite::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent){
    35     CCLog("****ccTouchesEnded*");
    36 }
    37 void MySprite::ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent){
    38     CCLog("****ccTouchesCancelled*");
    39 }

    在HelloWorldScene.h中include两个头文件,VisibleRect.h和MyScript.h

    修改HelloWorldScene.cpp的init方法准备进行测试

    bool HelloWorld::init()
    {
        //////////////////////////////
        // 1. super init first
        if ( !CCLayer::init() )
        {
            return false;
        }
        MySprite* pSprite = MySprite::create("HelloWorld.png");
        pSprite->setPosition(VisibleRect::center());
        this->addChild(pSprite, 0);
        
        return true;
    }

    我们发现,如此修改后,MySprite::create("HelloWorld.png")处报错。这是因为MySprite类没有相应的create静态方法。

    回到MyScript类我们来补充一下。

    在.h文件中声明这个方法:static MySprite* create(const char* pszFileName);

    这时的MySprite.h文件如下:

     1 //
     2 //  MySprite.h
     3 //  TouchesTest
     4 //
     5 //  Created by HanHongmin on 13-12-28.
     6 //
     7 //
     8 
     9 #ifndef __TouchesTest__MySprite__
    10 #define __TouchesTest__MySprite__
    11 
    12 #include "cocos2d.h"
    13 using namespace cocos2d;
    14 
    15 class MySprite:public CCSprite,public CCTouchDelegate{
    16 public:
    17     static MySprite* create(const char *pszFileName);
    18     
    19     virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
    20     // optional
    21     
    22     virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
    23     virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
    24     virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);
    25     
    26     // optional
    27     virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);
    28     virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent);
    29     virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent);
    30     virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent);
    31 };
    32 
    33 #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,导致突然放大或者缩小。

    下一篇换个办法。

     

     

    我是cocos2dx初学者,Java5年,一点C++,OC经验都没有,各位见笑了 文章中如有错误或者不全面或者有更好的解决办法,请指出,不胜感激
  • 相关阅读:
    数据库更改自增和主键
    修改MySQL的默认数据存储引擎
    tomcat密码的坑
    通过System.getProperties()获取系统参数
    Java语言开发的,直接解压即可使用软件
    一个javascript面试题
    为什么学习差
    IDEA设置
    java关键字
    IDEA快捷键
  • 原文地址:https://www.cnblogs.com/hanhongmin/p/3495331.html
Copyright © 2011-2022 走看看