UI适配问题,指的就是怎么让我们的游戏可以在屏幕分辨率差异巨大的手机上都能有很好的UI体验,这其中总结为两个核心问题:

  • 合适的位置,在屏幕边缘的UI,不至于显示到屏幕外面去。
  • 合适的大小,在屏幕比较小的手机上,不至于一个按钮都感觉很巨大;在大屏手机(平板)上道理类似。

    一、屏幕分辨率

    设备屏幕的分辨率,如iphone系列手机的分辨率:
机型(iphone) 设备分辨率
(px)
宽高比
3GS 320x480 0.667(3 : 2)
4(s) 640x960 0.667(3 : 2)
5(s) 640x1136 0.563(16 : 9)
6(s)/7/8 750x1334 0.562(16 : 9)
6(s)/7/8 plus 1242x2208 0.562(16 : 9)
X 1125x2436 0.462
XR 828×1792 0.462
XS 1125×2436 0.462
XS Max 1242×2688 0.462

andorid设备常见分辨率:

宽高比 分辨率
4 : 3 VGA 640*480 (Video Graphics Array)
QVGA 320*240 (Quarter VGA)
HVGA 480*320 (Half-size VGA)
SVGA 800*600 (Super VGA)
5 : 3 WVGA 800*480 (Wide VGA)
16 : 9 FWVGA 854*480 (Full Wide VGA)
HD 1920*1080 High Definition
QHD 960*540
720p 1280*720 标清
1080p 1920*1080 高清

相关源代码:

  1. class CC_DLL GLView : public Ref
  2. {
  3. public:
  4. //设备屏幕分辨率,像素单位。
  5. virtual Size getFrameSize() const;
  6. virtual void setFrameSize(float width, float height);
  7. }
  8. bool AppDelegate::applicationDidFinishLaunching(){
  9. auto director = Director::getInstance();
  10. auto glview = director->getOpenGLView();
  11. if(!glview) {
  12. glview = GLViewImpl::create("Cpp Tests");
  13. director->setOpenGLView(glview);
  14. }
  15. auto screenSize = glview->getFrameSize(); //获取设备分辨率
  16. }

二、设计分辨率

是内容生产者在制作场景时使用的分辨率蓝本,美术、策划根据设计分辨率设置场景。通常会采用市场目标群体中使用率最高的设备的屏幕分辨率。

  • Android
    • 800 x 480
    • 1280 x 720
  • IOS
    • 960 x 640
    • 1136 x 640

相关源码:

  1. class CC_DLL GLView : public Ref
  2. {
  3. public:
  4. //返回设计分辨率,默认和FrameSize屏幕分辨率一样。
  5. virtual const Size& getDesignResolutionSize() const;
  6. //设置设计分辨率
  7. virtual void setDesignResolutionSize(float width, float height, ResolutionPolicy resolutionPolicy);
  8. }
  9. const Size& Director::getWinSize(void) const {
  10. //_winSizeInPoints = _openGLView->getDesignResolutionSize();
  11. //Director的winsize就是GLView的DesignResolutionSize,也就是设计分辨率
  12. return _winSizeInPoints;
  13. }

(一)屏幕适配方案

按设计分辨率设置的场景显示到屏幕上的过程。
如果设计分辨率和屏幕分辨率相同,那很简单不需要做适配;更多是不相同的情况,cocos引擎提供了多种适配策略,按设计分辨率是否会等比缩放,分为两大类:

  • 等比缩放:
    • NO_BORDER
    • SHOW_ALL
    • FIX_HEIGHT
    • FIX_WIDTH
  • 不等比缩放:会导致设计分辨率场景的拉伸(stretched )或压缩(compressed)。
    • EXACT_FIT
      1. /** There are some Resolution Policy for Adapt to the screen. */
      2. enum class ResolutionPolicy {
      3. EXACT_FIT,
      4. NO_BORDER,
      5. SHOW_ALL,
      6. FIXED_HEIGHT,
      7. FIXED_WIDTH,
      8. };

      1、EXACT_FIT

      官方解释:

      The entire application is visible in the specified area without trying to preserve the original aspect ratio. Distortion can occur, and the application may appear stretched or compressed.

设计分辨率在x、y方向各自拉伸(压缩)到刚好充满屏幕,不会维持设计分辨率的宽高比,即非等比缩放,因此会导致图象的变形。在实践中一般都不采用。
世界坐标原点在屏幕左下角。
点击查看【processon】

2、NO_BORDER

官方解释:

The entire application fills the specified area, without distortion but possibly with some cropping,while maintaining the original aspect ratio of the application.

通过等比缩放,使设计分辨率填充满屏幕,使屏幕不会出现黑边,这可能会导致设计分辨率有超出屏幕的部分(裁剪)。
只有这种情况,世界坐标原点不是在屏幕左下角,而是在设计分辨率的左下角。
点击查看【processon】

3、SHOW_ALL

官方解释:

The entire application is visible in the specified area without distortion while maintaining the original aspect ratio of the application. Borders can appear on two sides of the application.

通过等比缩放,使设计分辨率全部显示在屏幕上,这可能会导致边界(borders)的出现。
世界坐标原点在屏幕左下角。
点击查看【processon】

