Support multiple aspect ratios

Hi,
I am working on a game, I would like to support different aspect ratios. Basic aspect ratio I chose is 3:2, but I would like to support 16:9, 4:3 etc too. My idea is to have some active area, which aspect ratio is 3:2. If the device has different aspect ratio than 3:2 I would like to show some image as a background outside active area. This image shows my idea: http://v-play.net/doc/images/squaby-different-devices-extended-background.png . So I do something like this:
set design resolution to 480x320 which is 3:2

glview->setDesignResolutionSize(480.0, 320.0, ResolutionPolicy::SHOW_ALL);

set search path

auto fileUtils = FileUtils::getInstance();
std::vector<std::string> resSearchPaths;
resSearchPaths.push_back("md");
fileUtils->setSearchPaths(resSearchPaths);

set content scale factor

Director::getInstance()->setContentScaleFactor(960.0/480.0);

As a background I use this image 1140x720, inner rectangle has 960x640, outer rectangle is for filling inactive background (if the device has aspect ratio 3:2, outer rectangle should not be visible):

When I run my app on iPhone 4-inch, which has different aspect ratio than 3:2 I get something like this

My question is: is there any way to display outer rectangle from my background image (or any other image) instead of black borders on the left and right side?

The obvious answer is to change resolution policy to ResolutionPolicy::NO_BORDERS, but as far as I understand I will have some part of my active area hidden/outside the device display. So it means I will have to restrict somehow active area to be sure I wont place any sprite outside visible area. Is it the correct way to deal with this problem or I am missing something?

Thanks for any help.

peter

I think that this is one of the most challenging aspects of starting out with Cocos2d-x, i.e design resolution and content scale factor. To be honest. I don’t grasp it 100% either.

I found this helpful: http://gamedev.stackexchange.com/questions/2073/how-would-you-handle-different-aspect-ratios-in-a-2d-platformer

What I do is I look at the size of the screen the user has and I size my layers accordingly. I also use a separate sprite sheet for each resolution that I want to support. This surely adds to the file size of my app. I use the resolution to create a multiplier factor for positioning. So all of my positioning is multiplied by a number that represents the screen size. I do set the resolution policy to ResolutionPolicy::NO_BORDERS

This works well for me, but I am sure there are better easy to handle aspect ratio. I think as others chime in here we are set to learn a few things from this thread.

Hi slackmoehrle,
thank you for your answer, it gave me some idea how can I solve this problem. I am sharing my code, maybe someone will find it useful.

Assumption:

  • only landscape orientation
  • fixed design resolution size (480x320), regardless of device resolution
  • support any aspect ratios between 4:3 and 16:9
  • support any resolution up to 2400x1600
  • four sets of resources

Solution:
I have design resolution size 480x320 and if aspect ratio is different than 3:2 I adjust design resolution to fill the whole screen. Then I add content layer, which is centred, has correct resolution and should be used as parent for any sprite. The rest is simple: I choose correct resource and set content scale factor.

Source code:

        // design resolution
        Size designSize(480.0, 320.0);
        float designAR(designSize.width/designSize.height);
        
        CCLOG ("design res width: %4.4f; height: %4.4f; ar: %4.4f;\n", designSize.width, designSize.height, designAR);

        
        // device resolution
        Size deviceSize(Director::getInstance()->getOpenGLView()->getFrameSize());
        float deviceAR(deviceSize.width/deviceSize.height);
        
        CCLOG ("device res width: %4.4f; height: %4.4f; ar: %4.4f;\n", deviceSize.width, deviceSize.height, deviceAR);
        
        // final design size, enlarged if aspect ratio is different than 3:2
        Size finalDesignSize(designSize);
        
        // wide screen
        if(deviceAR > designAR)
        {
                finalDesignSize.width = finalDesignSize.width * (deviceAR/designAR);
        }
        // narrow screen
        else if (deviceAR < designAR)
        {
                finalDesignSize.height = finalDesignSize.height * (designAR/deviceAR);
        }
        
        float finalDesignAR(finalDesignSize.width/finalDesignSize.height);
        
        CCLOG ("final design res width: %4.4f; height: %4.4f; ar: %4.4f;\n", finalDesignSize.width, finalDesignSize.height, finalDesignAR);
        
        glview->setDesignResolutionSize(finalDesignSize.width, finalDesignSize.height, ResolutionPolicy::NO_BORDER);
        
        // set resource directory and content scale factor
        auto fileUtils = FileUtils::getInstance();
        std::vector<std::string> resSearchPaths;
        
        struct Resource
        {
                Size size;
                char directory[100];
        };
        
        Resource smallResource  = { Size(480.0, 320.0),         "sd" }; // 570x360
        Resource mediumResource = { Size(960.0, 640.0),         "md" }; // 1140x720
        Resource highResource   = { Size(1440.0, 960.0),        "hd" }; // 1710x1080
        Resource ultraResource  = { Size(2400.0, 1600.0),       "ud" }; // 2846x1800
        
        Resource currentResource;
        
        // wide screen, use height to choose resources
        if(deviceAR >= designAR)
        {
                if(deviceSize.height > highResource.size.height)
                {
                        currentResource = ultraResource;
                }
                else if(deviceSize.height > mediumResource.size.height)
                {
                        currentResource = highResource;
                }
                else if(deviceSize.height > smallResource.size.height)
                {
                        currentResource = mediumResource;
                }
                else
                {
                        currentResource = smallResource;
                }
        }
        // narrow screen, use width to choose resuorces
        else
        {
                if(deviceSize.width > highResource.size.width)
                {
                        currentResource = ultraResource;
                }
                else if(deviceSize.width > mediumResource.size.width)
                {
                        currentResource = highResource;
                }
                else if(deviceSize.width > smallResource.size.width)
                {
                        currentResource = mediumResource;
                }
                else
                {
                        currentResource = smallResource;
                }
        }
        
        resSearchPaths.push_back(currentResource.directory);
        
        fileUtils->setSearchPaths(resSearchPaths);
        
        Director::getInstance()->setContentScaleFactor(currentResource.size.width/designSize.width);
        
        // create a scene. it's an autorelease object
        auto scene = HelloWorld::createScene();
        
        // set background layer
        Layer* backgroundLayer = Layer::create();
        scene->addChild(backgroundLayer);
        
        Sprite* background = Sprite::create("bg.jpg");
        background->setPosition(Vec2(finalDesignSize.width/2, finalDesignSize.height/2));
        backgroundLayer->addChild(background);
        
        // set content layer
        Layer* contentLayer = Layer::create();
        contentLayer->setContentSize(designSize); // probably useless
        contentLayer->setPosition(Vec2((finalDesignSize.width - designSize.width)/2, (finalDesignSize.height - designSize.height)/2));
        scene->addChild(contentLayer);
        
        Sprite* dot = Sprite::create("dot.png");
        contentLayer->addChild(dot);

Results:

iPhone Retina 3,5 inch

iPhone Retina 4 inch

iPad

This code is probably overcomplicated but seems to work.

Discussion is welcome.

3 Likes

Nice job. Thanks for sharing. Your code doesn’t look bad at all :slight_smile:

Hi,
I have a question about your screenshot:
can you publish the code that you wrote to have a yellow background that cover space of full device screen?

Thanks

Hi,
I am not sure if I understand your question, but the whole code I used is in the 3rd post. There is nothing more. As an exmaple background I used four images, which sizes are described in comments, in the “Resource smallResource = etc.” section.

Regards