lunes, 6 de abril de 2015

Multi-resolution support for Android and iOS with Cocos2d-x v3

Hi!

In this post I wrote some time ago, I explained how you could target different resolutions for your iOS game with Cocos2d-x v3. That post didn't include the new resolutions for iPhone 6 and iPhone 6 Plus, and it didn't discuss how to approach the multi-resolution problem for Android devices.

First of all, this is the updated code I use for iOS devices. 

   auto screenSize = glview->getFrameSize();  
   auto fileUtils = FileUtils::getInstance();  
   std::vector<std::string> searchPaths;  
 #if CC_TARGET_PLATFORM == CC_PLATFORM_IOS  
   //Iphone 6 plus  
   if ( screenSize.width == 2208 || screenSize.height == 2208 )  
   {  
     ConfigManager::GetInstance() -> SetDeviceType( iPhone6Plus );  
     glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER );  
     searchPaths.push_back("iphone6plus");  
     searchPaths.push_back("ipadhd");  
     searchPaths.push_back("iphone6");  
     searchPaths.push_back("ipadsd");  
     searchPaths.push_back("iphone5");  
     searchPaths.push_back("iphonehd");  
     searchPaths.push_back("iphonesd");  
   }  
   //Ipad HD  
   else if ( screenSize.width == 2048 || screenSize.height == 2048 )  
   {  
     ConfigManager::GetInstance() -> SetDeviceType( iPadRetina );  
     glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER);  
     searchPaths.push_back("ipadhd");  
     searchPaths.push_back("iphone6");  
     searchPaths.push_back("ipadsd");  
     searchPaths.push_back("iphone5");  
     searchPaths.push_back("iphonehd");  
     searchPaths.push_back("iphonesd");  
   }  
   //Iphone 6  
   else if ( screenSize.width == 1334 || screenSize.height == 1334 )  
   {  
     ConfigManager::GetInstance() -> SetDeviceType( iPhone6 );  
     glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER);  
     searchPaths.push_back("iphone6");  
     searchPaths.push_back("ipadsd");  
     searchPaths.push_back("iphone5");  
     searchPaths.push_back("iphonehd");  
     searchPaths.push_back("iphonesd");  
   }  
   else if (screenSize.width == 1024 || screenSize.height == 1024)  
   {  
     ConfigManager::GetInstance() -> SetDeviceType( iPad );  
     glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER );  
     searchPaths.push_back("ipadsd");  
     searchPaths.push_back("iphone5");  
     searchPaths.push_back("iphonehd");  
     searchPaths.push_back("iphonesd");  
   }  
   else if (screenSize.width == 1136 || screenSize.height == 1136)  
   {  
     ConfigManager::GetInstance() -> SetDeviceType( iPhone5 );  
     glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER );  
     searchPaths.push_back("iphone5");  
     searchPaths.push_back("iphonehd");  
     searchPaths.push_back("iphonesd");  
   }  
   else if (screenSize.width == 960 || screenSize.height == 960)  
   {  
     ConfigManager::GetInstance() -> SetDeviceType( iPhoneRetina );  
     glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER );  
     searchPaths.push_back("iphonehd");  
     searchPaths.push_back("iphonesd");  
   }  
   else  
   {  
     ConfigManager::GetInstance() -> SetDeviceType( iPhone );  
     searchPaths.push_back("iphonesd");  
     glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER );  
   }  

As you can see, I only added the new resolutions for iPhone 6 and iPhone 6 Plus.

As for Android, I follow a strategy that I'll explain in short. This strategy has worked for me, but it's important that you understand the facts that I considered for following it:
  1. My resources are designed to fit the iOS devices resolutions. 
  2. My game is only played in portrait mode, that is, in vertical orientation.
  3. I use True Type Fonts, and I use different font sizes for each iOS device. If I want to reuse the same font sizes for Android devices (which I certainly do), I need to know which iOS device resolution is the most similar to the Android device resolution, and use that corresponding font size. 
With these facts in mind, I follow these coarse-grained steps:
  1. The design resolution size is the actual resolution size of the Android device. 
  2. I set a content scale factor taking iOS screens resolutions as references (because my resources are designed to fit these resolutions). Given that my game will only be played in portrait mode, the content factor is set in terms of the height dimension.
  3. For determining the font size, I take the ratio between the actual screen width and the screen width of an iOS device. If this ration is above 1.5f, I move to the font size of the next iOS device with higher resolution.
  4. Backgrounds images are scaled to fit the full screen (depending on the device, they can be a bit stretched or compressed).
