cocos 屏幕适配源码分析及VisibleSize,VisibleOrigin

cocos 屏幕适配源码分析及VisibleSize,VisibleOrigin,第1张

概述其实这个话题应该是从第一天接触cocos就会碰到的问题,我始终没能完全理解那些文章的意思,只是大概知道是怎么回事,仅此而已,智商捉急呀!!今天也是花了很长的时间去理解,现在总算有点眉目了,就把它记录下来,以后可以常回顾一下。 不废话了,进入正题。所谓的屏幕适配到底需要我们完成什么样的功能呢?这才是我们研究这个问题需要解决的东西,看了很多文章写屏幕适配,大神们总是在侃侃而谈,殊不知我们这些学渣理解能

其实这个话题应该是从第一天接触cocos就会碰到的问题,我始终没能完全理解那些文章的意思,只是大概知道是怎么回事,仅此而已,智商捉急呀!!今天也是花了很长的时间去理解,现在总算有点眉目了,就把它记录下来,以后可以常回顾一下。

不废话了,进入正题。所谓的屏幕适配到底需要我们完成什么样的功能呢?这才是我们研究这个问题需要解决的东西,看了很多文章写屏幕适配,大神们总是在侃侃而谈,殊不知我们这些学渣理解能力确实有问题,所以经常一篇文章读下来,确实能理解里面讲的是什么,但是为什么要解决这个问题,为什么要这样解决,就呵呵啦。。我的理解是:不管在什么手机上都可以保证UI完全显示出来。接下来就来探讨一下这个问题。

建议提前参考Cocos2d-x屏幕适配之Sprite绘制原理这篇文章。

前言:设计分辨率是截面区域,视口是图像映射到的矩形区域,屏幕分辨率是真正显示的区域大小。

case Projection::_3D:        {            @R_419_5987@ zeye = this->getZEye();            Mat4 matrixPerspective,matrixLookup;            loadIDentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);            #if CC_TARGET_PLATFORM == CC_PLATFORM_WP8            //if needed,we need to add a rotation for Landscape orIEntations on windows Phone 8 since it is always in Portrait Mode            GLVIEw* vIEw = getopenGLVIEw();            if(getopenGLVIEw() != nullptr)            {                multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION,getopenGLVIEw()->getorIEntationMatrix());            }#endif            // issue #1334            Mat4::createPerspective(60,(GL@R_419_5987@)size.wIDth/size.height,10,zeye+size.height/2,&matrixPerspective);            multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION,matrixPerspective);            Vec3 eye(size.wIDth/2,size.height/2,zeye),center(size.wIDth/2,0.0f),up(0.0f,1.0f,0.0f);            Mat4::createLookAt(eye,center,up,&matrixLookup);            multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION,matrixLookup);                        loadIDentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);            break;        }

可以看出投影之后的截面区域就是:设计分辨率(size)。这个区域经过视口变换映射到视口区域:
voID GLVIEwImpl::setVIEwPortInPoints(@R_419_5987@ x,@R_419_5987@ y,@R_419_5987@ w,@R_419_5987@ h){    glVIEwport((Glint)(x * _scaleX * _retinaFactor * _frameZoomFactor + _vIEwPortRect.origin.x * _retinaFactor * _frameZoomFactor),(Glint)(y * _scaleY * _retinaFactor  * _frameZoomFactor + _vIEwPortRect.origin.y * _retinaFactor * _frameZoomFactor),(GLsizei)(w * _scaleX * _retinaFactor * _frameZoomFactor),(GLsizei)(h * _scaleY * _retinaFactor * _frameZoomFactor));}

如果视口区域比屏幕小,那么整个设计分辨率下的东西便能完全显示到屏幕上;如果比屏幕大,那么设计分辨率下的一部分才能完全显示在屏幕上,计算出这个区域就可以了。

这就是cocos保证全屏显示的两种方法。下面的几种策略模式就采用了这两种方式。


cocos2d 引入了 屏幕适配策略 一共一有6种策略:EXACT_FIT,NO_border,SHOW_ALL,FIXED_HEIGHT,FIXED_WIDTH,UNKNowN。其实最后一种并不算什么策略,而是我们未指定其它策略时默认的情况。下面我们就分别来讨论这些策略:

cocos采用的

1:UNKNowN模式

拿这个来引出屏幕适配的问题吧,假如我们游戏运行在屏幕分辨率为480X320的手机上,我们要设置一个按钮的位置在手机的右上方,这个好办,button.y=320-button.height/2,button.x = 480-button.wIDth/2;就是这么简单,那么问题来了,现在假如我又有一部480X280的手机,那么这个按钮就跑到外面去了,所以屏幕适配是个迫切需要解决的问题。

2:EXACT_FIT模式 采用的是第一种方式

从这里开始我们引入designSize,设计分辨率,这是个非常重要的概念。这个是和手机分辨率没有任何关系的,纯粹的是程序员定义的,可以理解为在此分辨率下设计的游戏。在该分辨率下的坐标经过各种投影变换映射到视口中。

EXACT_FIT是如何去根据设计分辨率来使得全屏显示呢?

_scaleX = (@R_419_5987@)_screenSize.wIDth / _designResolutionSize.wIDth; _scaleY = (@R_419_5987@)_screenSize.height / _designResolutionSize.height;
if (_resolutionPolicy == ResolutionPolicy::NO_border)    {      _scaleX = _scaleY = MAX(_scaleX,_scaleY);    }       else if (_resolutionPolicy == ResolutionPolicy::SHOW_ALL)    {      _scaleX = _scaleY = MIN(_scaleX,_scaleY);    }       else if ( _resolutionPolicy == ResolutionPolicy::FIXED_HEIGHT) {      _scaleX = _scaleY;      _designResolutionSize.wIDth = ceilf(_screenSize.wIDth/_scaleX);    }       else if ( _resolutionPolicy == ResolutionPolicy::FIXED_WIDTH) {      _scaleY = _scaleX;      _designResolutionSize.height = ceilf(_screenSize.height/_scaleY);    }


voID GLVIEwImpl::setVIEwPortInPoints(@R_419_5987@ x,(GLsizei)(h * _scaleY * _retinaFactor * _frameZoomFactor));}

保持设计分辨率不变,视口就是屏幕分辨率,所以显示效果就是将设计分辨率拉伸到屏幕分辨率,整个投影过去,很明显资源的宽高比不能得到保持。所以此种模式理论上是OK的,但是并不建议采用这种方式,没有用户会接受这样的体验感。显示区域为:(0,0)--->(designSize.wIDth,designSize.height)。

3:FIXED_HEIGHT,FIXED_WIDTH模式采用的是第一种方式

这两种放在一起讲,原因是它们很类似,会改变程序员最初设置的设计分辨率。还是分析下它的实现原理吧。

新的设计分辨率A和屏幕分辨率B的宽高比是一样的,具体A和B之间的缩放比例取决于是FIXED_HEIGHT还是FIXED_WIDTH。

此时的视口和B是一样的,经过视口变换后,显示出来的效果就相当于缩放了整个显示区域。所以在A分辨率下能正常显示的肯定能在B分辨率下显示。显示区域是:(0,0)--->(designSize.wIDth,designSize.height)。


4:SHOW_ALL模式采用的是第一种方式

保持设计分辨率不变,只是改变视口的大小。

 _scaleX = _scaleY = MIN(_scaleX,_scaleY);

voID GLVIEwImpl::setVIEwPortInPoints(@R_419_5987@ x,(GLsizei)(h * _scaleY * _retinaFactor * _frameZoomFactor));}

所以视口和设计分别率的宽高比是一样的。但是肯定比屏幕分辨率小,因为_scale取得是较小的那个比值,所以此模式下会有黑边存在,除非你有个很大的背景在,拿也无可厚非。此时在设计分辨率下能正常显示的肯定能在屏幕上显示出来。显示区域是:(0,0)--->(desingSize,wIDth,desingSize.height)。

5:NO_border模式采用的是第二种方式

保持设计分辨率不变,改变视口的大小。

 _scaleX = _scaleY = MAX(_scaleX,_scaleY);
voID GLVIEwImpl::setVIEwPortInPoints(@R_419_5987@ x,(GLsizei)(h * _scaleY * _retinaFactor * _frameZoomFactor));}

视口和设计分辨率的宽高比一致,但是会比屏幕分辨率大,此模式下有些东西会看不到,在此设计分辨率下的能正常显示的UI并不能保证在屏幕上完全显示出来,会裁剪掉一部分,显示区域不再是:(0,0)--->(designsize.wIDth,desingSize.height),而是:(origin.x,origin,y)----->(origin.x+visibleSize.wIDth,origin.y+visibleSize.heigth),很容易发现这就是我们经常用来设置UI坐标的东西。下面看看它们是怎么来的。

Size GLVIEwProtocol::getVisibleSize() const{    if (_resolutionPolicy == ResolutionPolicy::NO_border)    {        return Size(_screenSize.wIDth/_scaleX,_screenSize.height/_scaleY);    }    else     {        return _designResolutionSize;    }}Vec2 GLVIEwProtocol::getVisibleOrigin() const{    if (_resolutionPolicy == ResolutionPolicy::NO_border)    {        return Vec2((_designResolutionSize.wIDth - _screenSize.wIDth/_scaleX)/2,(_designResolutionSize.height - _screenSize.height/_scaleY)/2);    }    else     {        return Vec2::ZERO;    }}

仔细想想就会看出来的。这个区域和屏幕分辨率的宽高比是一样的,但是比设计分辨率小,更通俗点讲就是:在设计分辨率下的最大区域,该区域有的特征是:和屏幕分辨率的宽高比一致。(有点啰嗦)

不仅仅是这个模式,其它模式也适合,其它模式的visibleOrigin=(0,0),visibleSize=_desiginResolutionSize,其它模式在这个区域中的UI肯定能在屏幕分辨率下显示。

这就是为什么不管我哦们的策略模式是如何的,都可以用这个两个参数去设置UI的坐标来保证UI可以在显示区域中。


表达能力有限,只能讲成这样了。

总结

以上是内存溢出为你收集整理的cocos 屏幕适配源码分析及VisibleSize,VisibleOrigin全部内容,希望文章能够帮你解决cocos 屏幕适配源码分析及VisibleSize,VisibleOrigin所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1069094.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-26
下一篇2022-05-26

发表评论

登录后才能评论

评论列表(0条)

    保存