文档章节

cocos2dx 多层触摸机制

霄霄月月
 霄霄月月
发布于 2014/04/18 14:16
字数 1096
阅读 1776
收藏 2
/*
* LsTouch.h
*/

#ifndef LSTOUCH_H_
#define LSTOUCH_H_

#include "cocos2d.h"

USING_NS_CC;

class LsTouchEvent;

/**
* 定义可触摸元素,用于统一管理
*/
class LsTouch : public CCNode {
public:
    LsTouch();
    ~LsTouch();
    CREATE_FUNC(LsTouch);
    virtual bool init();

    // 设置显示项
    void setDisplay(CCSprite* dis);

    void setEventId(int eventId);
    int getEventId();

    /// 常规判断
    bool selfCheck(CCTouch* ccTouch, LsTouchEvent* lsTe);

private:
    // 判断当前的元素是否被点击
    bool containsCCTouchPoint(CCTouch* ccTouch);
    bool isParentAllVisible(LsTouchEvent* lsTe);

    // 用户保存显示精灵的 tag
    static const int TAG_DISPLAY = 100;
    int m_iEventId;

};

class LsTouchEvent {
public:
    LsTouchEvent();
    ~LsTouchEvent();

    void addLsTouch(LsTouch* touch, int eventId);

    void removeLsTouch(LsTouch* touch);

    bool sendTouchMessage(CCTouch* ccTouch);

    // 返回优先级较高的可触摸对象
    LsTouch* getPriorityTouch(LsTouch* a, LsTouch* b);

    virtual void touchEventAction(LsTouch* touch) = 0;
private:
    CCArray* m_pLsTouches;
};

#endif /* LSTOUCH_H_ */
/*
* LsTouch.cpp
*
*/

#include "LsTouch.h"

LsTouch::LsTouch() {
    CCLog("LsTouch()");
    m_iEventId = 0;
}

LsTouch::~LsTouch() {
    CCLog("LsTouch().~()");
}

bool LsTouch::init() {

    if ( !Node::init() )
    {
        return false;
    }
    
    return true;
}

void LsTouch::setDisplay(CCSprite* dis) {
    // 设置之前先清除,没有也无所谓
    removeChildByTag(TAG_DISPLAY, true);
    addChild(dis, 0, TAG_DISPLAY);
}

void LsTouch::setEventId(int eventId) {
    m_iEventId = eventId;
}

int LsTouch::getEventId() {
    return m_iEventId;
}

bool LsTouch::selfCheck(CCTouch* ccTouch, LsTouchEvent* lsTe) {
    bool bRef = false;
    // 可点击项的检测,可扩展
    do {
        // 是否通过点击位置检测
        CC_BREAK_IF(!containsCCTouchPoint(ccTouch));
        // 是否正在运行,排除可能存在已经从界面移除,但是并没有释放的可能
        CC_BREAK_IF(!isRunning());

        // 判断是否隐藏
        CC_BREAK_IF(!isVisible());
        // 这里可能还需要判断内部显示项目是否隐藏
        ///// 暂留
        // 不仅判断当前元素是否隐藏,还需要判断在它之上的元素直到事件处理层,是否存在隐藏
        CC_BREAK_IF(!isParentAllVisible(lsTe));

        bRef = true;
    } while (0);
    return bRef;
}

bool LsTouch::containsCCTouchPoint(CCTouch* ccTouch) {
    // 获得显示内容
    CCNode* dis = getChildByTag(TAG_DISPLAY);
    CCSprite* sprite = dynamic_cast<CCSprite*>(dis);
    CCPoint point = sprite->convertTouchToNodeSpaceAR(ccTouch);
    CCSize s = sprite->getTexture()->getContentSize();
    CCRect rect = CCRectMake(-s.width / 2, -s.height / 2, s.width, s.height);
    return rect.containsPoint(point);
}

bool LsTouch::isParentAllVisible(LsTouchEvent* lsTe) {
    bool bRef = true;
    // 向父类转型,以便获取地址比较对象,LsTouchEvent 的对象必须同时直接或者简介继承 CCNode
    CCNode* nLsTe = dynamic_cast<CCNode*>(lsTe);

    CCNode* parent = getParent();
    do {
        // 如果遍历完毕,说明 LsTouch 不再 LsTouchEvent 之内
        if (!parent) {
            bRef = false;
            break;
        }
        // 如果 LsTouch 在 LsTouchEvent 之内,返回 true
        // 注意:如果想让LsTouchEvent 处理 不在其 CCNode 结构之内的元素,则取消此处判断
        if (nLsTe == parent) {
            break;
        }
        if (!parent->isVisible()) {
            bRef = false;
            break;
        }
        parent = parent->getParent();
    } while (1);
    return bRef;
}

