Multi-resolution code in the default template

Why multi-resolution code in the default template is so confusing?

This is the default AppDelegate.cpp.

#include "AppDelegate.h"
#include "HelloWorldScene.h"

// #define USE_AUDIO_ENGINE 1
// #define USE_SIMPLE_AUDIO_ENGINE 1

#if USE_AUDIO_ENGINE && USE_SIMPLE_AUDIO_ENGINE
#error "Don't use AudioEngine and SimpleAudioEngine at the same time. Please just select one in your game!"
#endif

#if USE_AUDIO_ENGINE
#include "audio/include/AudioEngine.h"
using namespace cocos2d::experimental;
#elif USE_SIMPLE_AUDIO_ENGINE
#include "audio/include/SimpleAudioEngine.h"
using namespace CocosDenshion;
#endif

USING_NS_CC;

static cocos2d::Size designResolutionSize = cocos2d::Size(480, 320);
static cocos2d::Size smallResolutionSize = cocos2d::Size(480, 320);
static cocos2d::Size mediumResolutionSize = cocos2d::Size(1024, 768);
static cocos2d::Size largeResolutionSize = cocos2d::Size(2048, 1536);

AppDelegate::AppDelegate()
{
}

AppDelegate::~AppDelegate() 
{
#if USE_AUDIO_ENGINE
    AudioEngine::end();
#elif USE_SIMPLE_AUDIO_ENGINE
    SimpleAudioEngine::end();
#endif
}

// if you want a different context, modify the value of glContextAttrs
// it will affect all platforms
void AppDelegate::initGLContextAttrs()
{
    // set OpenGL context attributes: red,green,blue,alpha,depth,stencil
    GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};

    GLView::setGLContextAttrs(glContextAttrs);
}

// if you want to use the package manager to install more packages,  
// don't modify or remove this function
static int register_all_packages()
{
    return 0; //flag for packages manager
}

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
        glview = GLViewImpl::createWithRect("HelloCpp", cocos2d::Rect(0, 0, designResolutionSize.width, designResolutionSize.height));
#else
        glview = GLViewImpl::create("HelloCpp");
#endif
        director->setOpenGLView(glview);
    }

    // turn on display FPS
    director->setDisplayStats(true);

    // set FPS. the default value is 1.0/60 if you don't call this
    director->setAnimationInterval(1.0f / 60);

    // Set the design resolution
    glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);
    auto frameSize = glview->getFrameSize();
    // if the frame's height is larger than the height of medium size.
    if (frameSize.height > mediumResolutionSize.height)
    {        
        director->setContentScaleFactor(MIN(largeResolutionSize.height/designResolutionSize.height, largeResolutionSize.width/designResolutionSize.width));
    }
    // if the frame's height is larger than the height of small size.
    else if (frameSize.height > smallResolutionSize.height)
    {        
        director->setContentScaleFactor(MIN(mediumResolutionSize.height/designResolutionSize.height, mediumResolutionSize.width/designResolutionSize.width));
    }
    // if the frame's height is smaller than the height of medium size.
    else
    {        
        director->setContentScaleFactor(MIN(smallResolutionSize.height/designResolutionSize.height, smallResolutionSize.width/designResolutionSize.width));
    }

    register_all_packages();

    // create a scene. it's an autorelease object
    auto scene = HelloWorld::createScene();

    // run
    director->runWithScene(scene);

    return true;
}

// This function will be called when the app is inactive. Note, when receiving a phone call it is invoked.
void AppDelegate::applicationDidEnterBackground() {
    Director::getInstance()->stopAnimation();

#if USE_AUDIO_ENGINE
    AudioEngine::pauseAll();
#elif USE_SIMPLE_AUDIO_ENGINE
    SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
    SimpleAudioEngine::getInstance()->pauseAllEffects();
#endif
}

// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground() {
    Director::getInstance()->startAnimation();

#if USE_AUDIO_ENGINE
    AudioEngine::resumeAll();
