cocos2dx基础篇(7) 触碰事件
cocos2dx游戏引擎的重点是在于移动设备的跨平台开发,而移动设备上的游戏大部分都是通过屏幕触碰来进行的。比如主菜单的按钮触碰,打飞机中飞机的触碰移动,都需要用到触碰操作。想一想之前讲的菜单按钮CCMenu,菜单项的点击响应事件,其实就是触碰。
cocos2dx引擎中实现触碰的类CCTouchDelegate。而CCLayer类默认继承了CCTouchDelegate接口,所以CCLayer的子类无须再重新使用这些接口,这样就很方便地为我们提供了触摸操作相关的操作。
触碰事件主要分为两类:单点触碰 和 多点触碰。
【本节内容】
一、单点触碰TargetedDelegate、以及参数CCTouch类。
二、多点触碰StandardDelegate、以及参数CCSet类。
三、两类触碰的区别。
【单点触碰】
单点触碰TargetedDelegate,顾名思义,就是只接受一个点的触摸响应事件。
在使用触碰之前,必须要先注册触碰委托。单点触碰的注册委托函数为addTargetedDelegate。
1、开启单点触碰事件addTargetedDelegate
写在onEnter()中。
//
/**
 *     开启单点触碰TargetedDelegate
 *     注册触碰:addTargetedDelegate("触碰事件委托的对象","优先级","是否拦截触屏事件");
 *     优先级的值越小,就越高越早被响应。
 *     当第3个参数为true时,表示对本次触屏事件进行拦截,也就是说当触屏事件响应了本次触屏委托后,将不会再继续响应其他触碰委托。
 */
    void HelloWorld::onEnter()
    {
        //注册触碰响应事件
        CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,0,false);
        CCLayer::onEnter();//一定不要忘了调用父类的onEnter
    }
//
2、关闭单点触碰事件removeDelegate
写在onExit()中。
//
/**
 *     关闭单点触碰TargetedDelegate
 *     注销触碰:removeDelegate("注销触碰事件委托的对象");
 */
    void HelloWorld::onExit()
    {
        //注销触屏响应事件
        CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
        CCLayer::onExit();//一定不要忘了调用父类的onExit
    }
//
3、单点触碰响应函数
ccTouchBegan、ccTouchMoved、ccTouchEnded、ccTouchCancelled。
其中ccTouchBegan的返回值为bool类型:
当返回true时 ,表示继续响应ccTouchMoved、ccTouchEnded事件;
当返回false时,则不再继续响应这两个事件。
//
    virtual bool ccTouchBegan(CCTouch* touch,CCEvent* event);        //手指碰到屏幕时调用
    virtual void ccTouchMoved(CCTouch* touch,CCEvent* event);        //手指在屏幕上滑动时调用
    virtual void ccTouchEnded(CCTouch* touch,CCEvent* event);        //手指离开屏幕是调用
    virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent); //取消触碰
//
4、关于CCTouch类
CCTouch类是用来存储用户触摸屏幕的过程中,其触摸点的相关信息。也就是保存了触碰的整个过程中,手指所在的位置坐标。
需要在.h中添加引用命名空间:using namespace cocos2d; 才可以使用。
常用操作如下:
//
    class CCTouch : public CCObject
    {
        CCPoint getLocation();         //返回当前触点的坐标
        CCPoint getPreviousLocation(); //返回前一个触点的坐标
        CCPoint getStartLocation();    //返回开始触碰时的坐标
        CCPoint getDelta();            //返回最近两个触点的偏移量坐标
    };
//
5、代码实战
接下来将举个例子:使用单点触碰实现精灵的移动。
5.1、声明单点触碰响应函数
先在HelloWorld.h中,声明触碰响应函数,以及类的生命周期。
//
    //触屏事件
    virtual bool ccTouchBegan(CCTouch* touch,CCEvent* event);
    virtual void ccTouchMoved(CCTouch* touch,CCEvent* event);
    virtual void ccTouchEnded(CCTouch* touch,CCEvent* event);
    //生命周期
    virtual void onEnter();
    virtual void onExit();
//
5.2、开启、关闭单点触碰事件
在HelloWorld.cpp中编写开启和关闭触碰事件。
//
    //开启触屏监听
    void HelloWorld::onEnter()
    {
        CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,0,false);
        CCLayer::onEnter(); //一定不要忘了
    }
    //关闭触屏监听
    void HelloWorld::onExit()
    {
        CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
        CCLayer::onExit();  //一定不要忘了
    }