LsTouchEvent::LsTouchEvent() {
    CCLog("LsTouchEvent()");
    m_pLsTouches = CCArray::create();
    m_pLsTouches->retain();
}

LsTouchEvent::~LsTouchEvent() {
    CCLog("LsTouchEvent().~()");
    m_pLsTouches->release();
}

void LsTouchEvent::addLsTouch(LsTouch* touch, int eventId) {
    touch->setEventId(eventId);
    m_pLsTouches->addObject(touch);
}

void LsTouchEvent::removeLsTouch(LsTouch* touch) {
    m_pLsTouches->removeObject(touch, true);
}

bool LsTouchEvent::sendTouchMessage(CCTouch* ccTouch) {
    // 编写判断,集合中的哪个元素级别高,就触发哪一个
    LsTouch* lsTouch = NULL;

    // 获得点击的点
    CCObject* pObj = NULL;
    LsTouch* lt = NULL;
    CCARRAY_FOREACH(m_pLsTouches, pObj) {
        lt = dynamic_cast<LsTouch*>(pObj);
        if (lt) {
            if (lt->selfCheck(ccTouch, this)) {
                if (lsTouch == NULL)
                    lsTouch = lt;
                else
                    // 如果已存在符合条件元素,比较优先级
                    lsTouch = getPriorityTouch(lsTouch, lt);
            }
        }
    }
    // 比对最终只有一个元素触发
    if (lsTouch){
        touchEventAction(lsTouch);
        return true;
    }
    return false;
}

LsTouch* LsTouchEvent::getPriorityTouch(LsTouch* a, LsTouch* b) {
    // 触摸优先级通过 CCNode 树判断,也既是显示层次级别等因素
    // 以当前元素为“根”向父类转型,以便获取地址比较对象,LsTouchEvent 的对象必须同时直接或者简介继承 CCNode
    CCNode* nLsTe = dynamic_cast<CCNode*>(this);

    // 共同的分枝
    CCNode* allParent = NULL;
    // 寻找 a 与 b 共同的分枝
    CCNode* nAParent = a;
    CCNode* nBParent = b;
    CCNode* nAChild = NULL;
    CCNode* nBChild = NULL;
    do {
        nAChild = nAParent;
        nAParent = nAParent->getParent();
        if (!nAParent)
            break;

        nBParent = b;
        do {
            nBChild = nBParent;
            nBParent = nBParent->getParent();
            if (!nBParent)
                break;
            if (nAParent == nBParent) {
                allParent = nAParent;
                break;
            }
            if (nBParent == nLsTe) {
                break;
            }
        } while (1);
        if (allParent)
            break;
        if (nAParent == nLsTe) {
            break;
        }
    } while (1);

    // 此处只需要判断 nAChild 和 nBChild 的优先级即可,默认返回 a
    if (!nAChild || !nBChild)
        return a;
    // 根据 ZOrder 判断,如果 ZOrder一样,根据索引位置判断
    if ( nAChild->getZOrder() == nBChild->getZOrder() )
    {
        return (allParent->getChildren().getIndex(nAChild)) > (allParent->getChildren().getIndex(nBChild)) ? a : b;
    } 
    else
    {
        return nAChild->getZOrder() > nBChild->getZOrder() ? a : b;
    }
    


}

调用例子:

1. 继承

class HelloWorld : public cocos2d::Layer, public LsTouchEvent

2. 重写 touchEventAction:

void HelloWorld::touchEventAction(LsTouch* touch)
{
    //touch->getEventId() 事件ID
    CCLog("touch event action id: %d", touch->getEventId());
}