#elif USE_SIMPLE_AUDIO_ENGINE
    SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
    SimpleAudioEngine::getInstance()->resumeAllEffects();
#endif
}
  • The first thing I do not like is how mixed setDesignResolutionSize() and setContentScaleFactor().

I can see two logical ways of using setContentScaleFactor().

  1. If you use setDesignResolutionSize() and use multiple folders with graphics resources. In this case setContentScaleFactor() must be used together with setSearchPaths().
    This is not the case of a default template.

  2. If you do not use setDesignResolutionSize() and prefer to have your own headache with scaling.
    This is not the case of a default template too.

Wait… aspect ratios! look at the aspect ratio of designResolutionSize, smallResolutionSize, mediumResolutionSize, largeResolutionSize. This gives me the idea that in this case setContentScaleFactor() compensates the different aspect ratios. It still does not explain why setSearchPaths() is missing though.

  • Now the second thing I do not like is different aspect ratios of designResolutionSize, smallResolutionSize, mediumResolutionSize, largeResolutionSize.

This will probably work if you are developing only for iOS and you have a very limited set of screen resolutions.
But trying to calculate how this code will work on android devices causes me a headache and a desire to stop trying.
I mean, I can not guarantee that there really will not be black borders on all devices with this code. Mostly because I really stopped trying. And it is very difficult (in this case) to calculate what size should UI elements and other graphic elements have to ensure that there will not be clipping and overlapping of the elements.

My point? This code is poorly designed and needs to be changed.

I will work on this tomorrow.

Nice. I am glad to hear that.

This is why I am adding my CustUtils.cpp to avoid that.

The following data is tested on 432 * 240 emulator.
dpi = 120
Content Scale Factor: 1.000000
FrameSize HW: 240.000000 432.000000
CustUtils: screenHeight, screenWidth: 240.000000, 432.000000
CustUtils: designScreenHeight, designScreenWidth: 720.000000, 1280.000000
CustUtils: scaleX, scaleY: 0.337500, 1.000000
Bounding HW= 243.000000 432.000000
Image HW= 720.000000 1280.000000

testcase_432_240

The following data is tested on 800 * 480 emulator.
dpi = 240
Content Scale Factor: 1.000000
FrameSize HW: 480.000000 800.000000
CustUtils: screenHeight, screenWidth: 480.000000, 800.000000
CustUtils: designScreenHeight, designScreenWidth: 720.000000, 1280.000000
CustUtils: scaleX, scaleY: 1.000000, 0.666667
Bounding HW= 480.000000 853.333374
Image HW= 720.000000 1280.000000

If you look at the image very closely, you will see top and bottom red borders are slightly cropped.

What I am doing in CustUtils.cpp is find out Aspect Ratio.
432 * 240 AR = 1.8
800 * 480 AR = 1.66
My default image AR or CustUtils.cpp’s default AR (1280 * 720) = 1.77

Now based on AR comparison, I am trying to scale the image just to avoid black bars.

On 800 * 432(lower AR than 1.77) cropping will be done based on width, since width is bigger. And 432 * 240(greater AR than 1.77) cropping will be done based on height since height is bigger. Both after scaling.

Truly AppDelegate.cpp needs overhaul. It’s way too much confusing.

Is this the result of the original code?

I edited my post.

But I can guarantee that there really will not be black borders when using setDesignResolutionSize() and setContentScaleFactor() in another ways and I can relatively easily calculate the restrictions on the use these ways.

This is my final modified code.

I tried to do it in my way.

I see what you mean now.

This is one of the solutions. Thank you for sharing. I’m sure that it will be useful for others.

1 Like

I would like to post my modified code here so that others can get help.

AppDelegate.cpp

#include "AppDelegate.h"
#include "CustUtils.h"
#include "SplashScreen.h"

// #define USE_AUDIO_ENGINE 1
// #define USE_SIMPLE_AUDIO_ENGINE 1

