您的位置:首页 > 移动开发 > Cocos引擎

cocos2dx 3.2 触摸

2014-09-15 13:21 274 查看
例子:
设置
menu优先级

void
GameUtil::pack_setPriority2(Layer *layer,
EventListenerTouchOneByOne *touchListener,int priority ,bool swallow)
{
auto dispatcher =
Director::getInstance()->getEventDispatcher();

dispatcher->removeEventListenersForTarget(layer);
touchListener->onTouchBegan =
CC_CALLBACK_2(Layer::onTouchBegan,layer);
touchListener->onTouchMoved =
CC_CALLBACK_2(Layer::onTouchMoved,layer);
touchListener->onTouchEnded =
CC_CALLBACK_2(Layer::onTouchEnded,layer);
touchListener->setSwallowTouches(swallow);

//设置不想向下传递触摸 true是不想
默认为false
dispatcher->addEventListenerWithFixedPriority(touchListener,priority);

//下面的监听和layer绑定 layer释放连带监听 不需要手动 但是下面方法无法设置优先级
// dispatcher->addEventListenerWithSceneGraphPriority(touchListener,layer);
// Sets listener's priority with fixed value. 这个函数只能设置fix priority 不能设置GraphPriority 所以不能用上一个方法
// dispatcher->setPriority(touchListener,priority);
}

使用:

static EventListenerTouchOneByOne* listener; //可控的监听

//!触摸生效
void
classXXX::setMyTouchEnable()
{

listener = EventListenerTouchOneByOne::create();

GameUtil::pack_setPriority2(this, listener,1 ,true);
}

//!触摸失效
void
classXXX::setMyTouchDisable()
{

if(listener)

_eventDispatcher->removeEventListener(_touchListener);

}

前言

Cocos2d-X 3.0 引入了一个新的机制来响应用户事件。这篇文档将解释新的机制是如何工作的。

基础概念:

Event listeners 包含了你的事件处理代码
Event dispatcher 用于通知用户事件监听器
Event objects 包含事件的信息

为了响应事件, 你必须创建一个 EventListener 。一共有5种不同的 EventListener :

EventListenerTouch
响应触摸事件
EventListenerKeyboard
响应键盘事件
EventListenerAcceleration
响应加速计事件
EventListenMouse
响应鼠标事件
EventListenerCustom
响应自定义的事件

然后, 把你的事件处理代码添加到 Event listeners 中的合适的回调函数中 (例如,
onTouchBegan
对应
EventListenerTouch
监听器,
onKeyPressed
对应
键盘事件监听器。

下一步,用 EventDispatcher 注册你的 EventListener 。

当事件发生时 (例如用户触摸了屏幕,按下了键盘的某个键),
EventDispatcher
将分发 Event objects (例如
EventTouch
,
EventKeyboard
)
给合适的 EventListeners 然后调用你的回调函数。 每一个事件对象都包含事件的相关信息 (例如事件发生的坐标)。


例子

在下面的例子中, 我们将在Scene中添加3个部分重叠的按钮。 每一个按钮都响应触摸按钮。


使用图片创建3个Sprite作为按钮

auto sprite1 = Sprite::create("Images/CyanSquare.png");
sprite1->setPosition(origin+Point(size.width/2, size.height/2) + Point(-80, 80));
addChild(sprite1, 10);

auto sprite2 = Sprite::create("Images/MagentaSquare.png");
sprite2->setPosition(origin+Point(size.width/2, size.height/2));
addChild(sprite2, 20);

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






创建一个单点触摸事件监听器并且添加回调代码

(需要注意的是,在下面的例子中, 我们使用 C++11 lambda 表达式 实现回调。可以看到,在下面的键盘事件例子中,使用了不同的方式来书写,使用了
CC_CALLBACK_N
宏。

//创建一个单点(one by one)触摸事件监听器(一次处理一个触摸)
auto listener1 = EventListenerTouchOneByOne::create();
// 当吞噬触摸(swallow touches)被设置为 true ,然后如果在 onTouchBegan 方法中返回 true ,那么触摸事件将会被吞噬,防止其他的监听器使用。
listener1->setSwallowTouches(true);

// 通过 lambda 表达式实现 onTouchBegan 回调方法的例子
listener1->onTouchBegan = [](Touch* touch, Event* event){
// event->getCurrentTarget() 返回监听器的 sceneGraphPriority node 。
auto target = static_cast<Sprite*>(event->getCurrentTarget());

//得到现在的点相对于按钮的位置。
Point locationInNode = target->convertToNodeSpace(touch->getLocation());
Size s = target->getContentSize();
Rect rect = Rect(0, 0, s.width, s.height);

//检查点击区域
if (rect.containsPoint(locationInNode))
{
log("sprite began... x = %f, y = %f", locationInNode.x, locationInNode.y);
target->setOpacity(180);
return true;
}
return false;
};

//触摸移动的触发器
listener1->onTouchMoved = [](Touch* touch, Event* event){
auto target = static_cast<Sprite*>(event->getCurrentTarget());
//Move the position of current button sprite
//Move the position of current button sprite
target->setPosition(target->getPosition() + touch->getDelta());
};

//处理触摸结束事件
listener1->onTouchEnded = [=](Touch* touch, Event* event){
auto target = static_cast<Sprite*>(event->getCurrentTarget());
log("sprite onTouchesEnded.. ");
target->setOpacity(255);
//重新设置zOrder,将改变现实顺序
if (target == sprite2)
{
sprite1->setZOrder(100);
}
else if(target == sprite1)
{
sprite1->setZOrder(0);
}
};



将事件监听器添加到事件分发器中

//添加事件监听器
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite2);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite3);


