Cocos2d-x 之 事件处理机制

简述

    无论是否针对Cocos2d-x,事件处理都是很重要的部分。一般都含有鼠标,键盘事件,还有一些就是根据自己特性特有的。因为Cocos2d-x是游戏引擎,所以在游戏中 点击 /滑动 用到的 单点触摸事件(EventListenerTouchOneByOne)、多点触发事件(EventListenerTouchAllAtOnce)就很好理解了。除了这些 还有加速计事件(EventListenerAcceleration),自定义事件(EventListenerCustom)等。                                                                                                                                                                                                 

                                                                                                                                                                                                                               基本元素

  • 事件监听器:负责接收事件,并执行预定义的事件处理函数
  • 事件分发器:负责发起通知
  • 事件对象:记录事件的相关信息


(1)事件监听器

    EventListener 类是事件监听器的基类,如果需要自定义监听器与不同的回调,需要继承该类 。该类的继承关系如图所示。    

Cocos2d-x 之 事件处理机制_第1张图片

(2)事件分发器

    EventDispatcher类表示一个事件的分发器,它的作用是管理事件监听器及事件分发,当一个事件触发时,它会向所有需要的对象发送用户操作信息。在Node类中有个_eventDispatcher成员变量,通过它管理节点(如场景、层,精灵等)的多有事件分发情况。EventDispatcher 类还有一个集合列表,用来保存所有添加了的事件监听器。

常用的函数有:

void addEventListenerWithSceneGraphPriority(EventListener*listener,Node*node) :添加场景优先事件监听器。响应事件优先级基于Node绘制顺序,zOrder顺序高的先调用。自顶向下的传播。

void addEventListenerWithFixPriority(EventListener* listener,Node* node):添加固定优先值的事件监听器。优先级值低的事件监听器将先于优先级值高的事件监听器被调用。   


示例                         

列举几个例子更清楚的理解。

(1)TouchOneByOneTest  (单点触发事件 EventListenerTouchOneByOne

	// 创建三个精灵对象
	auto sprite1 = Sprite::create("CyanSquare.png");
	sprite1->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2) + Vec2(-80, 80));
	addChild(sprite1, 10);

	auto sprite2 = Sprite::create("MagentaSquare.png");
	sprite2->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
	addChild(sprite2, 20);

	auto sprite3 = Sprite::create("YellowSquare.png");
	sprite3->setPosition(Vec2(0, 0));
	sprite2->addChild(sprite3, 1);

	//创建一个单点触摸事件监听器,处理触摸事件逻辑
	auto listener1 = EventListenerTouchOneByOne::create();
	//设置是否向下传递触摸
	listener1->setSwallowTouches(true);
	//通过 lambda 表达式 直接实现触摸事件的响应函数
	listener1->onTouchBegan = [](Touch* touch, Event* event){
		auto targer = static_cast(event->getCurrentTarget());
		Point locationInNode = targer->convertToNodeSpace(touch->getLocation());
		Size s = targer->getContentSize();
		Rect rect = Rect(0, 0, s.width, s.height);
		if (rect.containsPoint(locationInNode))
		{
			log("onTouchBegin...x=%f, y=%f", locationInNode.x, locationInNode.y);
			targer->setOpacity(180);
			return true;
		}
		return false;
	};

	listener1->onTouchMoved = [](Touch* touch, Event *event){
		auto target = static_cast(event->getCurrentTarget());
		//移动精灵
		target->setPosition(target->getPosition() + touch->getDelta());
	};
	//[=]值传递
	listener1->onTouchEnded = [=](Touch* touch, Event *event){
		auto target = static_cast(event->getCurrentTarget());
		// 设置透明度
		target->setOpacity(255);
		std::string name;
		if (target == sprite2)
		{
			name = "MagentaSquare.png";
			sprite1->setZOrder(100);
			subtitle->setString(FontToUTF8("响应事件的是酒红色滑块,青色滑块的ZOrder值修改为100"));
		}
		else if (target == sprite1)
		{
			name = "CyanSquare.png";
			sprite1->setZOrder(0);
			subtitle->setString(FontToUTF8("响应事件的是青色滑块,青色滑块的ZOrder值修改为0"));
		}
		else{
			name = "YellowSquare.png";
		}
		log(FontToUTF8("onTouchEnded.. 您触摸的是%s"), name.c_str());
	};
	//添加场景优先事件监听器

	_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);
	
	_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite2);
	_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite3);