#if USE_AUDIO_ENGINE && USE_SIMPLE_AUDIO_ENGINE
#error "Don't use AudioEngine and SimpleAudioEngine at the same time. Please just select one in your game!"
#endif

#if USE_AUDIO_ENGINE
#include "audio/include/AudioEngine.h"
using namespace cocos2d::experimental;
#elif USE_SIMPLE_AUDIO_ENGINE
#include "audio/include/SimpleAudioEngine.h"
using namespace CocosDenshion;
#endif

USING_NS_CC;

AppDelegate::AppDelegate()
{
}

AppDelegate::~AppDelegate() 
{
#if USE_AUDIO_ENGINE
    AudioEngine::end();
#elif USE_SIMPLE_AUDIO_ENGINE
    SimpleAudioEngine::end();
#endif
}


void AppDelegate::initGLContextAttrs()
{
    GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};

    GLView::setGLContextAttrs(glContextAttrs);
}

static int register_all_packages()
{
    return 0;
}

bool AppDelegate::applicationDidFinishLaunching() {
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
        glview = GLViewImpl::createWithRect("IPW", cocos2d::Rect(0, 0, designResolutionSize.width, designResolutionSize.height));
#else
        glview = GLViewImpl::create("IPW");
#endif
        director->setOpenGLView(glview);
    }

    director->setDisplayStats(false);
    director->setAnimationInterval(1.0f / 60);

    auto frameSize = glview->getFrameSize();

    glview->setDesignResolutionSize(frameSize.width, frameSize.height, ResolutionPolicy::NO_BORDER);

    CustUtils::getWinSize(frameSize.height, frameSize.width);

    register_all_packages();

    auto scene = SplashScreen::createScene();
    director->runWithScene(scene);

    return true;
}

void AppDelegate::applicationDidEnterBackground() {
    Director::getInstance()->stopAnimation();

#if USE_AUDIO_ENGINE
    AudioEngine::pauseAll();
#elif USE_SIMPLE_AUDIO_ENGINE
    SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
    SimpleAudioEngine::getInstance()->pauseAllEffects();
#endif
}

void AppDelegate::applicationWillEnterForeground() {
    Director::getInstance()->startAnimation();

#if USE_AUDIO_ENGINE
    AudioEngine::resumeAll();
#elif USE_SIMPLE_AUDIO_ENGINE
    SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
    SimpleAudioEngine::getInstance()->resumeAllEffects();
#endif
}

CustUtils.cpp

#include "CustUtils.h"

using namespace cocos2d;

static float designScreenHeight = 720;
static float designScreenWidth = 1280;
float screenHeight = 720;
float screenWidth = 1280;
float scaleFactor = 1.0f;

void CustUtils::scaleBG(cocos2d::Sprite *bg) {
    float scaleX = 1;
    float scaleY = 1;

    if((screenWidth / screenHeight) > (designScreenWidth / designScreenHeight)) {
        scaleX = screenWidth / designScreenWidth;

        CustUtils::setScaleFactor(scaleX);

        bg->setScale(scaleX);
    } else {
        scaleY = screenHeight / designScreenHeight;

        CustUtils::setScaleFactor(scaleY);

        bg->setScale(scaleY);
    }
}

void CustUtils::setScaleFactor(float scale) {
    scaleFactor = scale;
}

float CustUtils::getScaleFactor(){
    return scaleFactor;
}

void CustUtils::getWinSize(float height, float width) {
    screenHeight = height;
    screenWidth = width;
}

SplashScreen.cpp

#include "SplashScreen.h"
#include "SimpleAudioEngine.h"
#include "CustUtils.h"

USING_NS_CC;

Scene* SplashScreen::createScene()
{
    return SplashScreen::create();
}

bool SplashScreen::init()
{
    if ( !Scene::init() )
    {
        return false;
    }

    auto visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();

    auto sprite = Sprite::create("images/splashscreen.png");
    CustUtils::scaleBG(sprite);
    sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
    this->addChild(sprite, 0);

    return true;
}

Just wondering why you do not use setContentScaleFactor() anymore?

