- A+
图像渲染和动画——坐标系详解
Contents
笛卡尔坐标系(Cartesian coordinates)
笛卡尔坐标系中定义右手系原点在左下角,x向右,y向上,z向外,OpenGL坐标系为笛卡尔右手系。
y
|
|
|
|
|
|-------------- x
/
/
/
/
z
Cocos2d-x坐标系和OpenGL坐标系相同,都是起源于笛卡尔坐标系。
屏幕坐标系(Screen Coordinates)
|-------------- x
|
|
|
|
|
y
iOS, Android, Windows Phone等在开发应用时使用的是标准屏幕坐标系,原点为屏幕左上角,x向右,y向下。
Cocos2d坐标系和OpenGL坐标系一样,原点为屏幕左下角,x向右,y向上。
世界坐标系(World Coordinate)
世界坐标系也叫做绝对坐标系,是游戏开发中建立的概念。因此,“世界”指游戏世界。
我们通过Node的setPosition设定元素的位置使用的是相对与其父节点的本地坐标系而非世界坐标系。
本地坐标系(Node Local)
本地坐标系也叫相对坐标系,是和节点相关联的坐标系。每个节点都有独立的坐标系,当节点移动或改变方向时,和该节点关联的坐标系将随之移动或改变方向。
锚点(Anchor Point)
在Cocos2d-x中Layer的Anchor Point为默认值(0, 0),其他Node的默认值为(0.5, 0.5)。
Layer比较特殊,它默认忽略锚点,需要先调用ignoreAnchorPointForPosition()。
PS: setPosition本质是设置节点的锚点在父节点本地坐标系上的位置。
VertexZ,PositionZ和zOrder
VerextZ是OpenGL坐标系中的Z值
PositionZ是Cocos2d-x坐标系中Z值,是全局渲染顺序即在根节点上的渲染顺序
zOrder是Cocos2d-x本地坐标系中Z值,是局部渲染顺序,即该节点在其父节点上的渲染顺序,与Node的层级有关
可通过setPositionZ来设置PositionZ
相关坐标转换函数
// 获取触摸点的GL坐标
getLocation()
// 获取触摸点的屏幕坐标
getLocationInView()
// 把世界坐标转换到当前节点的本地坐标系中
Point convertToNodeSpace(const Point& worldPoint) const;
// 把基于当前节点的本地坐标系下的坐标转换到世界坐标系中
Point convertToWorldSpace(const Point& nodePoint) const;
// 基于Anchor Point把基于当前节点的本地坐标系下的坐标转换到世界坐标系中
Point convertToNodeSpaceAR(const Point& worldPoint) const;
// 基于Anchor Point把世界坐标转换到当前节点的本地坐标系中
Point convertToWorldSpaceAR(const Point& nodePoint) const;
触摸点(Touch position)
单点触摸
auto touchListener = EventListenerTouchOneByOne::create(); // 创建单点触摸监听器
touchListener->setSwallowTouches(true); // 设置触摸向下传递
普通写法
virtual bool onTouchBegan(Touch *touch, Event * event);
virtual void onTouchMoved(Touch *touch, Event * event);
virtual void onTouchEnded(Touch *touch, Event * event);
virtual void onTouchCancelled(Touch *touch, Event * event);
touchListener->onTouchBegan = CC_CALLBACK_2(TestScene1::onTouchBegan, this);
touchListener->onTouchMoved = CC_CALLBACK_2(TestScene1::onTouchMoved, this);
touchListener->onTouchEnded = CC_CALLBACK_2(TestScene1::onTouchEnded, this);
touchListener->onTouchCancelled = CC_CALLBACK_2(TestScene1::onTouchCancelled, this);
lambda表达式写法
touchListener->onTouchBegan = [](Touch* touch, Event* event){
log("onTouchBegan");
return true;
};
touchListener->onTouchMoved = [](Touch* touch, Event* event){
log("onTouchMoved");
};
touchListener->onTouchEnded = [](Touch* touch, Event* event){
log("onTouchEnded");
};
touchListener->onTouchCancelled = [](Touch* touch, Event* event){
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, sprite);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener->clone(), sprite2);
PS: 使用addEventListenerWithSceneGraphPriority添加事件监听器后,发生触摸事件,会先根据PositionZ由大到小,再根据zOrder由大到小进行响应。
点击检测
检测是否是点击在了想要的精灵上
通过获取触摸点的GL坐标,并转化成指定的对象节点的本地坐标,如果坐标处于指定的对象节点矩形区域内,则认定为点击在该对象上
bool TestScene1::onTouchBegan( Touch* touch, Event* event )
{
log("onTouchBegan");
auto target = static_cast<Sprite*>(event->getCurrentTarget());
Vec2 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);
return true;
}
return false;
}
PS: getCurrentTarget获取到的目标不一定是选中的目标,而是事件传递给的目标。
onTouchBegan不同于其他三个函数,onTouchBegan的返回值是bool。只有当onTouchBegan返回true后,才有可能触发后续的onTouchMoved和onTouchEnded函数。
可以认为onTouchBegan函数就是用来挑选确定给onTouchMoved和onTouchEnded传递的event指针所关联的对象。