注意:在使用addEventListenerWithSceneGraphPriority或者addEventListenerWithFixedPriority函数时,会对当前使用的事件监听器添加一个已注册的标记,这使得它不能够被添加多次。所以当我们再次使用listener1的时候,需要使用clone()函数创建一个新的克隆。

(2)TouchAllatOnceTest(多点触发事件 EventListenerTouchAllAtOnce

多点触发事件略微与单点触发事件不同,主要体现在:人家是多点,o(* ̄︶ ̄*)o,从函数

void onTouchesBegan(const std::vector &touches, cocos2d::Event *event); 的第一个参数touches是集合的形式可以看出。                

(3) CustomTest (自定义事件 EventListenerCustom

    自定义事件不是由系统自动触发的,而是需要人为干涉,这一点很需要注意。

void TouchAllatOnceTest::onTouchesBegan(const std::vector& touches, Event  *event)
{
	if (touches.size() >= 2)
	{
		auto touch1 = touches.at(0);
		Vec2 mPoint1 = Director::getInstance()->convertToGL(touch1->getLocation());
		
		auto touch2 = touches.at(1);
		Vec2 mPoint2 = Director::getInstance()->convertToGL(touch2->getLocation());
		// 获得新触摸点两点之间的距离
		_distance = sqrt((mPoint1.x - mPoint2.x)*(mPoint1.x - mPoint2.x) + (mPoint1.y - mPoint2.y)*(mPoint1.y - mPoint2.y));

	}
}

void TouchAllatOnceTest::onTouchesMoved(const std::vector& touches, Event  *event)
{
	if (touches.size() >= 2)
	{
		auto touch1 = touches.at(0);
		Vec2 mPoint1 = Director::getInstance()->convertToGL(touch1->getLocation());

		auto touch2 = touches.at(1);
		Vec2 mPoint2 = Director::getInstance()->convertToGL(touch2->getLocation());
		// 获得新触摸点两点之间的距离
		double mdistance = sqrt((mPoint1.x - mPoint2.x)*(mPoint1.x - mPoint2.x) + (mPoint1.y - mPoint2.y)*(mPoint1.y - mPoint2.y));
		_mscale = mdistance / _distance*_mscale;
		_bgSprite->setScale(_mscale);
	}
}

void TouchAllatOnceTest::onTouchesEnded(const std::vector& touches, Event  *event)
{

}

void TouchAllatOnceTest::onTouchesCancelled(const std::vector& touches, Event  *event)
{

}

	auto listener = EventListenerCustom::create("game_custom_event", [=](EventCustom* event){
		statusLabel->setString(StringUtils::format("receive custom event [%s]times", event->getUserData()));
	});

	_eventDispatcher->addEventListenerWithFixedPriority(listener, 1);

	static int count = 0;

	auto sendItem = MenuItemFont::create("click send custom event", [=](Ref* sender){
		++count;
		char* buf = new char[10];
		sprintf(buf, "%d", count);
		EventCustom event("game_custom_event");
		event.setUserData(buf);
		//将此事件分发出去 从而触发之前所实现的逻辑  这里发送出去   在上面响应
		_eventDispatcher->dispatchEvent(&event);
		//释放数据占据的内存
		CC_SAFE_DELETE_ARRAY(buf);
	});


                         

你可能感兴趣的:(cocos2d-x,事件分发机制)