It was only making me confused. That’s why.

Come on, you perfectly explained your idea of how to calculate scaleFactor to avoid black borders, now you only need to use setContentScaleFactor() and then the engine will be apply scaleFactor to all sprites automatically.

I do not want the engine to take care of the images. Because, in case of engine, it will just take the MIN or MAX value of the ratios. But then there will be no guarantee of black border’s absence. That’s why I am using contentScaleFactor = 1 and implementing my scaleFactor to guarantee black border’s absence.

If you will use setContentScaleFactor(yourScaleFactor), then you will not get black borders. 100%

It is based on your code.

#include "AppDelegate.h"
#include "HelloWorldScene.h"

// #define USE_AUDIO_ENGINE 1
// #define USE_SIMPLE_AUDIO_ENGINE 1

#if USE_AUDIO_ENGINE && USE_SIMPLE_AUDIO_ENGINE
#error "Don't use AudioEngine and SimpleAudioEngine at the same time. Please just select one in your game!"
#endif

#if USE_AUDIO_ENGINE
#include "audio/include/AudioEngine.h"
using namespace cocos2d::experimental;
#elif USE_SIMPLE_AUDIO_ENGINE
#include "audio/include/SimpleAudioEngine.h"
using namespace CocosDenshion;
#endif

USING_NS_CC;

static cocos2d::Size designResolutionSize = cocos2d::Size(1280, 720);


AppDelegate::AppDelegate()
{
}

AppDelegate::~AppDelegate() 
{
#if USE_AUDIO_ENGINE
    AudioEngine::end();
#elif USE_SIMPLE_AUDIO_ENGINE
    SimpleAudioEngine::end();
#endif
}

// if you want a different context, modify the value of glContextAttrs
// it will affect all platforms
void AppDelegate::initGLContextAttrs()
{
    // set OpenGL context attributes: red,green,blue,alpha,depth,stencil
    GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};

    GLView::setGLContextAttrs(glContextAttrs);
}

// if you want to use the package manager to install more packages,  
// don't modify or remove this function
static int register_all_packages()
{
    return 0; //flag for packages manager
}

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
        glview = GLViewImpl::createWithRect("HelloCpp", cocos2d::Rect(0, 0, designResolutionSize.width, designResolutionSize.height));
#else
        glview = GLViewImpl::create("HelloCpp");
#endif
        director->setOpenGLView(glview);
    }

    // turn on display FPS
    director->setDisplayStats(true);

    // set FPS. the default value is 1.0/60 if you don't call this
    director->setAnimationInterval(1.0f / 60);

    // Set the design resolution
    //glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);
    auto frameSize = glview->getFrameSize();

	if ((frameSize.width / frameSize.height) > (designResolutionSize.width / designResolutionSize.height))
	{
		director->setContentScaleFactor(frameSize.width / designResolutionSize.width);
	}
	else // (frameSize.width / frameSize.height) < (designResolutionSize.width / designResolutionSize.height)
	{
		director->setContentScaleFactor(frameSize.height / designResolutionSize.height);
	}

    register_all_packages();

    // create a scene. it's an autorelease object
    auto scene = HelloWorld::createScene();

    // run
    director->runWithScene(scene);

    return true;
}

// This function will be called when the app is inactive. Note, when receiving a phone call it is invoked.
void AppDelegate::applicationDidEnterBackground() {
    Director::getInstance()->stopAnimation();

#if USE_AUDIO_ENGINE
    AudioEngine::pauseAll();
#elif USE_SIMPLE_AUDIO_ENGINE
    SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
    SimpleAudioEngine::getInstance()->pauseAllEffects();
#endif
}

// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground() {
    Director::getInstance()->startAnimation();

#if USE_AUDIO_ENGINE
    AudioEngine::resumeAll();
#elif USE_SIMPLE_AUDIO_ENGINE
    SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
    SimpleAudioEngine::getInstance()->resumeAllEffects();
#endif
}