3.调用

    //创建精灵    
    auto sprint1 = Sprite::create("CloseNormal.png");
    //创建可触控对象
    LsTouch* lt = LsTouch::create();
    //设置可触控对象的位置
    lt->setPosition(origin.x, origin.y);
    //把精灵绑定到可操控对象上,把精灵加入带可操控对象表
    lt->setDisplay(sprint1);
    //把可触控对象加入到场景中
    this->addChild(lt);
    //把可触控对象加入事件处理,当触屏绑定精灵时调用touchEventAction
    //并传达事件ID,根据区分ID 处理对应的事情
    this->addLsTouch(lt, 120);
    //创建布景的 触摸监听
    auto listener1 = EventListenerTouchOneByOne::create();//创建一个触摸监听  
    listener1->setSwallowTouches(true);//设置是否想下传递触摸

    listener1->onTouchBegan = [ = ](Touch* touch, Event* event){
        // 给事件类 发送消息
        sendTouchMessage(touch);
        return true;

     };
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, this);

本文引用:http://blog.leafsoar.com/archives/2013/05-25.html

© 著作权归作者所有

共有 人打赏支持
霄霄月月
粉丝 34
博文 40
码字总数 32350
作品 0
成都
程序员
Cocos2dx游戏开发系列笔记3:牛刀小试->忍者飞镖射幽灵的Demo

就是这个例子,应该很简单,主要用到的有:精灵的移动,触摸,碰撞检测。 赶紧搞定,待会还要陪哲哲来几局爱消除。 首先在Scene初始化方法里添加精灵: CCSprite *player =CCSprite::create...

懒骨头
2013/12/09
0
0
杨超 (wantnon)/EffectNodes-for-Cocos2dx

EffectNodes for Cocos2dx by yang chao (wantnon), 2014-6-26 EffectNodes for Cocos2dx is a collection of 2d special effects implemented with cocos2dx. i will add more when i got g......

杨超 (wantnon)
05/09
0
0
cocos2d-x js模版修改

创建cocos2d-x项目,导入引擎模版,避免每次都拷贝引擎到项目中,修改路径: D:commonscocos2d-xcocos2d-2.1rc0-x-2.1.3templatemsvcCCAppWiz.win32Scripts1033下的js文件如下: // Additio...

石头哥哥
2013/08/04
0
0
【cocos2dx进阶】调试篇(2)Cocos2dx的一些小改造

继续上一篇 【cocos2dx进阶】调试篇(1)基础介绍 的内容,这次主要讲下对于Cocos2dx的一些小改造。 先说Cocosdx关于调试的一些设计。主要包括2块内容,一个是log输出,一个是节点信息的反馈...

kingzeus
06/28
0
0
Cocos2dx游戏开发系列笔记6:怎样让《萝莉快跑》的例子运行在vs和手机上

感谢听D同学赞助的Demo。 那怎样让它运行在vs中呢: 1 使用cocos2d-x-2.2toolsproject-creator文件夹中的create_project.py脚本,生成一个demo。 2 拷贝Classes和Resources文件夹到刚生成的d...

懒骨头
2013/12/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

内存模型是怎么解决缓存一致性的?

在再有人问你Java内存模型是什么,就把这篇文章发给他。这篇文章中,我们介绍过关于Java内容模型的来龙去脉。 我们在文章中提到过,由于CPU和主存的处理速度上存在一定差别,为了匹配这种差距...

Java填坑之路
15分钟前
1
0
vue-cli 3.0 初体验

最近复习了下vue,突然发现vue-cli已经更新到3.0版本了,并且变化蛮大,看来要不停的学习,真是一入前端深似海。 安装步骤: 1、全局安装 npm install -g @vue/cli Vue CLI 的包名称由 vue-...

tianyawhl
17分钟前
0
0
Angular进阶之路

【初级】会写页面,能出东西。 给定环境和 rest API,不用第三方库,能在十分钟内完成一个 master/detail 结构的带路由的应用(可以不管美观)。 知识点:Angular CLI、组件、路由、HTTP 服务...

陆小七的主页
19分钟前
0
0
Redis缓存数据库安全加固指导(一)

背景 在众多开源缓存技术中,Redis无疑是目前功能最为强大,应用最多的缓存技术之一,参考2018年国外数据库技术权威网站DB-Engines关于key-value数据库流行度排名,Redis暂列第一位,但是原生...

中间件小哥
19分钟前
0
0
百万级数据mysql分区

1. 什么是表分区? 表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。 2. 表分区与分表的区别 分表...

罗文浩
22分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部