_eventDispatcher 是一个 Node 的属性. 你可以使用它管理当前节点(Node)的所有事件的分发(这些节点可以是 Scene,Layer,Sprite 等)。

注意: 在上面的例子中, 我们在第二和第三个调用
addEventListenerWithSceneGraphPriority
使用
clone()
方法。这是因为每一个事件监听器只能被添加一次。
addEventListenerWithSceneGraphPriority
addEventListenerWithFixedPriority
方法在事件监听器中设置了一个注册标志,如果注册标志已经被设置了,就不能再次添加了。

还有一点是需要记住的: 如果你给一个节点添加 fixed priority 监听器, 当这个节点被移除了之后,你需要手动移除这个。然而,这种情况对于 scene graph priority 监听器来说,它是和节点捆绑的,当一个节点的析构函数被调用的时候,监听器会自动移除。


新的触摸机制

上面的过程和2.x版本的事件机制相比似乎看起来更加的复杂。在老版本中, 你需要继承一个委托( delegate )类,它定义了
onTouchBegan()
方法等。你的事件处理代码将会进入到这些委托方法。

新的事件机制从 delegate 中移除了事件处理逻辑,将这些逻辑移到了监听器中。但是,上面的逻辑实现了下方的方法: 1. 通过使用一个事件监听器, sprite 可以通过 SceneGraphPriority 被添加到事件分发器。当点击一个 sprite 按钮,相同绘制等级的回调函数将会被调用(换句话说,最表面的 sprite 将最先得到触摸事件)。 2. 处理事件逻辑的时候,当被触摸时根据每种情况采取相应的处理逻辑来显示点击效果(例如识别点击区域,为被点击的元素设置不同的透明度)。
3. 当
listener1->setSwallowTouches(true)
被设置的时候,将根据 onTouchBegan 的返回值, 决定触摸事件的显示顺序是否应该被向后传递。


FixedPriority
vs SceneGraphPriority

FixedPriority 是一个 int 值. 带有更小的
Priority
值事件监听器将先处理事件,更大的
Priority
值的将后处理。
SceneGraphPriority 是一个指向
Node
的指针. 拥有更高的 Z
order 值的节点的监听器将比低 Z order 值的先接收到事件。(话句话说,Z order 越大就是被绘制在越表面)。这保证了触摸事件可以从前向后传递。


其他事件分发处理模块

除了触摸事件响应,下面的模块也使用了相同事件处理方法。


按键事件(Keyboard
events)

除了键盘,它也可以是每一个有菜单的设备,他们可以使用相同的监听器来处理事件。

在上方的触摸事件中,我们使用了 lamdba 表达式设置回调函数。你也可以通过
CC_CALLBACK_N
宏来绑定已经存在的回调函数。如下:

