一开始我就忽略了屏幕适配的问题,现在才发现它是多么的重要。通过实践才领悟了其基础概念,而屏幕适配的策略是建立在其上的,有很多,但我还没有认真研究。这里仅把自己对屏幕适配基础知识进行一个梳理。
关于屏幕适配,有一个基础单位:像素。像素构成了分辨率,不应该把分辨率理解为大小。因此这里不说大小,只说分辨率;不说长宽,只说横纵。
1.FrameSize
这个最好理解,就是设备的分辨率,不同的手机有不同的分辨率。事实上,在PC上面开发也有一个设备分辨率,那就是在main.cpp里面设置的窗口分辨率,这个窗口应该理解为设备。因此不必在手机上模拟屏幕适配策略,在PC模拟上就足够了。通过:
CCEGLView::sharedOpenGLView()->getFrameSize();
就可以得到设备的分辨率,它是屏幕适配的基础。注意,设备分辨率一定是动态变换的,根据不同设备能获得不同的值。
2.winSize
很多教程中把它说成是设计分辨率,也许很恰当,但是我感觉不太好理解。我把它叫做游戏分辨率。它就像是一个画布,必须附着在画板上面,这个画板就是设备屏幕。如果不手动设置的话,其默认值就和程序入口时设置的设备分辨率一样。所以,在PC上开发,默认情况下游戏的分辨率和窗口分辨率是一定保持一致的,但由于不同平台程序入口不一致(不是引擎入口),放到手机上就会出现不适配的情况了。游戏分辨率和设备分辨率是不同的概念,是两码事。
我们需要手动设置winSize,手动设置winSize,就是所谓的屏幕适配。在后文详述。
3.visibleSize
我还是觉得其它教程对它的描述模糊不清。我把它叫做可见游戏分辨率。什么叫可见游戏分辨率?就像一张大画布,大过了所依附的画板,会多出去一些布料,无论如何,这张画布都是游戏分辨率。但是只有处在画板内部的那部分画布,才能算作可见游戏分辨率(只是个比方,其实出现这种情况,visibleSize还是要大于frameSize的)。visibleSize就是显示于FrameSize里面的winSize。关于这个概念点,我的描述还是不很精当。不过只要理解了winSize就行,visibleSize就是winSize的子集。
接下来就可以来分析引擎提供的屏幕适配方案了。
有意思的是,引擎把设置游戏分辨率(winSize)和适配参数放在了一个接口里面:pEGLView->setDesignResolutionSize (float width, float height, ResolutionPolicy resolutionPolicy)
适配参数有5个可用值,ShowAll, NoBorder, ExactFit并没有改变游戏分辨率,只是通过一个比例获得了一个新的分辨率,我把它叫做实际游戏分辨率,这才是呈现给玩家的真实游戏分辨率。虽然它原则上必须跟设备分辨率一致,但还是两码事。剩下的两个参数是FixedHeight和FixedWidth,它们用来修改游戏分辨率,也就是改动了winSize,保证了winSize的横纵比例与FrameSize的横纵比例一致。我做了张图表,表示其效果。
横(像素) | 纵(像素) | 效果 | ||
设备分辨率(frameSize) | 640 | 960 | ||
游戏分辨率(winSize) | 720 | 1200 | ||
ratio(设备/游戏) | 0.888888889 | 0.8 | ||
实际分辨率(winSize) | ShowAll | 576 | 960 | 根据小ratio计算实际分辨率,左右出现黑边(图1) |
NoBorder | 640 | 1067 | 根据大ratio计算实际分辨率,上下超出屏幕(图2) | |
ExactFit | 640 | 960 | 出现拉伸 | |
FixedHeight | 640 | 960 | 根据frameSize的横纵比,改变winSize宽为800 | |
FixedWidth | 640 | 960 | 根据frameSize的横纵比,改变winSize高为1080 |
再举两个图例:
ShowAll:
NoBorder:
红色框框表示的范围就是实际分辨率,即真实的游戏分辨率。可以看到在NoBorder策略中,实际分辨率的纵轴达到了1067像素,大于设备分辨率的纵轴的960像素,因此超出去了一部分。同时visibleSize也小于winSize,它等于960除以大的ratio,等于1080。虽然我们不好观测winSize以及visibleSize,但是很明确地知道它们实实在在存在着,实际分辨率就是winSize的缩影。
至此,才大略整理了引擎的屏幕适配基础。但设备屏幕许许多多,适配方法肯定是很多的。如今实践不足,只能留待日后总结了!
最后再记录一条在安卓开发环境中修改横竖屏的方法:
在AndroidManifest.xml文件中,找到android:screenOrientation,"landscape"表示横屏显示,"portrait"表示竖屏显示。