In this case, you do not need to scale each sprite manually.
And you can always get scaleFactor by director->getContentScaleFactor().

I tried this but did not get what I wanted. That’s why I moved to my solution.

My bad. It should be setContentScaleFactor(1 / yourScaleFactor).

Here is the correct version.

AppDelegate.cpp

#include "AppDelegate.h"
#include "HelloWorldScene.h"

// #define USE_AUDIO_ENGINE 1
// #define USE_SIMPLE_AUDIO_ENGINE 1

#if USE_AUDIO_ENGINE && USE_SIMPLE_AUDIO_ENGINE
#error "Don't use AudioEngine and SimpleAudioEngine at the same time. Please just select one in your game!"
#endif

#if USE_AUDIO_ENGINE
#include "audio/include/AudioEngine.h"
using namespace cocos2d::experimental;
#elif USE_SIMPLE_AUDIO_ENGINE
#include "audio/include/SimpleAudioEngine.h"
using namespace CocosDenshion;
#endif

USING_NS_CC;

static cocos2d::Size designResolutionSize = cocos2d::Size(1280, 720);


AppDelegate::AppDelegate()
{
}

AppDelegate::~AppDelegate() 
{
#if USE_AUDIO_ENGINE
    AudioEngine::end();
#elif USE_SIMPLE_AUDIO_ENGINE
    SimpleAudioEngine::end();
#endif
}

// if you want a different context, modify the value of glContextAttrs
// it will affect all platforms
void AppDelegate::initGLContextAttrs()
{
    // set OpenGL context attributes: red,green,blue,alpha,depth,stencil
    GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};

    GLView::setGLContextAttrs(glContextAttrs);
}

// if you want to use the package manager to install more packages,  
// don't modify or remove this function
static int register_all_packages()
{
    return 0; //flag for packages manager
}

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
        glview = GLViewImpl::createWithRect("Multi-resolution", cocos2d::Rect(0, 0, 640, 480));
#else
        glview = GLViewImpl::create("Multi-resolution");
#endif
        director->setOpenGLView(glview);
    }

    // turn on display FPS
    director->setDisplayStats(true);

    // set FPS. the default value is 1.0/60 if you don't call this
    director->setAnimationInterval(1.0f / 60);

    // Set the design resolution
    //glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);
    auto frameSize = glview->getFrameSize();

	if ((frameSize.width / frameSize.height) > (designResolutionSize.width / designResolutionSize.height))
	{
		//director->setContentScaleFactor(frameSize.width / designResolutionSize.width);
		auto scale = frameSize.width / designResolutionSize.width;
		director->setContentScaleFactor(1 / scale);
	}
	else // (frameSize.width / frameSize.height) < (designResolutionSize.width / designResolutionSize.height)
	{
		//director->setContentScaleFactor(frameSize.height / designResolutionSize.height);
		auto scale = frameSize.height / designResolutionSize.height;
		director->setContentScaleFactor(1 / scale);
	}

    register_all_packages();

    // create a scene. it's an autorelease object
    auto scene = HelloWorld::createScene();

    // run
    director->runWithScene(scene);

    return true;
}

// This function will be called when the app is inactive. Note, when receiving a phone call it is invoked.
void AppDelegate::applicationDidEnterBackground() {
    Director::getInstance()->stopAnimation();

#if USE_AUDIO_ENGINE
    AudioEngine::pauseAll();
#elif USE_SIMPLE_AUDIO_ENGINE
    SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
    SimpleAudioEngine::getInstance()->pauseAllEffects();
#endif
}

// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground() {
    Director::getInstance()->startAnimation();

#if USE_AUDIO_ENGINE
    AudioEngine::resumeAll();
#elif USE_SIMPLE_AUDIO_ENGINE
    SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
    SimpleAudioEngine::getInstance()->resumeAllEffects();
#endif
}

HelloWorldScene.cpp

#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"

USING_NS_CC;

Scene* HelloWorld::createScene()
{
    return HelloWorld::create();
}