//初始化并绑定
auto listener = EventListenerKeyboard::create();
listener->onKeyPressed = CC_CALLBACK_2(KeyboardTest::onKeyPressed, this);
listener->onKeyReleased = CC_CALLBACK_2(KeyboardTest::onKeyReleased, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

// 按键事件回调方法的实现原型
void KeyboardTest::onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event)
{
log("Key with keycode %d pressed", keyCode);
}

void KeyboardTest::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event)
{
log("Key with keycode %d released", keyCode);
}



加速计事件(Accelerometer
events)

在使用加速计事件之前,你必须先在设备上将他们开启:

Device::setAccelerometerEnabled(true);


然后创建相应的监听器。

auto listener = EventListenerAcceleration::create(CC_CALLBACK_2(AccelerometerTest::onAcceleration, this));
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

// 加速计事件回调方法的实现原型
void AccelerometerTest::onAcceleration(Acceleration* acc, Event* event)
{
//  逻辑处理代码
}



鼠标事件(Mouse
events)

鼠标点击事件的分发已经被添加到3.0版本了。它可以跨平台,并且丰富了游戏的用户体验。

如同所有的事件类型,首先我们需要创建事件监听器:

_mouseListener = EventListenerMouse::create();
_mouseListener->onMouseMove = CC_CALLBACK_1(MouseTest::onMouseMove, this);
_mouseListener->onMouseUp = CC_CALLBACK_1(MouseTest::onMouseUp, this);
_mouseListener->onMouseDown = CC_CALLBACK_1(MouseTest::onMouseDown, this);
_mouseListener->onMouseScroll = CC_CALLBACK_1(MouseTest::onMouseScroll, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(_mouseListener, this);


然后一个接一个地实现每一个回调方法并绑定到监听器:

void MouseTest::onMouseDown(Event *event)
{
EventMouse* e = (EventMouse*)event;
string str = "Mouse Down detected, Key: ";
str += tostr(e->getMouseButton());
// ...
}

void MouseTest::onMouseUp(Event *event)
{
EventMouse* e = (EventMouse*)event;
string str = "Mouse Up detected, Key: ";
str += tostr(e->getMouseButton());
// ...
}

void MouseTest::onMouseMove(Event *event)
{
EventMouse* e = (EventMouse*)event;
string str = "MousePosition X:";
str = str + tostr(e->getCursorX()) + " Y:" + tostr(e->getCursorY());
// ...
}

void MouseTest::onMouseScroll(Event *event)
{
EventMouse* e = (EventMouse*)event;
string str = "Mouse Scroll detected, X: ";
str = str + tostr(e->getScrollX()) + " Y: " + tostr(e->getScrollY());
// ...
}



自定义事件(Custom
Event)

上面的事件类型是系统已经定义了的,而且事件(例如触摸屏幕,按键响应)是由系统自动触发的。另外,你可以制作你自己的 custom events ,它们可以不由系统触发,但是必须通过你的代码,如下:

_listener = EventListenerCustom::create("game_custom_event1", [=](EventCustom* event){
std::string str("Custom event 1 received, ");
char* buf = static_cast<char*>(event->getUserData());
str += buf;
str += " times";
statusLabel->setString(str.c_str());
});

_eventDispatcher->addEventListenerWithFixedPriority(_listener, 1);


上面自定义了一个事件监听器,并且带有一个响应方法。它被添加到了事件分发器里。那如何处理事件触发呢,往下看:

static int count = 0;
++count;
char* buf = new char[10];
sprintf(buf, "%d", count);
EventCustom event("game_custom_event1");
event.setUserData(buf);
_eventDispatcher->dispatchEvent(&event);
CC_SAFE_DELETE_ARRAY(buf);


上面的例子创建了一个
EventCustom
对象,并且设置了他的 UserData。之后,它被
_eventDispatcher->dispatchEvent(&event);
手动的分发。它将触发之前定义好的事件处理方法。


移除事件监听器

一个已经添加的监听器可以通过下方的方法移除:

_eventDispatcher->removeEventListener(listener);


使用下方的代码移除事件分发器的所有监听器:

_eventDispatcher->removeAllEventListeners();


当使用
removeAll
的时候,这个节点的所有监听器都会被移除。推荐的做法是移除指定的监听器。

注意:在使用
removeAll
之后,菜单将不会响应,因为它也需要接受触摸事件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: