zoukankan      html  css  js  c++  java
  • 关于Cocos2d-x中坐标系的种类和转换

    注意:

    当一个节点有一个子节点的时候,如果移动父节点,子节点也会跟着做相应的移动变化,只要被添加到父节点中,子节点就被绑定了,所以子节点的位置,坐标就会被动地变化。

    当一个节点有一个子节点的时候,如果通过setPosition方法设置子节点的坐标,那么,这时候其实是在以父节点左下角为原点的坐标系中,x轴最长是父节点的宽度,y轴最长是父节点的高度。后面如果有需要可以通过一些坐标的转换的方法转化为世界坐标/UI坐标。

    例如,jewel1是hero的子节点,屏幕分辨率960*640,hero大小200*250

    Point p1, p2,p3;
    auto hero = Sprite::create("s_1.png");
    hero->setPosition(visibleSize.width / 2, visibleSize.height / 2);
    p1=hero->getPosition();
    log("p1=(%f,%f)",p1.x,p1.y);
    addChild(hero);

    auto jewel1 = Sprite::create("jewel1.png");
    jewel1->setAnchorPoint(Vec2(1, 0));
    jewel1->setPosition(hero->getContentSize().width, 0);
    p2 = jewel1->getPosition();
    log("p2=(%f,%f)", p2.x, p2.y);
    p3 = hero->convertToWorldSpace(jewel1->getPosition());
    log("p3=(%f,%f)", p3.x, p3.y);
    hero->addChild(jewel1);

    输出结果

    p1=(480.000000,320.000000)
    p2=(200.000000,0.000000)
    p3=(580.000000,195.000000)

     

    一.UI坐标系

    在进行iOS或者Android界面开发时,它的坐标系规则如下图所示:

    alt

    • 原点坐标(x=0, y=0)位于左上角;
    • X轴从屏幕最左边开始,由左向右渐增;
    • Y轴坐标从屏幕最上方开始,由上向下渐增

    二.Cocos2d-x坐标系

    Cocos2d-x坐标系是这里的重点,也是我们开发时考虑的最多的。由于Cocos2d-x是基于OpenGL和OpenGL ES的。该坐标系的规则如下:

    • 原点坐标(x=0, y=0)位于左下角;
    • X轴从屏幕最左边开始,由左向右渐增;
    • Y轴从屏幕最下方开始,由下向上渐增;

    在Cocos2d-x中的场景,就是使用的该坐标系。

    三.世界坐标系

    世界坐标系也叫绝对坐标系,是游戏开发中建立的概念。它建立了描述其它坐标系所需要的参考标准。我们都可以使用世界坐标系来描述其它坐标系的位置。

    Cocos2d-x中元素是有父子关系的层次结构,通过Node设置位置使用的是相对其父节点的本地坐标系,而非世界坐标系,最后在绘制屏幕的时候,Cocos2d-x会把这些元素的本地节点坐标映射成世界坐标系坐标。世界坐标系和OpenGL坐标系方向一致,原点在屏幕左下角,X轴向右,Y轴向上。

    四.节点坐标系

    节点坐标系也叫相对坐标系,它是与特定节点相关联的坐标系。每个节点都有独立的坐标系,当节点移动或改变方向时,和该节点关联的坐标系(它的子节点)将随之移动或改变方向。比如一个Layer上面有10个精灵,当移动这个Layer的时候,这些精灵也会跟着一起移动的。

    Node节点类中,我们可以对节点进行位置的操作,而这些设置位置使用的就是父节点的节点坐标系。它和OpenGL坐标系方向一致,原点在屏幕左下角,X轴向右,Y轴向上。有的时候,我们需要将节点坐标转换成世界坐标,或者将世界坐标转换成节点坐标。在Node节点类中,就提供了对应的转换函数,下面我们就使用一下这些函数,加深对Cocos2d-x坐标系、世界坐标系和节点坐标系的理解。

     

     

    转换API

    在Cocos2d-x中提供了以下的API用来进行坐标转换。

    /**
    * 将世界坐标转换成节点坐标,忽略锚点的影响;结果是以点为单位。
    */
    Vec2 convertToNodeSpace(const Vec2& worldPoint) const;
    
    /**
    * 将节点坐标转换成世界坐标,忽略锚点的影响;结果是以点为单位。
    */
    Vec2 convertToWorldSpace(const Vec2& nodePoint) const;
    
    /**
    * 将世界坐标转换成节点坐标;结果是以点为单位。
    * 会考虑到锚点的影响
    */
    Vec2 convertToNodeSpaceAR(const Vec2& worldPoint) const;
    
    /**
    * 将节点坐标转换成世界坐标;结果是以点为单位。
    * 会考虑到锚点的影响。
    */
    Vec2 convertToWorldSpaceAR(const Vec2& nodePoint) const;
    
    /**
    * 将Touch对应的点转换成节点坐标,忽略锚点的影响。
    */
    Vec2 convertTouchToNodeSpace(Touch * touch) const;
    
    /**
    * 将Touch对应的点转换成节点坐标,考虑锚点的影响。
    */
    Vec2 convertTouchToNodeSpaceAR(Touch * touch) const;

    好了,世界坐标系转节点坐标系,节点坐标系转世界坐标系,就这么几个函数就能搞定了,剩下的就是实际的应用了。对了,在实际中,一定要考虑到锚点的影响,可能你得到的结果,就是因为锚点的影响,而完全不同的。

     

     

    坐标系变换原理

    上面总结了坐标系之间转换的一些API函数,下面就来看看它们之间到底是如何转换的。看了网上很多人的博客,写的转换原理,写的都不错,就是看的云里雾里的,很多人都配上了坐标图,搞笑的是那些坐标图都是“一副”,也不知道谁抄袭的谁的。

    下面就做一些简单的原理,没有过的图来说明,就是一些简短的文字,按照这些文字说明,你肯定能看的懂的。

     

    1.convertToNodeSpace
    Vec2 newPosition = node1->convertToNodeSpace(node2->getPosition());
    将node2的位置坐标转换成相对于node1左下角顶点的坐标。转换方法:node1和node2位置不变,将坐标轴原点设置为node1的左下角顶点,重新计算node2->getPosition()这个点的坐标即为newPosition。
    当调用以下代码时,返回的是相对于其父节点的节点坐标,当然了,以下代码的实际用处并不大。

    Vec2 newPosition = node1->convertToNodeSpace(node1->getPosition());

    2.convertToNodeSpaceAR
    Vec2 newPosition=node1->convertToNodeSpaceAR(node2->getPosition());
    将node2的位置坐标转换成相对于node1锚点的坐标。转换方法:node1和node2位置不变,将坐标轴原点设置为node1的锚点,重新计算node2->getPosition()这个点的坐标即为newPosition。

    3.convertToWorldSpace
    Vec2 newPosition=node1->convertToWorldSpace(node2->getPosition());
    将node2的位置坐标转换成世界坐标。转换方法:node1的位置不变,世界坐标的坐标轴也不变,以node1的左下角顶点再建立一个坐标系(其实就是本地坐标),将node2->getPosition()这个点设置到新建的坐标系中,以原来的世界坐标系为参考,重新计算node2->getPosition()这个点的坐标即为newPosition。

    4.convertToWorldSpaceAR
    Vec2 newPosition=node1->convertToWorldSpaceAR(node2->getPosition());
    将node2的位置坐标转换成世界坐标。转换方法:node1的位置不变,世界坐标的坐标轴也不变,以node1的锚点再建立一个坐标系,将node2->getPosition()这个点设置到新建的坐标系中,以原来的世界坐标系为参考,重新计算node2->getPosition()这个点的坐标即为newPosition。

    另一个例子

    首先我们添加两个测试精灵(宽:27,高:40)到场景里面:

    Sprite *sprite1 = Sprite::create("player.png");
    sprite1->setPosition(Vec2(20, 40));
    sprite1->setAnchorPoint(Vec2(0, 0));
    this->addChild(sprite1);

    Sprite *sprite2 = Sprite::create("player.png");
    sprite2->setPosition(Vec2(-15, -30));
    sprite2->setAnchorPoint(Vec2(1, 1));
    this->addChild(sprite2);

    然后调试,在场景中大概是下图这样显示(以左下角为坐标原点,从左到右为x方向,从下到上为y方向,废话了:)):

    在cocos2d-x中,每个精灵都有一个锚点,以后对精灵的操作(比如旋转)都会围绕锚点进行,我们暂且可以看作是精灵的中心位置,一般来说有每个方向有三种可能的值:0,0.5,1。上图中红色圆点即为各自的锚点,sprite1 锚点为 (0,0) 左下角,sprite2锚点为(1,1)在右上角。

    现在我们来看看坐标系转换,同样地,我们先写点测试代码:

    Point p1 = sprite2->convertToNodeSpace(sprite1->getPosition());
    Point p2 = sprite2->convertToWorldSpace(sprite1->getPosition());
    Point p3 = sprite2->convertToNodeSpaceAR(sprite1->getPosition());
    Point p4 = sprite2->convertToWorldSpaceAR(sprite1->getPosition());

    接着,再打印出各点的x,y值:
     


    Log("p1:%f,%f", p1.x, p1.y);
    Log("p2:%f,%f", p2.x, p2.y);
    Log("p3:%f,%f", p3.x, p3.y);
    Log("p4:%f,%f", p4.x, p4.y);

    由于cocos2d-x的坐标系(本地坐标系)是以左下角为坐标原点的,所以 sprite1和sprite2的坐标原点在上图的位置分别是(20,40)、(-42,-70),那么很明显的:

    p1就是sprite1锚点相对于sprite2原点来说在sprite2坐标系中的位置,经过对比上图,我们可以得到(20-(-42),40-(-70))即(62,110)

    p2就是sprite1锚点相对于sprite2原点来说在上图坐标系中的位置,这样我们可以计算出sprite1在sprite2坐标系中的位置:(20+(-42),40+(-70)),即(-22,-30)

    p3就是sprite1锚点相对于sprite2锚点来说在sprite2坐标系中的位置,也就是(20-(-15),40-(-30)),即(35,70)

    p4就是sprite1锚点相对于sprite2锚点来说在上图坐标系中的位置,也就是(20+(-15),40+(-30)),即(5,10)

    现在我们可以知道,计算方法都是用sprite1的坐标去加减sprite2的坐标,针对本地坐标系就用减法,针对世界坐标系就用加法。

  • 相关阅读:
    CodeForces Gym 100935G Board Game DFS
    CodeForces 493D Vasya and Chess 简单博弈
    CodeForces Gym 100935D Enormous Carpet 快速幂取模
    CodeForces Gym 100935E Pairs
    CodeForces Gym 100935C OCR (水
    CodeForces Gym 100935B Weird Cryptography
    HDU-敌兵布阵
    HDU-Minimum Inversion Number(最小逆序数)
    七月馒头
    非常可乐
  • 原文地址:https://www.cnblogs.com/HangZhe/p/5760350.html
Copyright © 2011-2022 走看看