游戏人生,混乱的坐标系和锚点

有关坐标和适配的问题往往让人发指,最近项目对worldtoNode,nodetoworld搞的我头都大了好多圈,加上ancher和适配,笔者都快疯了,这里准备做个系类,把这里的东西屡一下,整理个文档。

先从坐标系和锚点开始。这里想提醒读者,这部分看似简单,其实挺混乱的,而且相当重要。

coco2dx中涉及四种坐标

GL坐标系:

Cocos2D以OpenglES为图形库,所以它使用OpenglES坐标系。GL坐标系原点在屏幕左下角,x轴向右,y轴向上。
屏幕坐标:

系苹果的Quarze2D使用的是不同的坐标系统,原点在屏幕左上角,x轴向右,y轴向下。ios的屏幕触摸事件CCTouch传入的位置信息使用的是该坐标系。因此在cocos2d中对触摸事件做出响应前需要首先把触摸点转化到GL坐标系。可以使用CCDirector的convertToGL来完成这一转化。

世界坐标系:

也叫做绝对坐标系。世界坐标系和GL坐标系一致,原点在屏幕左下角。

本地坐标系:

本地坐标系也叫做物体坐标系,是和特定物体相关联的坐标系(父节点)

其实GL坐标和世界坐标是一样的,屏幕坐标对于使用cocos2dx的开发者而言大部分时间可以无视,那么其实需要大家理解的就是——世界坐标,本地坐标。


本地坐标是相对于父节点而言的坐标,例如在一个CCLayer中添加一个CCSprite,此时setPosition设置的就是相对CCLaye的本地坐标。在渲染的过程中会将本地坐标变成世界坐标,所以我们很难发现其实我们设置的是相对坐标。那么相对坐标究竟是什么坐标?世界坐标是以屏幕坐下角为(0,0),x轴向右,y轴向上的坐标,本地坐标则是以其父节点坐标为(0,0),x轴向右,y轴向上的坐标。带入个场景:


一个Layer里添加一个sprite,设置layer坐标为(100,100),sprite坐标(0,0)

bool HelloWorld::init()
{
    //
    // 1. super init first
    if ( !CCLayer::init() )
    {
        return false;
    }
    
<span style="white-space:pre">	</span>//this->setPosition(ccp(100,100));
    // add "HelloWorld" splash screen"
    CCSprite* pSprite = CCSprite::create("HelloWorld.png");
	pSprite->setScale(0.5f);
	pSprite->setPosition(ccp(0,0)); 
	this->addChild(pSprite, 1);
    return true;
}


然后放开注释,this->setPosition(ccp(100,100))

相信大家有些理解相对坐标了,在不设置layer坐标的情况下layer坐标(0,0),sprite的setposition(0,0)与世界坐标一样,都是坐下角为原点。但是layer坐标变为(100,100)之后,sprite坐标就变成了父节点layer的坐标(100,100)为原点的相对坐标位置。

cocos2dx在这里提供了2个方法,将世界坐标与本地坐标相对转化,只不过有点坑的是你需要知道世界坐标与父节点的坐标。

CCPoint convertToNodeSpace(const CCPoint& worldPoint);
CCPoint convertToWorldSpace(const CCPoint& nodePoint);
cocos的某系操作基于本地坐标,例如moveTo,有些是基于世界坐标,例如touch。当我们需要touch时间检测碰撞或者触摸,然后移动sprite的时候就需要用到以上函数了。

	CCRect pRect = pSprite->boundingBox();
	pRect.origin = pSprite->convertToWorldSpace(ccp(0,0));
	if(pRect.containsPoint(ccp(x,y)))
	{
		CCLOG("监测到点击精灵事件");
		CCActionInterval* anim = CCMoveTo::create(1.0f,ccp(x,y));
		pSprite->runAction(anim);
	}

如果运行以上代码,如果sprite的父节点坐标为(0,0),那么精灵会点击的时候移动到点击位置,如果不是(0,0),那么恭喜你,精灵会移动到想都想不到的地方。怎么解决?我的方法是使用moveBy,计算点击位置与精灵位置的矢量差,通过moveBy移动。


接下来咱们说说锚点:

这是一个难以理解的东西,什么是锚点?这个不好说,还是看看下边的例子吧。

首先ignoreAnchorPointForPosition这个东西,很神奇,先看看设置为false的情况。

bool HelloWorld::init()
{
    //
    // 1. super init first
    if ( !CCLayer::init() )
    {
        return false;
    }

    // add "HelloWorld" splash screen"
    CCSprite* pSprite = CCSprite::create("HelloWorld.png");
	pSprite->setScale(0.5f);
	pSprite->setPosition(ccp(0,0));
	pSprite->ignoreAnchorPointForPosition(false);
	pSprite->setAnchorPoint(ccp(0,0));
	CCPoint point = this->getAnchorPoint();
	this->addChild(pSprite, 1);
	//initScroll();
    return true;
}


pSprite->setAnchorPoint(ccp(0.5,0.5));




在ignoreAnchorPointForPosition(false);的情况下,设置锚点可以这样理解,设置位置就是设置锚点的位置,当锚点为(0,0)的时候,图片的左下角为锚点,图片左下角与设置位置重合。当锚点为(0.5,0.5)时候,图片的中点为锚点,设置位置(0,0)就是图片中点位置为(0,0)。


在说说ignoreAnchorPointForPosition(true)的情况,设置锚点为(0.5,0.5),运行后如下



这是什么情况? 我们先命名一个变量:父子点,父节点提供给子节点的坐标系原点。经过测试,设置为ture之后,设置子节点锚点时父子点一同被设置,父节点的父子点和sprite的锚点都被设置到了中点上,所以当setPosition为(0.5,0.5),sprite位置(0,0)的时候,就是父节点的父子点与sprite的锚点重合,得到如上情况。

总结一下:所谓的设置位置,用的都是本地坐标,设置的是相对位置。设置位置就是设置父子点与子锚点之间的相对位置关系。锚点从0-1,及从左到右,从下到上。默认情况下父子点位置为父节点左下角。默认情况下ignoreAnchorPointForPosition为FALSE,锚点为(0.5,0.5)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值