cocos2dx[3.x](7) ——坐标系统

【小知识】

    Vec2:cocos2dx中的二维向量坐标类。

 

一、坐标系

    你可能在学校的几何学上已经知道笛卡尔坐标系。

    如果你忘记了,下面的图片可以让你回忆一下:

wKiom1QHD7ih12uXAACFtUODbEo714.jpg

 

    有3种类型的坐标系在游戏开发中你会用的到。

    (1)UI坐标系:              一般用于Android、IOS中:原点(x=0,y=0)在左上角。

                                (X方向从左侧向右侧递增,Y方向从屏幕顶部向底部递增)

    (2)Direct3D坐标系:        DirectX,用左手笛卡尔坐标系。

    (3)OpenGL和cocos2dx坐标系:cocos2dx和OpenGL一样,用右手坐标系。

 wKiom1QwNU2gEdpCAABJ4xvFGlw302.jpg        wKiom1QHEEjBvYkOAAApNrcbpIc124.jpg

 

    原点在屏幕的左下角,意味着屏幕在右手坐标系的第一象限中。

    X轴从屏幕左侧向右侧延伸,Y轴从屏幕底部向顶部延伸。

    底下有张图片可以帮你理解cocos2dx坐标系:

wKioL1QHEKfx1U20AAC4dPxWKJI724.jpg

二、父类和子类

    每一个继承自Node的类都有一个锚点属性。当决定如何绘制对象(Sprite,Layer等等)的时候,cocos2dx将会考虑位置信息以及锚点信息。并且,当旋转一个物体的时候,cocos2dx也会绕着锚点旋转。

    我们创建一个蓝色的Sprite图像作为父对象,创建一个棕色的Sprite作为子对象。设置父对象的位置为Vec2(100,100),锚点Vec2(0,0);子对象的位置在Vec2(0,0),锚点Vec2(0.5,0.5)。

 

//
    Sprite* parent = Sprite::create("parent.png");
    parent->setAnchorPoint(Vec2(0, 0)); //锚点
    parent->setPosition(Vec2(100, 100));
    this->addChild(parent);
   
    //create child
    Sprite* child = Sprite::create("child.png");
    child->setAnchorPoint(Vec2(0.5, 0.5)); //锚点
    child->setPosition(Vec2(0, 0));
    parent->addChild(child); //添加子精灵到父精灵中
//

我们设置了子对象的位置在Vec2(0,0),父对象的位置在Vec2(100,100)。

    因此,子对象显示在如图所示位置:

wKioL1QHEMCD3XvwAAEQ49QimA8160.jpg

三、锚点

    锚点被用于位置和旋转物体。锚点是相对坐标(也就是一个百分比),经常被用来对应一个物体内的点。例如:锚点是Vec2(0.5,0.5),(表示x方向在物体50%的位置,y方向50%的位置)对应物体的中心。当设置物体位置的时候,调用setPositon时,锚点信息也会在坐标系中展示。相同的,当转动物体,物体将会随锚点转动。

    例如:如下精灵有一个锚点Vec2(0,0),并且位置在Vec2(0,0)。

wKiom1QHENShGOjPAAASugHSI0w488.jpg

    因此,精灵被放置在屏幕左下角。

1

2

3

4

5

6

7

//

    //创建精灵

    Sprite* sprite = Sprite::create("bottomleft.png");

    sprite->setAnchorPoint(Vec2(0, 0)); //锚点

    sprite->setPosition(Vec2(0,0));

    this->addChild(sprite);

//

 

    在如下的例子中,展示了锚点坐标的相对性,锚点被赋值为Vec2(0.5,0.5),位于精灵的中心。

wKiom1QHEO2SPgtYAAATyWAX9OY107.jpg

1

2

3

4

5

6

7

//

    //创建精灵  

    Sprite* sprite = Sprite::create("center.png");

    sprite->setAnchorPoint(Vec2(0.5, 0.5)); //Anchor Point

    sprite->setPosition(Vec2(0,0));

    this->addChild(sprite);

//

 

 正如你所看到的的,精灵的中心位置被放置在了坐标原点(0,0)。这也就是说锚点不是一个像素值。锚点的X和Y值是相对于该节点的大小。

    你也可以设置锚点为Vec2(0.3,0.3),物体左下角锚点是(0,0),右上角是(1,1),因此Vec2(0.3,0.3)表示在X方向上30%位置,Y方向上30%位置。

wKioL1QHESWig7AvAACxLif71iE069.jpg

 


 

【渲染顺序】

    在2.x中是使用Zorder来控制节点渲染的先后顺序的。而在3.x中渲染的顺序则是由两个因素决定。

        > 全局Z顺序:GlobalZOrder。所有节点之间对比。

        > 局部Z顺序:LocalZOrder。 兄弟节点之间对比。

    且Z顺序越小,最先渲染。

 

