最近在学习cocos2dx,发现原来2.0版本以前是没有鼠标监听器的,既然3.0版本有了,那刚好来学习一下。
通过鼠标监听器来实现,图像随鼠标的拖动而移动,如果鼠标释放的时候,图像没有位于正确的位置,那么图像就回归原处。
首先是加载图像什么的,就不用多说了。
Size visibleSize = Director::getInstance()->getVisibleSize();
auto whiteLayer = LayerColor::create(Color4B(255, 255, 255, 255));
this->addChild(whiteLayer);
auto rectangle1 = Sprite::create("rectangle.png");
rectangle1->setAnchorPoint(Point(0, 0));
rectangle1->setPosition(Point(visibleSize.width / 5, visibleSize.height / 2));
this->addChild(rectangle1);
auto rectangle2 = Sprite::create("rectangle.png");
rectangle2->setAnchorPoint(Point(0, 0));
rectangle2->setPosition(Point(visibleSize.width / 5 * 3, visibleSize.height / 2));
this->addChild(rectangle2);
auto fg = Sprite::create("font.png");
fg->setAnchorPoint(Point(0, 0));
fg->setPositionZ(1);
rectangle1->addChild(fg);
接着是配置监听器,现在3.0版本采用的是创建监听器,并将监听器添加到事件分发器上就可以了。
事件监听器有以下几种:
- 触摸事件 (EventListenerTouch)
- 键盘响应事件 (EventListenerKeyboard)
- 鼠标响应事件 (EventListenerMouse)
- 自定义事件 (EventListenerCustom)
- 加速记录事件 (EventListenerAcceleration)
_eventDispatcher
的工作由三部分组成:
- 事件分发器 EventDispatcher
- 事件类型 EventTouch, EventKeyboard 等
- 事件监听器 EventListenerTouch, EventListenerKeyboard 等
注册的时候有两种方法,一种是addEventListenerWithSceneGraphPriority
,另一种是addEventListenerWithFixedPriority
,其中addEventListenerWithSceneGraphPriority
会自动释放,所以可以优先使用这种方法。
顺便说一下,现在C++11多了特性lambda表达式,也就是匿名函数。可以参考这篇关于lambda表达式的文章http://www.cnblogs.com/haippy/archive/2013/05/31/3111560.html。
第一,监听器的创建和鼠标移动函数的实现,由于鼠标坐标系跟GL坐标系不太一样,它是以左上角为原点,向右为X轴正方向的,但是却以向上为Y轴正方向的,也就是其实界面的Y点都是负数的,所以利用visibleSize.height + cursorY来转换成正值。
对了,还有converToNoSpace函数,它是将某个点转化成在某个坐标系中的点,在这里是指鼠标的点转化成以rectangle1初始点为原点的坐标系中的点,从而能获得正确鼠标加载图像位置。
另外,setAnchorPoiint函数是关于锚点的设置。其中参数是以比例计算的,范围在0~1之间。
锚点就是子对象在父对象中的初始位置,通俗来讲,就是说setPosition是放置图像的位置,那么子对象是以什么点开始放置的呢?其实就是你设置的锚点,举个栗子,就是说setAnchorPoint(Point(0, 0)),setPosition(Point(100, 100)),那么子对象就以子对象的左下角为开始点,放置在(100,100)处,如果是setAnchorPoint(Point(1, 1)), setPosition(Point(100,100)),那么子对象就以子对象的右上角为开始点,放置在(100,100)处。
// Mouse listener configuration, in which getCursorX, the getCursorY function is to
// the upper left corner as the origin, to the right is the X axis, Y axis down negative.
auto _mouseListen = EventListenerMouse::create();
// The mouse move function.
_mouseListen->onMouseMove = [=](Event* event)
{
EventMouse* e = (EventMouse*)event;
if (e->getMouseButton() == 0)
{
float cursorX = e->getCursorX();
float cursorY = e->getCursorY();
Vec2 actualPosition = rectangle1->convertToNodeSpace(Point(cursorX, visibleSize.height + cursorY));
fg->setAnchorPoint(Point(0.5, 0.5));
fg->setPosition(actualPosition);
}
};
第二,释放鼠标函数,是判断某点是否位于区域中,使用的办法是通过获取图像矩形大小,然后利用方法containsPoint解决。其中,为了实现当放置点位于区域内时候,正确放置图像,将rectangle2原点左边转化成在recatangle1坐标系中的。
// The mouse release function.
_mouseListen->onMouseUp = [=](Event* event)
{
EventMouse* e = (EventMouse*)event;
float cursorX = e->getCursorX();
float cursorY = e->getCursorY();
Vec2 actualPositionInRectangle2 = rectangle2->convertToNodeSpace(Point(cursorX, visibleSize.height + cursorY));
Size size = rectangle2->getContentSize();
Rect rect = Rect(0, 0, size.width, size.height);
if (rect.containsPoint(actualPositionInRectangle2))
{
// To convert origin coordinates of second image in the coordinates system
// of the first image.
Vec2 convertPosition = rectangle1->convertToNodeSpace(rectangle2->getPosition());
fg->setAnchorPoint(Point(0, 0));
fg->setPosition(convertPosition);
}
else
{
fg->setAnchorPoint(Point(0, 0));
fg->setPosition(Point(0, 0));
}
};
最后,就是注册监听器。
auto _eventDispatcher = Director::getInstance()->getEventDispatcher();
_eventDispatcher->addEventListenerWithSceneGraphPriority(_mouseListen, fg);
截图: