1.新建项目,用VS打开.sln文件,在HelloWorldScene.cpp中写入自己代码,这一步主要是添加背景图,以及添加4个精灵图
素材:https://pan.baidu.com/s/1GXwgb7u3RsUBD9ajY06zGg
bool HelloWorld::init()
{
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
//加入背景
auto *background = Sprite::create("bg.jpg");
background->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
this->addChild(background);
//加入卡牌精灵
Sprite *myCard[4];
for (int i = 0; i < 4; i++)
{
char imageName[15] = { 0 };
//Sprite myCard[4];
sprintf(imageName, "mycard0%d.png", i + 1);
myCard[i] = Sprite::create(imageName);
myCard[i]->setScale(0.5f);
myCard[i]->setPosition(visibleSize.width*(i + 1) / 5, visibleSize.height / 2);
this->addChild(myCard[i]);
}
return true;
}
实现效果
2.建立事件监听
第一步
// 创建一个事件监听器 OneByOne 为单点触摸
auto myListener = EventListenerTouchOneByOne::create();
//设置是否吞没事件,在 onTouchBegan 方法返回 true 时吞没
myListener->setSwallowTouches(true);
//C++11中的Lambda表达式
//[=] 以值的形式捕获所有外部变量
//[] 不捕获任何外部变量
//onTouchBegan 事件回调函数
myListener->onTouchBegan = [=](Touch* touch, Event* event)
{
//获取事件所绑定的target
auto target = static_cast(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("x = %f, y = %f", locationInNode.x, locationInNode.y);
target->setOpacity(180);
return true;
}
return false;
};
提示 为了能够在onTouchBegan 方法中引用来自外部的局部变量,需要[=],这样设置,否则会报错
第二步
//onTouchMoved 事件回调函数
myListener->onTouchMoved = [](Touch* touch, Event* event)
{
auto target = static_cast(event->getCurrentTarget());
//显示当前卡牌精灵的坐标位置
log("x = %f, y = %f", touch->getLocation().x, touch->getLocation().y);
//移动当前卡牌的精灵坐标位置
target->setPosition(target->getPosition() + touch->getDelta());
};
//onTouchEnded 事件回调函数
myListener->onTouchEnded = [](Touch* touch, Event* event)
{
auto target = static_cast(event->getCurrentTarget());
target->setOpacity(255);
};
可以在VS的输出栏看到下图所示
3.为事件监听器绑定事件
//为事件监听器绑定事件,用来判断是对哪个卡牌进行事件响应
_eventDispatcher->addEventListenerWithSceneGraphPriority(myListener, myCard[0]);
//再次绑定是要用clone方法
_eventDispatcher->addEventListenerWithSceneGraphPriority(myListener->clone(), myCard[1]);
_eventDispatcher->addEventListenerWithSceneGraphPriority(myListener->clone(), myCard[2]);
_eventDispatcher->addEventListenerWithSceneGraphPriority(myListener->clone(), myCard[3]);
点击运行,效果图
新知识,了解一下:
单词:touch触摸 opcacity不透明度 node节点 location位置 convert转换 current当前的
target对象 event事件 graph图 priority优先级 swallow吞没
listener->setSwallowTouches(true),不向下触摸
简单点来说,比如有两个sprite ,A 和 B,A在上B在下(位置重叠),触摸A的时候,B不会受到影响
我们可以看到,通过EventListenerTouchOneByOne定义了单点触控的监听器。
然后对其响应类型进行了定义:
onTouchBegan对用户的触摸到屏幕的操作进行处理,首先获取了事件绑定的target,即用户的滑动、拖曳行为针对哪一个对象进行操作,这里的操作对象是卡牌。然后判断单击的坐标是否包含于操作对象范围中,如果包含在里面,则返回true,才能执行onTouchMoved;否则返回false,不执行onTouchMoved。
onTouchMoved对用户在操作对象上的拖动操作进行处理,根据用户的触摸位置来改变操作对象的位置。其中存在一个问题,如果对两个操作对象重叠部分进行操作,应该移动哪一个触摸对象呢?这里通过setSwallowTouches()设置是否允许触摸事件向下传递,true则不传递,即只对上层对象进行操作,而false则会传递,当触摸重叠区域时,重叠的所有对象都会被操作。
onTouchEnded对用户触摸结束时进行处理,这个例子中,只是调整了精灵的透明度。在最后一部分也是十分重要的一部分,可以看到,通过_eventDispatcher->addEventListenerWithSceneGraphPriority将对象与监听器进行了绑定,其中的_eventDispatcher是Node对象中自带的属性,用于统一管理各个节点的分发情况。需要注意的是对不同对象进行绑定时,要对触发器对象使用clone方法来保证程序的正常运行。
拓展:
如果在4张卡牌都被绑定了事件监听的情况下,怎么保证只有第一张牌能被拖动呢?
只要将if (rect.containsPoint(locationInNode))改为if (rect.containsPoint(locationInNode)&&target==myCard[0]),皆可