Am I overthinking this? (Multi-resolution support)

I don’t see your problem?
Get the dpi will tell you how many pixels per inch
So if you want something to be the same physical height (say 1 inch) then it has to be that many pixels high - so on an iphone 6, 326 pixels, on an iPad1 132 pixels.

If you do it like this, put the devices side-by-side, then the object should be the same size.

1 Like

Continuing the discussion from Am I overthinking this? (Multi-resolution support):

I tried a proof of concept with your approach (running cocos2d-x 3.8). I created a sprite as background that covers the whole screen (2508x1584 in RETINA). Added this centered.

I tried to launch my demo project on an iPhone 6 simulator and the sprite is bigger than physical screen.

This is the code in AppDelegate:

auto screenSize = glview->getFrameSize();
auto designSize = cocos2d::Size(SCREEN_WIDTH_RETINA, SCREEN_HEIGHT_RETINA);
auto gameSize = cocos2d::Size(GAME_WIDTH_RETINA, GAME_HEIGHT_RETINA);

std::vector<std::string> searchPaths;

if(screenSize.height <= SCREEN_HEIGHT_SD) {
    searchPaths.push_back("SD");
    director->setContentScaleFactor(SCREEN_HEIGHT_SD/designSize.height);
    cocos2d::log("Set SD Design Res");
} else if(screenSize.height <= SCREEN_HEIGHT_HD) {
    searchPaths.push_back("HD");
    director->setContentScaleFactor(SCREEN_HEIGHT_HD/designSize.height);
    cocos2d::log("Set HD Design Res");
} else {
    searchPaths.push_back("RETINA");
    director->setContentScaleFactor(SCREEN_HEIGHT_RETINA/designSize.height);
    cocos2d::log("Set RETINA Design Res");
}

cocos2d::FileUtils::getInstance()->setSearchPaths(searchPaths);
glview->setDesignResolutionSize(designSize.width, designSize.height, ResolutionPolicy::NO_BORDER);

And this is the code in the Scene:

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

Vec2 s_origin = Director::getInstance()->getVisibleOrigin();
Vec2 s_centre = s_origin + visibleSize / 2;

backgroundSprite = Sprite::create("background.png");
backgroundSprite->setPosition(s_centre);
this->addChild(backgroundSprite);

I thought cocos2d-x should rescale sprites from design size to phyisical size. Am I missing something?

Yeah it’s not working well on fonts, because on lower resolution screen the font is kinda losing its quality and become blurry even when you use ttf font. Right now I’m trying to look around for the solution on this matter

How much bigger is it? because these approach is to accommodate different aspect ratio by creating bigger aspect ratio and leave the excess area out

well if you want to let cocos2d-x rescale all your sprites from design size to physical size, then you should use it like this

auto screenSize = glview->getFrameSize();
auto designSize = cocos2d::Size(SCREEN_WIDTH_RETINA, SCREEN_HEIGHT_RETINA);
auto gameSize = cocos2d::Size(GAME_WIDTH_RETINA, GAME_HEIGHT_RETINA);

std::vector<std::string> searchPaths;
searchPaths.push_back("RETINA");
director->setContentScaleFactor(SCREEN_HEIGHT_RETINA/designSize.height);
cocos2d::log("Set RETINA Design Res");

cocos2d::FileUtils::getInstance()->setSearchPaths(searchPaths);
glview->setDesignResolutionSize(designSize.width, designSize.height, ResolutionPolicy::NO_BORDER);

but that solution will allocate huge amount of space in the device’s memory and it will be bad on low-end device with small RAM specs. That’s why I divided the assets into 3 size configuration (RETINA, HD and SD), and the scale is 1.0, 0.5 and 0.25 from the RETINA size. So you need to scale your RETINA background with that scale configuration and put them in each folder separately (usually I used python script to do this resizing task), so there will be the same background file but with different size on each folder

I found what I were missing! My proof of concept was in vertical position, so I had to made some changes to your code in AppDelegate.

I uploaded my demo project to GitHub to help someone who wants to apply @wiwing solution: https://github.com/hydex86/MultiResolution-cocos2dx

Thanks a lot!

1 Like

Can you share python script for resize? Thanks :smile:

sorry for the late reply @wanboouit … this is my python script for resizing the assets but you need to install Python Image Library or PILLOW

#! /usr/bin/python

import os
import sys
import argparse
import glob
import math
from PIL import Image 

verbose = False
EXPORT_DIRS = {
	"RETINA": 100,
	"HD": 50,
	"SD": 25
}
EXTENSIONS = [
	'png',
	'jpg'
]
PROJECT_PATH = os.environ['PROJECT_DIR']

def main():
	global verbose

	source = ''
	dest = ''
	scale = 0

	parser = argparse.ArgumentParser(description="Scale all PNG images inside source directory to a specified scale percentage.")
	parser.add_argument("-v", "--verbose", help="Vebose process", action="store_true")
	parser.add_argument("-o", "--outputdir", type=str, help="Output directory name")
	parser.add_argument("source", type=str, default=".", help="Relative/absolute source directory path. Default is current working directory")
	args = parser.parse_args()

	if args.verbose:
		verbose = args.verbose

	if args.outputdir:
		dest = args.outputdir

	if args.source:
		source = args.source

	convert(source, dest)

def convert(source, dest):
	sourcepath = ''
	destpath = ''

	if os.path.exists(source) :
		sourcepath = os.path.abspath(source)
	else:
		return

	print sourcepath
	for key in EXPORT_DIRS.keys():
		scale = EXPORT_DIRS[key]
		destpath = OUTPUT_PATH + key
		touch(destpath)
		if dest:
			destpath = destpath + "/" + dest

		if not os.path.exists(destpath):
			if verbose:
				print ("Creating directory: %s" % destpath)
			os.makedirs(destpath)

		for ext in EXTENSIONS:
			files = glob.glob(sourcepath + "/*." + ext)

			for imgsrc in files:
				img = Image.open(imgsrc)
				(w, h) = img.size
				width = int(math.ceil(int(w) * scale / 100))
				height = int(math.ceil(int(h) * scale / 100))
				scaledImg = img.resize((width, height), Image.ANTIALIAS)
				outputpath = destpath + "/" + os.path.basename(imgsrc)
				if verbose:
					print ("Save scaled %d%% image to %s" % (scale, outputpath))
				scaledImg.save(outputpath)
		if verbose :
			print ("Update assets folder timestamp")
		touch(destpath + "/")

def touch(fname, times=None) :
	os.utime(fname, times)

if __name__ ==  "__main__":
	main()