4、FIX_HEIGHT

官方解释:

The application takes the height of the design resolution size and modifies the width of the internal canvas so that it fits the aspect ratio of the device. No distortion will occur however you must make sure your application works on different aspect ratios.

通过等比缩放,使设计分辨率的高刚好填充满屏幕的高。
世界坐标原点在屏幕左下角。
点击查看【processon】

5、FIX_WIDTH

官方解释:

The application takes the width of the design resolution size and modifies the height of the internal canvas so that it fits the aspect ratio of the device. No distortion will occur however you must make sure your application works on different aspect ratios.

通过等比缩放,使设计分辨率的宽刚好填充满屏幕的宽。
世界坐标原点在屏幕左下角。
点击查看【processon】

(二)visibleSize、winSize

  • DesignResolutionSizewinSize
    • 设计分辨率
  • frameSize(screenSize)
    • 准确的讲,是OpenGL视口(ViewPort)大小,一般情况是设置的和屏幕大小一样,也就是屏幕分辨率,像素为单位。
  • visibleSize
    • 可视区域,区域之外是黑的,从上面我们可以大概理解,它是设计分辨率和屏幕分辨率重叠的部分,即设计分辨率可见的部分。
  • visibleOrigin
    • 这个可视区域的左下角的原点在世界坐标系中的坐标位置。 ```cpp

class CC_DLL Director : public Ref{ const Size &Director::getWinSize( void ) const;

  1. // = winSize * scaleFactor
  2. Size Director::getWinSizeInPixels() const;
  3. virtual Size getFrameSize() const;
  4. Size getVisibleSize() const;
  5. Vec2 getVisibleOrigin() const;

}

class CC_DLL GLView : public Ref{ virtual Size getVisibleSize() const; // 可视区域大小 virtual Vec2 getVisibleOrigin() const; // 可视区域左下角世界坐标 virtual Rect getVisibleRect() const; // 可视矩形区域的Rect }

  1. <a name="1bNBw"></a>
  2. # 四、资源分辨率
  3. 由于设备分辨率差异巨大,高分辨率的资源在低分辨率设备上显示会导致失真和内存过多占用,所以美术会针对不同等级分辨率的设备设计多套资源,当然至少有一个套是针对设计分辨率的资源。
  4. ```cpp
  5. auto director = Director::getInstance();
  6. auto glview = director->getOpenGLView();
  7. FileUtils::getInstance()->setSearchPaths( resPath );
  8. director->setContentScaleFactor( scaleFactor );
  9. glview->setDesignResolutionSize( designSize.width, designSize.height, policy );

coocs引擎提供了相关接口,实践例子如下:

  1. bool AppDelegate::applicationDidFinishLaunching(){
  2. //比如设计了三套资源
  3. //一套资源,针对小屏幕(480x320),小于设计分辨率较多的情况。
  4. //一套资源,针对设计分辨率大小或者差不都的屏幕(960x640)。
  5. //一套资源,针对大屏幕(1334x750),超过设计分辨率较多的情况。
  6. auto resSize_LOW = Size(480, 320); //小屏幕
  7. auto resSize = Size(960, 640); //设计分辨率差不多大小的屏幕
  8. auto resSize_HD = Size(1334, 750); //大屏幕
  9. auto resPath_LOW = "res_LOW" //资源路径
  10. auto resPath = "res"
  11. auto resPath_HD = "res_HD"
  12. auto director = Director::getInstance(); // initialize director
  13. auto fileUtils = FileUtils::getInstance();
  14. auto designSize = Size(960, 640); //设计分辨率
  15. auto screenSize = director->getFrameSize(); //屏幕分辨率
  16. double scaleFactor = 1.0; //缩放因子
  17. std::string searchPath("res"); //资源搜索路径
  18. if( screenSize.height <= resSize_LOW.height ) //小屏幕,采用低清资源
  19. // 设置缩放因子,用来将一种分辨率的资源适配到设计分辨率上,
  20. // 表示:scaleFactor个资源像素占据1个像素设计分辨率。
  21. // 比如一套资源,分辨率是480x320,设计分辨率是960x640,则如果要将这套资源用在这个设计分辨率上
  22. // 那么0.5个像素资源占据1个像素设计分辨率才能在这个分辨率上正常显示这套资源。
  23. scaleFactor = resSize_LOW.height/designSize.height;
  24. searchPath = resSize_LOW;
  25. else if(screenSize.height >= resPath_HD.height){ //大屏幕采用高清资源
  26. scaleFactor = resSize_HD.height/designSize.height;
  27. searchPath = resPath_HD;
  28. }
  29. director->setContentScaleFactor(scaleFactor);
  30. fileUtils->setSearchPaths(searchPath);
  31. }

(三)适配方案设计

由于移动设备分辨率的巨大差异,单一采用上面介绍的任何一种方案都不能比较好的满足大部分的设备。我们应该根据屏幕实际分辨率和需求制定组合方案:

  • 背景图允许被裁剪,不允许出现黑边
    • 采用NO_BORDER,一般就用这个。
  • 背景图不允许被裁剪,允许出现黑边
    • 采用SHOW_ALL