我们工作室需要用cocos2dx来写项目,不过之前的分工有些不是很明确,每个人都使用cocos2dx中的点击事件封装了好几个按钮。所以造成了,游戏的基础框架中出现了N种风格的按钮,于是问题就来了:由于我们使用的cocos2dx中的触摸事件是单点,也就是说非手势的触摸事件。不过cocos2dx在ios和安卓平台上对于单点的响应有些不一致。ios的单点触摸事件的响应机制是,如果屏幕上两个地方同时响应触摸事件,如果一个地方先响应触摸事件,另一个地方的触摸事件就不会再向下分发下去,这样就避免了两个事件都会响应。而安卓中的触摸点击事件分发就显得比较蛋疼了,是一个接一个的分发,最终造成的结果就是如果你用手同时点击两个按钮(尽管同时这种事情在cpu处理看来基本是不可能的),会把这两次触摸事件依次分发下去,这样,如果两次点击事件触发加载两个不同的场景的情况下,就显得比较混乱,所以我们需要做到在两个按钮同时点击的时候肯定要屏蔽到后点击到的按钮的点击事件。

经过一些思索,决定统一写一个基类来搞定这个问题。

#include <stdio.h>
#include "cocos2d.h"
#include "WWCompatibleClasses.h"

class WWButton:public cocos2d::Node
{
public:
    
    WWButton();
    ~WWButton();
    
virtual bool init();
    virtual bool init(wawa::WWNode* pTouchNode);
    virtual void onEnter();
    virtual void onExit();

    virtual bool onTouchBegan(cocos2d::Touch *touch,cocos2d::Event *unused_event);
    virtual void onTouchMoved(cocos2d::Touch *touch,cocos2d::Event *unused_event);
    virtual void onTouchEnded(cocos2d::Touch *touch,cocos2d::Event *unused_event);
    virtual void onTouchCancelled(cocos2d::Touch *touch,cocos2d::Event *unused_event);
    
    virtual void touchActive(cocos2d::Touch* touch){};

void setEnabled(bool en);
    
    void setTouchSwallow(bool enable);
    

protected:
CC_SYNTHESIZE(wawa::WWNode*,m_pTouchNode,TouchNode);
    
    CC_SYNTHESIZE(bool,m_hadCancel,HadCancel);

private:

     bool containTouch(cocos2d::Touch* touch);

    
private:
bool m_bEnable;
    
    cocos2d::Vec2 m_beginPoint;
    
    bool m_swallow;
    //cocos2d::Vec2 m_movePoint;
   
};

#endif /* defined(__helloworld__WWButton__) */
此类继承了node,所以肯定可以使用最基本的cocos2d的一些UI功能,cpp文件中实现了触摸事件的分发,而这个分发中,我们用一个变量来控制所有触摸事件的接收。也就是当一个按钮被点击的时候,设置一个状态,这个状态属于全局的一个变量,把此状态置为false,然后其他按钮在执行到touch事件的时候会先经过这个状态判断,当状态为false的时候,就touchbegan就会返回false,这个touch事件就无法执行到 onTouchEnded方法,所以这个按钮就不会响应具体的点击事件,因为具体的点击事件都写在 onTouchEnded方法里边.具体实现代码如下:

#include "WWButton.h"
#include "ButtonManager.h"
#include "../WWMacros.h"

USING_NS_CC;
USING_NS_WW;

namespace ButtonArgument
{
    const static float g_moveMax = 10;
}

WWButton::WWButton():
	m_pTouchNode(nullptr),m_bEnable(true),m_swallow(true),m_hadCancel(false)
{
    
}

WWButton::~WWButton()
{
    
}

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

bool WWButton::init(WWNode *pTouchNode)
{
    if (!Node::init())
    {
        return false;
    }
    
	this->setCascadeColorEnabled(true);
	this->setTouchNode(pTouchNode);
    return true;
}