// Print useful error message instead of segfaulting when files are not there.
static void problemLoading(const char* filename)
{
    printf("Error while loading: %s\n", filename);
    printf("Depending on how you compiled you might have to add 'Resources/' in front of filenames in HelloWorldScene.cpp\n");
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !Scene::init() )
    {
        return false;
    }

	auto frameSize = Director::getInstance()->getOpenGLView()->getFrameSize();

    auto visibleSize = Director::getInstance()->getVisibleSize();
    auto origin = Director::getInstance()->getVisibleOrigin();

	// back
	auto back = Sprite::create("1280x720.png");
	back->setPosition(frameSize.width / 2, frameSize.height / 2);

	this->addChild(back);

	// triangle1
	auto triangle1 = Sprite::create("triangle1.png");
	triangle1->setPosition(triangle1->getContentSize().width / 2, frameSize.height / 2);

	this->addChild(triangle1);

	// triangle2
	auto triangle2 = Sprite::create("triangle2.png");
	triangle2->setPosition(frameSize.width / 2, frameSize.height - (triangle2->getContentSize().height / 2));

	this->addChild(triangle2);
	
	return true;
}


void HelloWorld::menuCloseCallback(Ref* pSender)
{
    //Close the cocos2d-x game scene and quit the application
    Director::getInstance()->end();

    #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif

    /*To navigate back to native iOS screen(if present) without quitting the application  ,do not use Director::getInstance()->end() and exit(0) as given above,instead trigger a custom event created in RootViewController.mm as below*/

    //EventCustom customEndEvent("game_scene_close_event");
    //_eventDispatcher->dispatchEvent(&customEndEvent);


}

Resources

1280x720.png

triangle1.png

triangle1

triangle2.png

triangle2

Screen 640x480

Screen 960x540

Screen 854x480

Screen 2160x1080 (x0.5)
(It is LG Q6 screen)

  • Note

Despite the fact that this is working solution, I prefer to use design resolution.

Because if I want to get something like this (the positions of the triangles)

and if I use the design resolution (glview->setDesignResolutionSize(1280, 720, ResolutionPolicy::NO_BORDER)),
then I can use this simple code to get the same result on all devices

auto visibleSize = Director::getInstance()->getVisibleSize();
auto origin = Director::getInstance()->getVisibleOrigin();

// back
auto back = Sprite::create("1280x720.png");
back->setPosition(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2);

this->addChild(back);

// triangle1
auto triangle1 = Sprite::create("triangle1.png");
triangle1->setPosition(origin.x + 100 + 70, origin.y + visibleSize.height / 2);

this->addChild(triangle1);

// triangle2
auto triangle2 = Sprite::create("triangle2.png");
triangle2->setPosition(origin.x + 100 + 70 + 200 + 70, origin.y + visibleSize.height / 2);

this->addChild(triangle2);

(The size of the triangles is 200x200, and the distance is 70).

I do not need to scale the distance or the size of the triangles, it will happen automatically.

  • Note 2

And even this is not the final solution.

In most cases, it is a good idea to use multiple sets of graphic resources, so

1 Like

I worked on it for a while to suggest the most universal and intuitive solution. But I accidentally deleted my codes and notes, and I can not restore it. I’m so upset now.

The good thing is that this post will be shorter than it might be, because I write only what I remember.

  • Option 1

Firstly, I do not think this is the best solution ever, but I think that this is a good option to illustrate how this works.

The aspect ratio of the Design Resolution is 16/9 to illustrate NO_BORDER.
Convenient scale factors (x1, x2, x3).

...

static cocos2d::Size designResolutionSize = cocos2d::Size(960, 540);

static cocos2d::Size smallResolutionSize = cocos2d::Size(960, 540);
static cocos2d::Size mediumResolutionSize = cocos2d::Size(1920, 1080);
static cocos2d::Size largeResolutionSize = cocos2d::Size(2880, 1620);

...

// Set the design resolution
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);

auto frameSize = glview->getFrameSize();
std::vector<std::string> searchPaths;