//
5.3、创建测试精灵
在HelloWorld::init()中创建一个CCSprite精灵,用于测试触碰。
//
    //添加一个CCSprite精灵
    CCSprite* sp = CCSprite::create("Icon.png");
    sp->setPosition( midPos );
    this->addChild(sp, 0, 1); //tag标记为1
//
5.4、实现触碰响应函数
ccTouchBegan:将精灵的位置设置到触碰开始的位置。关键函数:touch->getLocation()
ccTouchMoved:对精灵的位置进行移动。 关键函数:touch->getDelta()
ccTouchEnded:将精灵的位置还原到触碰开始的位置。关键函数:touch->getStartLocation()
//
    //触屏开始ccTouchBegan
    bool HelloWorld::ccTouchBegan(CCTouch* touch,CCEvent * event)
    {
        CCLOG("ccTouchBegan");
        //获取CCSprite精灵
        CCSprite* sp = (CCSprite*)this->getChildByTag(1);
        //设置精灵的坐标为: 当前触点位置
        CCPoint pTouch = touch->getLocation();
        sp->setPosition( pTouch );
        return true;
    }
    //触屏移动ccTouchMoved
    void HelloWorld::ccTouchMoved(CCTouch* touch,CCEvent* event)
    {
        CCLOG("ccTouchMoved");
        //获取可视区域尺寸大小
        CCSize mysize = CCDirector::sharedDirector()->getVisibleSize();
        //获取CCSprite精灵
        CCSprite* sp = (CCSprite*)this->getChildByTag(1);
        //实现精灵的触屏移动
        CCPoint pos = touch->getDelta();        //获得触屏滑动的偏移量
        CCPoint currentPos = sp->getPosition(); //获得精灵的当前坐标
        currentPos = ccpAdd(currentPos, pos);   //精灵+偏移量 后的坐标
        sp->setPosition(currentPos);            //设置触屏移动后的坐标
    }
    //触屏结束ccTouchEnded
    void HelloWorld::ccTouchEnded(CCTouch* touch,CCEvent* event)
    {
        CCLOG("ccTouchEnded");
        //获取CCSprite精灵
        CCSprite* sp = (CCSprite*)this->getChildByTag(1);
        //设置精灵的坐标为: 触屏开始时的触点位置
        CCPoint touchStartPos = touch->getStartLocation();
        sp->setPosition( touchStartPos );
    }
//
6、运行结果

【多点触碰】
多点触碰StandardDelegate,可以支持多个点的同时触摸响应事件。
1、开启多点触碰
多点触碰的委托注册放在onEnter的生命函数中会造成程序异常退出。
所以注册多点触碰都需要重写如下函数:registerWithTouchDispatcher。
开启多点触碰,除了注册触碰委托外,还需要调用setTouchEnabled(true)来启用触碰。
//
/**
 *     注册多点触碰,重写registerWithTouchDispatcher。
 *     addStandardDelegate("触碰事件委托的对象","优先级")
 */
    void HelloWorld::registerWithTouchDispatcher()
    {
        CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this,0);
    }
    //在HelloWorld::init()中启用多点触碰
    this->setTouchEnabled(true);
//
2、关闭多点触碰
与单点触碰的关闭类似,写在onExit()。
//
    void HelloWorld::onExit()
    {
        //关闭触碰
        CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
        CCLayer::onExit(); //一定不要忘了
    }
//
3、多点触碰响应函数
ccTouchesBegan、ccTouchesMoved、ccTouchesEnded、ccTouchesCancelled。
其中ccTouchesBegan和单点触碰不同,返回值为void。
//
    virtual void ccTouchesBegan(CCSet* touches, CCEvent* event);       //触碰开始
    virtual void ccTouchesMoved(CCSet* touches, CCEvent* event);       //触碰移动
    virtual void ccTouchesEnded(CCSet* touches, CCEvent* event);       //触碰结束
    virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent); //取消多点触屏
//
4、关于CCSet类
CCSet类是一个集合类,和C++中的Set是类似的。
在这里CCSet的数据元素类型为CCTouch,其主要存储的是多点触碰的触摸点CCTouch集合。
使用迭代器CCSetIterator进行CCSet集合中多个触点CCTouch的遍历。
//
    for (CCSetIterator iter = touches->begin() ;iter != touches->end(); iter++)
    {
        //获取触点后,就和单点一样的处理了
        CCTouch* touch = (CCTouch*)(*iter);
        //......
    }