void WWButton::onEnter()
{
    Node::onEnter();
	auto listener = EventListenerTouchOneByOne::create();
	listener->setSwallowtouches(m_swallow);

	listener->onTouchBegan = CC_CALLBACK_2(WWButton::onTouchBegan,this);
	listener->onTouchMoved = CC_CALLBACK_2(WWButton::onTouchMoved,this);
	listener->onTouchEnded = CC_CALLBACK_2(WWButton::onTouchEnded,this);
	listener->onTouchCancelled = CC_CALLBACK_2(WWButton::onTouchCancelled,this);
	Director::getInstance()->getEventdispatcher()->addEventListenerWithSceneGraPHPriority(listener,this);
}

void WWButton::onExit()
{
    Node::onExit();
    
}

bool WWButton::onTouchBegan(cocos2d::Touch *touch,cocos2d::Event *unused_event)
{
	if (!m_bEnable)
	{
		return false;
	}

	if (!ButtonManager::getInstance()->getIsClickEnable())
	{
		return false;
	}

	if (!containTouch(touch))
	{
		return false;
	}

	ButtonManager::getInstance()->setIsClickEnable(false);
	this->setColor(Color3B::GRAY);
    
    m_beginPoint = touch->getLocation();
    return true;
}

void WWButton::onTouchMoved(cocos2d::Touch *touch,cocos2d::Event *unused_event)
{
    if (!m_swallow)
    {
        auto movePoint = touch->getLocation();
        
        if (abs(movePoint.x-m_beginPoint.x)>ButtonArgument::g_moveMax||abs(movePoint.y-m_beginPoint.y)>ButtonArgument::g_moveMax)
        {
            onTouchCancelled(touch,unused_event);
        }
    }
}


void WWButton::onTouchCancelled(cocos2d::Touch *touch,cocos2d::Event *unused_event)
{
	this->setColor(Color3B::WHITE);
	ButtonManager::getInstance()->setIsClickEnable(true);
    m_hadCancel = true;
}

void WWButton::onTouchEnded(cocos2d::Touch *touch,cocos2d::Event *unused_event)
{
    this->setColor(Color3B::WHITE);
    ButtonManager::getInstance()->setIsClickEnable(true);
    cclOG("WWButton::onTouchEnded -------------");
    if (!m_hadCancel)
    {
        touchActive(touch);
    }
    m_hadCancel = false;
}

bool WWButton::containTouch(Touch* touch)
{
	if (m_pTouchNode == nullptr)
	{
		cclOG("ErrorInfo::WWButton::containTouch touchNode is nullptr");
		return false;
	}
	
	WWPoint touchLocation = touch->getLocation();
	WWPoint local = m_pTouchNode->convertToNodeSpace(touchLocation);
	WWRect r = m_pTouchNode->getBoundingBox();
	r.origin = Vec2::ZERO;
	return r.containsPoint(local);
}

void WWButton::setEnabled(bool en)
{
	m_bEnable = en;
	if (m_bEnable)
	{
		this->setColor(Color3B::WHITE);
	}
	else
	{
		this->setColor(Color3B::GRAY);
	}
}

void WWButton::setTouchSwallow(bool enable)
{
    m_swallow = enable;
    Director::getInstance()->getEventdispatcher()->removeEventListenersForTarget(this);
    
    auto listener = EventListenerTouchOneByOne::create();
    listener->setSwallowtouches(enable);
    
    listener->onTouchBegan = CC_CALLBACK_2(WWButton::onTouchBegan,this);
    listener->onTouchMoved = CC_CALLBACK_2(WWButton::onTouchMoved,this);
    listener->onTouchEnded = CC_CALLBACK_2(WWButton::onTouchEnded,this);
    listener->onTouchCancelled = CC_CALLBACK_2(WWButton::onTouchCancelled,this);
    Director::getInstance()->getEventdispatcher()->addEventListenerWithSceneGraPHPriority(listener,this);
}

其中ButtonManager是个单例类,存储了这个按钮的状态,也许有人会有疑问,简单的写一个static 变量不就可以了嘛,干嘛还要用单例仅仅为了存储一个变量,额,这就是一个历史问题了,当初我的单例里边是这样的

#ifndef __helloworld__ButtonManager__
#define __helloworld__ButtonManager__

#include <stdio.h>
#include "cocos2d.h"
#include "WWButton.h"

