cocos2d-x坐标转换
CONVERT POINT FUNC
cocos2d-x中,Node类有六个坐标转换函数,分别是:
Vec2 convertToNodeSpace(const Vec2& worldPoint) const;
Vec2 convertToWorldSpace(const Vec2& nodePoint) const;
Vec2 convertToNodeSpaceAR(const Vec2& worldPoint) const;
Vec2 convertToWorldSpaceAR(const Vec2& nodePoint) const;
Vec2 convertTouchToNodeSpace(Touch * touch) const;
Vec2 convertTouchToNodeSpaceAR(Touch * touch) const;
前四个函数作用于将传入的某个坐标转化为当前节点(调用者)的本地坐标系或世界坐标系(也就是父节点/scene的本地坐标系)中。后两个方便在触摸操作时直接转换,效果相同。
convertToWorldSpace
:把基于当前节点的本地坐标系下的坐标转换到世界坐标系中。
convertToNodeSpace
:把世界坐标转换到当前节点的本地坐标系中。
使用
例如,在飞机大战项目中,宠物是玩家的子节点,玩家是游戏场景的子节点,子弹层是游戏场景的子节点。子弹层计算子弹都在世界坐标系(基于游戏场景的本地坐标系)下。
玩家发射子弹时调用addBullet
方法时直接调用getPosition
函数就可以获得世界坐标。
如果宠物直接调用getPosition
所得到的是自己在父节点的本地坐标系中的位置。这里是(-100,0)。直接传入addBullet
将被看做基于游戏场景的本地坐标系,也就是这里的“世界坐标系”,很显然得不到预期结果。此时需要利用convert系列函数进行坐标转换。
void CPet::openFire(float fDelta)
{
Vec2 vec1 = this->getParent()->getPosition();
Vec2 vec2 = this->getPosition();
Vec2 vec = this->getParent()->convertToWorldSpaceAR(vec2); //坐标转换
CFly::getInstance()->getBulletLayer()->addBullet(vec, m_strBulletName);
}
为什么不是Vec2 vec = this->convertToWorldSpaceAR(vec2);
呢?
原因是vec2
需要转换到玩家所在的世界坐标,实际上vec2
已经是宠物的“世界坐标”了——getPosition
得到自己在父节点的本地坐标系中的位置,而父节点的本地坐标系就是子节点的“世界坐标系”。将世界坐标再次转换为世界坐标很明显是一件不符合逻辑的事。
因此,转换的重点是:
convertToWorldSpace
:把基于当前节点的本地坐标系下的坐标转换到世界坐标系中。
convertToNodeSpace
:把世界坐标转换到当前节点的本地坐标系中。
Vec2 vec = this->getParent()->convertToWorldSpaceAR(vec2); //坐标转换
这句的正确理解应该是“找到玩家节点的本地坐标系中宠物的位置,再调用玩家的convertToWorldSpace
将其转化到更广阔的世界坐标系(游戏场景的本地坐标系)中。”
基准点
convertToWorldSpace
和convertToWorldSpace
这两种转换都是不考虑锚点的,都以当前节点父类的左下角的坐标为标准。convertToNodeSpaceAR
和convertToWorldSpaceAR
注意到这两个方法只不过增加了AR的约束,也即锚点。其意思是:修改变换的基准。这样理解:
convertToNodeSpaceAR,就是将节点坐标系的坐标原点修改在其锚点位置。(convertToNodeSpace 节点坐标系的原点位置是其左下角 )
convertToWorldSpaceAR,就是在变换的时候将参照坐标修改到其锚点位置。(convertToWorldSpace 参照坐标是在其左下角 )