if (frameSize.width > mediumResolutionSize.width)
{
   director->setContentScaleFactor(largeResolutionSize.width/designResolutionSize.width);
   searchPaths.push_back("largeResources");
}
else if (frameSize.width > smallResolutionSize.width)
{
   director->setContentScaleFactor(mediumResolutionSize.width/designResolutionSize.width);
   searchPaths.push_back("mediumResources");
}
else
{
   director->setContentScaleFactor(smallResolutionSize.width/designResolutionSize.width);
   searchPaths.push_back("smallResources");
}

FileUtils::getInstance()->setSearchPaths(searchPaths);

...

In this case, I just do not like how it works if the screen aspect ratio < 16/9. Maybe I’m just a perfectionist. But this is a good option to illustrate NO_BORDER. I doubt what to choose.

  • Option 2

The aspect ratio of the Design Resolution is 4/3, not so good to illustrate NO_BORDER, my inner perfectionist absolutely likes how it works.
Convenient scale factors (x1, x2, x3).

...

static cocos2d::Size designResolutionSize = cocos2d::Size(960, 720);

static cocos2d::Size smallResolutionSize = cocos2d::Size(960, 720);
static cocos2d::Size mediumResolutionSize = cocos2d::Size(1920, 1440);
static cocos2d::Size largeResolutionSize = cocos2d::Size(2880, 2160);

...

// Set the design resolution
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);

auto frameSize = glview->getFrameSize();
std::vector<std::string> searchPaths;

if (frameSize.width > mediumResolutionSize.width)
{
   director->setContentScaleFactor(largeResolutionSize.width/designResolutionSize.width);
   searchPaths.push_back("largeResources");
}
else if (frameSize.width > smallResolutionSize.width)
{
   director->setContentScaleFactor(mediumResolutionSize.width/designResolutionSize.width);
   searchPaths.push_back("mediumResources");
}
else
{
   director->setContentScaleFactor(smallResolutionSize.width/designResolutionSize.width);
   searchPaths.push_back("smallResources");
}

FileUtils::getInstance()->setSearchPaths(searchPaths);

...
  • Option 3

The aspect ratio of the Design Resolution is 4/3, not so good to illustrate NO_BORDER, more iOS friendly.
Personally, I do not like scale factors.

...

static cocos2d::Size designResolutionSize = cocos2d::Size(1024, 768);

static cocos2d::Size smallResolutionSize = cocos2d::Size(1024, 768);
static cocos2d::Size mediumResolutionSize = cocos2d::Size(2048, 1536);
static cocos2d::Size largeResolutionSize = cocos2d::Size(2880, 2160);

...

// Set the design resolution
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);

auto frameSize = glview->getFrameSize();
std::vector<std::string> searchPaths;

if (frameSize.width > mediumResolutionSize.width)
{
   director->setContentScaleFactor(largeResolutionSize.width/designResolutionSize.width);
   searchPaths.push_back("largeResources");
}
else if (frameSize.width > smallResolutionSize.width)
{
   director->setContentScaleFactor(mediumResolutionSize.width/designResolutionSize.width);
   searchPaths.push_back("mediumResources");
}
else
{
   director->setContentScaleFactor(smallResolutionSize.width/designResolutionSize.width);
   searchPaths.push_back("smallResources");
}

FileUtils::getInstance()->setSearchPaths(searchPaths);

...
  • Note

Since there are many similar resolutions like 1920x1080, 1920x1200, 1920x1280, 1920x1440, I prefer to choose the resources based on the longer side of the screen, in the case of the default template it is width.

@slackmoehrle I want to know your opinion. :slight_smile:

1 Like

I mean it works correctly, but in some cases the resources will be scaled up.
eg if screen size is 1920x1440.

In fact, any criticism is welcome.

I will take a look.

Can you please also take a look at SBX? :slight_smile:
It supports any resolution and developing multi resolution games is so simple with it, also it WYSYWYG, so you can check any resolution support in no time by quickly switching between them.