const static std::string g_btnCreateNotafication = "buttonCreate";
const static std::string g_buttonClickNotafication = "buttonClick";
const static std::string g_buttonReset = "buttonReset";
const static std::string g_buttonRemove = "button_Remove";
const static std::string g_sceneChange = "scene_change";

class ButtonManager;
static ButtonManager* m_instance = nullptr;
class ButtonManager
{
public:
    ButtonManager();
    ~ButtonManager();
    
    static ButtonManager* getInstance()
    {
        if (!m_instance)
        {
            m_instance = new ButtonManager();
        }
        return m_instance;
    }
    
    static void release()
    {
        if (m_instance)
        {
            delete m_instance;
            m_instance = nullptr;
        }
    }
    
    void beginListen();
    
private:

	CC_SYNTHESIZE(bool,m_bIsClickEnable,IsClickEnable);
    
private:
    
    
    std::vector<WWButton*>  m_allButtons;
    
    
};
#endif /* defined(__helloworld__ButtonManager__) */


#include "ButtonManager.h"
USING_NS_CC;
#include "WWTouchSprite.h"
#include "WWTwoPicBtn.h"

ButtonManager::ButtonManager():
	m_bIsClickEnable(true)
{
    
}

ButtonManager::~ButtonManager()
{
    
}

void ButtonManager::beginListen()
{
 //   /*******监听按钮的创建********************************************/
 //   Director::getInstance()->getEventdispatcher()->addCustomEventListener(g_btnCreateNotafication,[&](EventCustom* event)
	//{
	//	auto btn = (WWButton*)event->getUserData();
	//	if (btn)
	//	{
	//		btn->setBtnIndex((int)m_allButtons.size());
	//		m_allButtons.push_back(btn);
	//		cclOG("the m_allButton size=%ld",m_allButtons.size());
	//		cclOG("the beginListen() btn idx=%ld",btn->getBtnIndex());
	//	}
	//});

 //   
 //   
 //   
 //   /*******监听按钮点击事件(touchbegan)********************************************/
 //   Director::getInstance()->getEventdispatcher()->addCustomEventListener(g_buttonClickNotafication,[&](EventCustom* event)
	//{
	//	auto btn = (WWButton*)event->getUserData();
	//	cclOG("the btn indx =%ld",btn->getBtnIndex());
	//	if (btn)
	//	{
	//		for (auto obj:m_allButtons)
	//		{
	//			cclOG("the every obj inx=%ld",obj->getBtnIndex());
	//			if (btn->getBtnIndex()!=obj->getBtnIndex())
	//			{
	//				cclOG("obj index%ldd",obj->getBtnIndex());
	//				obj->setTouchEnable(false);
	//			}
	//		}
	//	}
	//});
 //   
 //   
 //   
 //   /*******所有按钮置回可点状态********************************************/
 //   Director::getInstance()->getEventdispatcher()->addCustomEventListener(g_buttonReset,[&](EventCustom* event)
 //   {
 //       for (auto obj:m_allButtons)
 //       {
 //           obj->setTouchEnable(true);
 //       }
 //   });
 //   
 //   
 //   
 //   /*******按钮移除通知监听********************************************/
 //   Director::getInstance()->getEventdispatcher()->addCustomEventListener(g_buttonRemove,[&](EventCustom* event)
	//{
	//	auto btn = (WWButton*)event->getUserData();
	//	if (btn)
	//	{
	//		std::vector<WWButton*>::iterator i = m_allButtons.begin();
	//		while (i!=m_allButtons.end())
	//		{
	//			WWButton* obj = *i;
	//			if (obj->getBtnIndex()==btn->getBtnIndex())
	//			{
	//				m_allButtons.erase(i);
	//				break;
	//			}
	//			i++;
	//		}
	//	}
	//});
}

也就是说,一开始我把所有的按钮单独存储了一个状态,每次按钮点击的时候就会发送通知,将所有的按钮状态均置为fasle,不过后来幡然悔悟,用个全局变量就解决所有问题了,然后开始敲脑袋觉得智商捉急啊,所以把一些多此一举的代码贴上,以表耻辱。(不过还是觉得自己之前的想法也是有那么一点用处的,万一之后扩展,需要每次改变一些按钮的状态,这个按钮管理还是用得着的嘛。诸位莫要拍砖)