//
5、代码实战
在电脑中无法看到多点触碰的效果,因为……电脑操作只有一个鼠标。
下面就讲解一个多点触碰的例子吧,至于效果,自己将代码移植到手机上看吧。。。
5.1、声明多点触碰响应函数
先在HelloWorld.h中,声明多点触碰响应函数,以及类的生命周期。
//
    //触屏事件
    virtual void registerWithTouchDispatcher(void);
    virtual void ccTouchesBegan(CCSet* touches,CCEvent* event);
    virtual void ccTouchesMoved(CCSet* touches,CCEvent* event);
    virtual void ccTouchesEnded(CCSet* touches,CCEvent* event);
    //生命周期
    virtual void onExit();
//
5.2、开启、关闭多点触碰事件
在HelloWorld.cpp中编写开启和关闭多点触碰事件。
//
    //在init中开启多点触碰
    bool HelloWorld::init()
    {
        //.....
        //开启多点触屏。注意这句话必须要写,否则无法多点触屏
        this->setTouchEnabled(true);
        //.....
    }
    //注册多点触屏
    void HelloWorld::registerWithTouchDispatcher()
    {
        CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this,0);
    }
    //注销多点触屏
    void HelloWorld::onExit()
    {
        CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
        CCLayer::onExit();  //不要忘了写!
    }
//
5.3、创建测试精灵
在HelloWorld::init()中创建两个CCSprite精灵,用于测试触碰。
//
    //添加两个CCSprite精灵,用于多点触屏
    CCSprite* sp1 = CCSprite::create("Icon.png");
    sp1->setPosition( ccp( 100, 160 ) );
    this->addChild(sp1, 0, 1);
    CCSprite* sp2 = CCSprite::create("Icon_gray.png");
    sp2->setPosition( ccp( 200, 160) );
    this->addChild(sp2, 0, 2);
//
5.4、实现多点触碰响应函数
ccTouchesMoved中:将精灵的位置设置到触点位置,sp1精灵设置到第0个触点位置;sp2精灵设置到第1个触点位置。
关键函数:
(1)CCTouch* touch = (CCTouch*)(*iter)
(2)touch->getID()
//
    //触屏开始,返回值是void
    void HelloWorld::ccTouchesBegan(CCSet* touches,CCEvent* event)
    {
        CCLOG("ccTouchesBegan");
    }
    //触屏移动
    void HelloWorld::ccTouchesMoved(CCSet* touches,CCEvent* event)
    {
        CCLOG("ccTouchesMoved");
        //创建CCSet的迭代器CCSetIterator
        CCSetIterator iter = touches->begin();
        //遍历多点触点集合touches
        for( ;iter != touches->end(); iter++)
        {
            //获取触点后,就和单点一样的处理了
            CCTouch* touch = (CCTouch*)(*iter);
            if( touch->getID() == 0)      //控制精灵sp1
            {
                CCSprite* sp1 = (CCSprite*)this->getChildByTag(1);
                sp1->setPosition( touch->getLocation() );
            }
            else if( touch->getID() == 1) //控制精灵sp2
            {
                CCSprite* sp2 = (CCSprite*)this->getChildByTag(2);
                sp2->setPosition( touch->getLocation() );
            }
        }
    }
    //触屏结束
    void HelloWorld::ccTouchesEnded(CCSet* touches,CCEvent* event)
    {
        CCLOG("ccTouchesEnded");
    }
//
6、运行结果

想要看到多点触碰的效果,就把程序移植到手机上吧。
【两类触碰的区别】
(1)单点使用的监听类是CCtargetedTouchDelegate,而多点使用CCtangardTouchDelegate。
(2)多点触控还需要多一个步骤,就是单独写个函数来注册多点触控:registerWithTouchDispatcher。
(3)多点触控要有开启才能用。 this->setTouchEnabled(true)。
(4)多点触控中的ccTouchesBegan不是布尔型。
cocos2dx基础篇(7) 触碰事件的更多相关文章
- cocos2dx基础篇(3) 常用重要类
		
---------------------------------------- 入口类main.cpp 主要控制类AppDelegate.cpp -------------------------- ...
 - cocos2dx基础篇(14) 滚动视图CCScrollView
		