1、全局Z顺序

    > 定义渲染节点的顺序,拥有全局Z顺序越小的节点,最先渲染。

    > 假设:两个或者更多的节点拥有相同的全局Z顺序,那么渲染顺序无法保证。唯一的例外是如果节点的全局Z顺序为零,那么场景图顺序是可以使用的。

    > 默认的,所有的节点全局Z顺序都是零。这就是说,默认使用场景图顺序来渲染节点。

    > 全局Z顺序是非常有用的当你需要渲染节点按照不同的顺序而不是场景图顺序。

    > 局限性: 全局Z顺序不能够被拥有继承“SpriteBatchNode”的节点使用。

1

2

3

4

//

    virtual void setGlobalZOrder(float globalZOrder);

    virtual float getGlobalZOrder() const;

//

 

2、局部Z顺序

    > LocalZOrder是“key”(关键)来分辨节点和它兄弟节点的相关性。

    > 父节点将会通过LocalZOrder的值来分辨所有的子节点。如果两个节点有同样的LocalZOrder,那么先加入子节点数组的节点将会比后加入的节点先得到渲染,那么先加入的节点会被后加入的节点遮盖[update 20140927]。

    > 同样的,场景图使用“In-Order(按顺序)”遍历数算法来遍历。并且拥有小于0的LocalZOrder的值的节点是“left”子树(左子树) 所以拥有大于0的LocalZOrder的值得节点是“right”子树(右子树)。

1

2

3

4

5

//

    //设置这个节点的局部Z顺序((相对于兄弟节点))

    virtual void setLocalZOrder(int localZOrder);

    virtual int getLocalZOrder() const;

//

 


 

【坐标转换】

    参考:http://www.tairan.com/archives/5739

 

1、坐标转换函数

    坐标分为两种坐标:

        > 世界坐标:就是相对节点的世界坐标。

        > 局部坐标:就是相对节点的坐标。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

//

/**

 * 坐标转换convertTo

 *     WorldSpace :   世界坐标

 *     NodeSpace  :  局部坐标

 *

 */

    //把世界坐标, 转换到当前节点的本地坐标系中

    //基于Anchor Point, 把基于当前节点的本地坐标系下的坐标, 转换到世界坐标系中

    Vec2 convertToNodeSpace(const Vec2& worldPoint) const;

    Vec2 convertToNodeSpaceAR(const Vec2& worldPoint) const;

 

 

    //把基于当前节点的本地坐标系下的坐标, 转换到世界坐标系中

    //基于Anchor Point. 把世界坐标, 转换到当前节点的本地坐标系中

    Vec2 convertToWorldSpace(const Vec2& nodePoint) const;

    Vec2 convertToWorldSpaceAR(const Vec2& nodePoint) const;

     

     

    //把触点坐标, 转换到当前节点的本地坐标系中

    Vec2 convertTouchToNodeSpace(Touch * touch) const;

    Vec2 convertTouchToNodeSpaceAR(Touch * touch) const;

//

 

2、举例

wKioL1QXGdfRT4CEAABEcihIj24366.jpg        wKioL1QXGdeTLzlIAAA90sXMFdY199.jpg

    > node1坐标为:(20,40), 锚点(0,0)。

    > node2坐标为:(-5,-20),锚点(1,1)。

    > Vec2 point1 = node1->convertToNodeSpace(node2->getPosition());

        结果为:(-25,-60)。(即:相对node1节点坐标位置,的,相对坐标)

        分析  :node2相对node1节点的坐标为:(-5,-20) - (20,40) 。

                也就是说:node2相对node1的坐标位置。

    > Vec2 point2 = node1->convertToWorldSpace(node2->getPosition());

        结果为:(15,20)。(即:相对node1的世界坐标系统下,的,世界坐标)

        分析  :将node1作为参照,转换到世界坐标为:(20,40) + (-5,-20) 。

                也就是说:node2的坐标现在被看做是相对node1的坐标位置,然后转换到世界坐标。

 

3、在屏幕触控中的应用 

    判断触摸点是否触摸到某个精灵图片sp的内部区域。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

//

    bool HelloWorld::onTouchBegan(Touch *touch, Event *unused_event)

    {

        //将触点坐标, 转换为相对节点sp的, 相对坐标

        Vec2 point = sp->convertTouchToNodeSpace(touch);

 

        //构造sp的尺寸矩形

        Size size = sp->getContentSize();

        Rect rect = Rect(0, 0, size.width, size.height);

 

        //判断触点是否触摸到sp内部

        if (rect.containsPoint(point)) {

            CCLog("点中");

            return true;

        }

 

        return false;

    }

//

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值