Here's the code:

 #elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID  
   //Iphone 6 plus  
   if (screenSize.width >= 2208 || screenSize.height >= 2208)  
   {  
           director -> setContentScaleFactor( 2208.0f / screenSize.height );  
           ConfigManager::GetInstance() -> SetDeviceType( iPhone6Plus );  
           glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER );  
           searchPaths.push_back("iphone6plus");  
           searchPaths.push_back("ipadhd");  
           searchPaths.push_back("iphone6");  
           searchPaths.push_back("ipadsd");  
           searchPaths.push_back("iphone5");  
           searchPaths.push_back("iphonehd");  
           searchPaths.push_back("iphonesd");  
      }  
      //Ipad HD  
      else if ( screenSize.width >= 2048 || screenSize.height >= 2048 )  
      {  
           director -> setContentScaleFactor( 2048.0f / screenSize.height );  
           ConfigManager::GetInstance() -> SetDeviceType( iPadRetina );  
           glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER);  
           searchPaths.push_back("ipadhd");  
           searchPaths.push_back("iphone6");  
           searchPaths.push_back("ipadsd");  
           searchPaths.push_back("iphone5");  
           searchPaths.push_back("iphonehd");  
           searchPaths.push_back("iphonesd");  
      }  
      //Iphone 6  
      else if ( screenSize.width >= 1334 || screenSize.height >= 1334 )  
      {  
        director -> setContentScaleFactor( 1334.0f / screenSize.height );  
        if ( screenSize.width / 750.0 >= 1.5f )  
        {  
             ConfigManager::GetInstance() -> SetDeviceType( iPhone6Plus ); //bigger font  
        }  
        else  
        {  
             ConfigManager::GetInstance() -> SetDeviceType( iPhone6 );  
        }  
           glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER);  
           searchPaths.push_back("iphone6");  
           searchPaths.push_back("ipadsd");  
           searchPaths.push_back("iphone5");  
           searchPaths.push_back("iphonehd");  
           searchPaths.push_back("iphonesd");  
      }  
      else if (screenSize.width >= 1024 || screenSize.height >= 1024)  
      {  
        director -> setContentScaleFactor( 1024.0f / screenSize.height );  
        if ( screenSize.width / 768.0 >= 1.5f )  
        {  
                  ConfigManager::GetInstance() -> SetDeviceType( iPhone6Plus ); //bigger font  
        }  
        else  
        {  
             ConfigManager::GetInstance() -> SetDeviceType( iPad );  
             }  
           glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER );  
           searchPaths.push_back("ipadsd");  
           searchPaths.push_back("iphone5");  
           searchPaths.push_back("iphonehd");  
           searchPaths.push_back("iphonesd");  
      }  
      else if (screenSize.width >= 1136 || screenSize.height >= 1136)  
      {  
        director -> setContentScaleFactor( 1136.0f / screenSize.height );  
        if ( screenSize.width / 640.0 >= 1.5f )  
        {  
                ConfigManager::GetInstance() -> SetDeviceType( iPhone6 ); //bigger font  
        }  
        else  
        {  
                ConfigManager::GetInstance() -> SetDeviceType( iPhone5 );  
        }  
           glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER );  
           searchPaths.push_back("iphone5");  
           searchPaths.push_back("iphonehd");  
           searchPaths.push_back("iphonesd");  
      }  
      else if (screenSize.width >= 960 || screenSize.height >= 960)  
      {  
        director -> setContentScaleFactor( 960.0f / screenSize.height );  
        if ( screenSize.width / 640.0 >= 1.5f )  
        {  
             ConfigManager::GetInstance() -> SetDeviceType( iPhone6 ); //bigger font  
        }  
        else  
        {  
             ConfigManager::GetInstance() -> SetDeviceType( iPhoneRetina );  
        }  
           glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER );  
           searchPaths.push_back("iphonehd");  
           searchPaths.push_back("iphonesd");  
      }  
      else  
      {  
        director -> setContentScaleFactor( 480.0f / screenSize.height );  
        if ( screenSize.width / 320.0 >= 1.5f )  
        {  
             ConfigManager::GetInstance() -> SetDeviceType( iPhoneRetina ); //bigger font  
        }  
        else  
        {  
             ConfigManager::GetInstance() -> SetDeviceType( iPhone );  
        }  
           searchPaths.push_back("iphonesd");  
           glview -> setDesignResolutionSize( screenSize.width, screenSize.height, ResolutionPolicy::NO_BORDER );  
      }  
 #endif  
   fileUtils->setSearchPaths(searchPaths);  

Finally, as explained in bullet 4, each time I have to show a background image, I scale it to fit the screen, as follows:

   mBackground = Sprite::create("menuBackground.png");  
   mBackground -> setPosition(Point(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2));  
 #if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID  
   mBackground -> setScale( visibleSize.width / mBackground -> getContentSize().width,  
                            visibleSize.height / mBackground -> getContentSize().height );  
 #endif  
   this -> addChild(mBackground);  

Hope you find it useful. The complete guides to understand multi-resolution design is here and here.

See you!

1 comentario:

  1. Hi thanks for the multi resolution code, it works great.

    But i get an error on :

    ConfigManager::GetInstance()->SetDeviceType(iPhone6Plus);

    Use of undeclared identifier configmanager
    Use of undeclared identifier iphone6plus

    Can you tell me what is the use of config manager and how to assign font size to iphone6plus, and how to declare it in .h file.

    Thank you..
    I


    ResponderEliminar