[3.x] (1)去掉 "CC" (2)滚动方向 > CCScrollViewDirection 改为强枚举 ScrollView::Dire ...
 - cocos2dx基础篇(12) 编辑框之一CCTextFieldTTF
		
前面我们讲了精灵贴图.标签.菜单.按钮.感觉似乎少了点什么?UI控件里是不是应该还有一个很重要的控件--编辑框.在手机网游中,启动游戏,过了开场动画后,基本上显示的第一个界面应该就是游戏的登录界面了吧 ...
 - cocos2dx基础篇(5) 按钮
		
这篇是直接复制的别人的,太多了,难得写... [本节内容] CCMenu.CCMenuItem其具体的六个子类 [菜单CCMenu] 菜单CCMenu是用来装载菜单按钮的图层,图层中的子节点只能够是菜 ...
 - Android触碰事件
		
OnTouchListener使用 public class ViewActivity extends Activity implements View.OnTouchListener { @Over ...
 - cocos2dx基础篇(13) 编辑框之二CCEditBox
		
[3.x] (1)去掉"CC" (2)设置虚拟键盘的编辑类型 > EditBoxInputMode 变为强枚举 EditBox::EditBoxInputMode // SI ...
 - 【Cocos2d入门教程二】Cocos2d-x基础篇
		
上一章已经学习了环境的搭建.这一章对基础概念进行掌握.内容大概有: 1.导演 2.场景 3.节点 4.层 4.精灵 1.导演(Director) 导演存在的主要作用: a.环境设定(帧率 初始化ope ...
 - cocos2dx基础篇(15) 列表视图CCTableView
		
[3.x] (1)去掉 "CC" (2)TableViewCell 中: > unsigned int getIdx() 返回类型改为 ssize_t(类型为 long) ( ...
 - js 基础篇(点击事件轮播图的实现)
		
轮播图在以后的应用中还是比较常见的,不需要多少行代码就能实现.但是在只掌握了js基础知识的情况下,怎么来用较少的而且逻辑又简单的方法来实现呢?下面来分析下几种不同的做法: 1.利用位移的方法来实现 首 ...
 
随机推荐
- static成员变量
			
可以创建一个由同一个类的所有对象共享的成员变量.要创建这样的成员,只需将关键字 static 放在变量声明的前面,如下面的类所示: class StatDemo { private: static i ...
 - qt5--QLabel标签控件
			
需要 #include <QLabel> label->setFrameShape(QFrame::Box); //设置边框 边框样式参看:https://www.cnblo ...
 - node 的fs.state 获取文件信息
			
1. fs.stat()可以获取文件的信息,用法如下: const fs = require('fs'); fs.stat('./book.js',(err,stats)=>{ if(err) ...
 - linux 免密码 使用sudo 直接使用root权限执行命令
			
1.切换到root用户下,怎么切换就不用说了吧,不会的自己百度去. 2.添加sudo文件的写权限,命令是: chmod u+w /etc/sudoers 3.编辑sudoers文件 vi /etc/s ...
 - poj2386(dfs搜索水题)
			
Language:Default Lake Counting Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 42069 ...
 - 【杂题】[CodeForces 1172D] Nauuo and Portals【构造】
			
Description 有一个n*n的网格,你需要在上面设置一些传送门,传送门由两个配对的格子组成,从一个进入会立刻从另一个同一方向出来. 现在有n个人从第1列出发向右走,位于(i,1)的人要走到(r ...
 - Selenium 对元素的判断(expected_conditions)(转载)
			
我们在用webdriver去操作元素时,先要判断这个元素是否存在,存在才去操作,否则就会报错. selenium的expected_conditions模块提供了一些判断方法 场景 Expected ...
 - Springboot(九).多文件上传下载文件(并将url存入数据库表中)
			
一. 文件上传 这里我们使用request.getSession().getServletContext().getRealPath("/static")的方式来设置文件的存储 ...
 - 四图3d旋转轮播
			
<!DOCTYPE html><html><head><meta charset="utf-8" /><title>3d ...
 - windows基础提权
			
Window基础提权 提到system权限 甚至让他变成你的肉鸡 我们了解一下windows下面有那些用户 Guests是用户最低的权限 而且一般是被禁用的 User权限也很低 连关机都不行 还有wi ...