所以综上所述。cocos2dx有一点封装的还是不够好,就是在按钮点击方面,需要创建之后加入一个Menu里边,而如果一个界面出现多个层次的按钮,就需要多个Menu,而多个Menu之间再去做互斥又是多么蛋疼的事情啊,所以还是封装一个按钮来做互斥比较好一些。(今天喝了点白酒+龙舌兰+伏特加)半醉半朦胧,若有语焉不详之处,或者愚蠢的地方,欢迎留言拍砖。

cocos2dx点击事件的分发问题的更多相关文章

  1. 详解iOS游戏开发中Cocos2D的坐标位置关系

    这篇文章主要介绍了iOS游戏开发中Cocos2D的坐标位置关系,Cocos2D是专门用来开发iOS游戏的开源框架,文中示例代码采用Objective-C语言,需要的朋友可以参考下

  2. 剖析iOS开发中Cocos2d-x的内存管理相关操作

    这篇文章主要介绍了剖析iOS开发中Cocos2d-x的内存管理相关操作,Cocos2d-x是开发游戏的利器,需要的朋友可以参考下

  3. iOS开发中使用cocos2d添加触摸事件的方法

    这篇文章主要介绍了iOS开发中使用cocos2d添加触摸事件的方法,cocos2d是制作iOS游戏的利器,需要的朋友可以参考下

  4. ios – cocos2d 2.0-rc2:结束导演并重启

    我有一个使用UIKitmenues的cocos2d驱动游戏,所以我只使用一个viewcontroller的框架,这是游戏本身.此外,它只有一个场景.由于cocos2d2.0导演本身是一个UIViewController子类,所以我只需在用户点击一个开始按钮时将其推送到我的MenuViewController中:当用户启动第一个游戏时,第一次调用该方法时,这很好.当游戏结束时,我调用[[CCDire

  5. cocos2d 基本知识

    1.DrawNodedrawRect全屏:pad:460,320.iphone:400,3002.cocos2d-x-3.13.1&ios10.1:不设置position,ios模拟器屏幕上就看不到了3.cocos2d-xconsole生成初始项目:~/Desktop/cocos2d-x-3.13.1/tools/cocos2d-console/bin/cocosnewHelloMath-lcpp

  6. cocos2d随机数

    srand;intn=rand()%100+1;//生成1-100之间的随机数,包括100

  7. Cocos2d 2.0将UIView添加到CClayer openglview已弃用

    我有一些麻烦添加一个UIView到cocos2dv2.0,因为openGlView已被弃用,我无法添加视图.我在寻找另外一种方法来做到这一点,但是找不到任何东西.任何人都可以告诉我在所有cc层之前添加一个UIView的新方法?或者我该如何完成这个?使用这个而不是openGLView:

  8. cocos2d-x-3.3rc0事件处理

    1.头文件2.代码

  9. 一张图了解cocos2d坐标系

    一张图了解cocos2d坐标系平面直角坐标系

  10. cocos2d clippindNode,新手引导

    需要明确的一点就是CcclippingNode本质上是一个节点,什么是节点,节点就是可以存放东西,它也可以放到其他的节点上。还有就是如果用户没有按照要求点击的话,CcclippingNode的模板应该回到上一步的位置处才对,这里没有实现,不过项目中用的时候就需要根据你自己的需要去做了,这里只是为了说明原理。

随机推荐

  1. 【cocos2d-x 3.x 学习笔记】对象内存管理

    Cocos2d-x的内存管理cocos2d-x中使用的是上面的引用计数来管理内存,但是又增加了一些自己的特色。cocos2d-x中通过Ref类来实现引用计数,所有需要实现内存自动回收的类都应该继承自Ref类。下面是Ref类的定义:在cocos2d-x中创建对象通常有两种方式:这两中方式的差异可以参见我另一篇博文“对象创建方式讨论”。在cocos2d-x中提倡使用第二种方式,为了避免误用第一种方式,一般将构造函数设为protected或private。参考资料:[1]cocos2d-x高级开发教程2.3节[

  2. 利用cocos2dx 3.2开发消灭星星六如何在cocos2dx中显示中文

    由于编码的不同,在cocos2dx中的Label控件中如果放入中文字,往往会出现乱码。为了方便使用,我把这个从文档中获取中文字的方法放在一个头文件里面Chinese.h这里的tex_vec是cocos2dx提供的一个保存文档内容的一个容器。这里给出ChineseWords,xml的格式再看看ChineseWord的实现Chinese.cpp就这样,以后在需要用到中文字的地方,就先include这个头文件然后调用ChineseWord函数,获取一串中文字符串。

  3. 利用cocos2dx 3.2开发消灭星星七关于星星的算法

    在前面,我们已经在GameLayer中利用随机数初始化了一个StarMatrix,如果还不知道怎么创建星星矩阵请回去看看而且我们也讲了整个游戏的触摸事件的派发了。

  4. cocos2dx3.x 新手打包APK注意事项!

    这个在编译的时候就可以发现了比较好弄这只是我遇到的,其他的以后遇到再补充吧。。。以前被这两个问题坑了好久

  5. 利用cocos2dx 3.2开发消灭星星八游戏的结束判断与数据控制

    如果你看完之前的,那么你基本已经拥有一个消灭星星游戏的雏形。开始把剩下的两两互不相连的星星消去。那么如何判断是GameOver还是进入下一关呢。。其实游戏数据贯穿整个游戏,包括星星消除的时候要加到获得分数上,消去剩下两两不相连的星星的时候的加分政策等,因此如果前面没有做这一块的,最好回去搞一搞。

  6. 利用cocos2dx 3.2开发消灭星星九为游戏添加一些特效

    needClear是一个flag,当游戏判断不能再继续后,这个flag变为true,开始消除剩下的星星clearSumTime是一个累加器ONE_CLEAR_TIME就是每颗星星消除的时间2.连击加分信息一般消除一次星星都会有连击信息和加多少分的信息。其实这些combo标签就是一张图片,也是通过控制其属性或者runAction来实现。源码ComboEffect.hComboEffect.cpp4.消除星星粒子效果消除星星时,为了实现星星爆裂散落的效果,使用了cocos2d提供的粒子特效引擎对于粒子特效不了

  7. 02 Cocos2D-x引擎win7环境搭建及创建项目

    官网有搭建的文章,直接转载记录。环境搭建:本文介绍如何搭建Cocos2d-x3.2版本的开发环境。项目创建:一、通过命令创建项目前面搭建好环境后,怎样创建自己的Cocos2d-x项目呢?先来看看Cocos2d-x3.2的目录吧这就是Cocos2d-x3.2的目录。输入cocosnew项目名–p包名–lcpp–d路径回车就创建成功了例如:成功后,找到这个项目打开proj.win32目录下的Hello.slnF5成功了。

  8. 利用cocos2dx 3.2开发消灭星星十为游戏添加音效项目源码分享

    一个游戏,声音也是非常的重要,其实cocos2dx里面的简单音效引擎的使用是非常简单的。我这里只不过是用一个类对所有的音效进行管理罢了。Audio.hAudio.cpp好了,本系列教程到此结束,第一次写教程如有不对请见谅或指教,谢谢大家。最后附上整个项目的源代码点击打开链接

  9. 03 Helloworld

    程序都有一个入口点,在C++就是main函数了,打开main.cpp,代码如下:123456789101112131415161718#include"main.h"#include"AppDelegate.h"#include"cocos2d.h"USING_NS_CC;intAPIENTRY_tWinMain{UNREFERENCED_ParaMETER;UNREFERENCED_ParaMETER;//createtheapplicationinstanceAppDelegateapp;return

  10. MenuItemImage*图标菜单创建注意事项

    学习cocos2dx,看的是cocos2d-x3.x手游开发实例详解,这本书错误一大把,本着探索求知勇于发现错误改正错误的精神,我跟着书上的例子一起调试,当学习到场景切换这个小节的时候,出了个错误,卡了我好几个小时。

返回
顶部