Am I overthinking this? (Multi-resolution support)

@Maxxx yeah, I’m using no border policy because I don’t want to leave any black bars on my screen thus why I create this design resolutions to meet the requirements for all available aspect ratios and different kind of devices, and you can get more efficiency on memory usage especially when the player uses low-end device. From what I’ve seen on your solutions, you’ll have problems when there is different kind of aspect ratio that is not listed on your resources dictionary (let’s say 800x480 or any 16:10 aspect ratio) and it’ll burden low-end devices a lot.

I’ve made sure that all my resources, when scaled using fixed height, still fill the screen with no borders at all the resolutions they are used for - so I will never have borders, and always exactly fill the height.

I guess using no border is less of an issue, except then I may lose top and bottom AND/OR left and right - which, if it’s ok for your App is great - but I really wanted to keep the entire height of my App visible.

well if you want to keep the entire height of your app visible, then you can use your solution but it’s kinda make everything more complex … since the coordinate system will also get affected by that or maybe not, I’m not sure since I haven’t tried your solution
the other solution is you can design your game with extra height which you don’t mind if it got clipped like what I’ve done, I design my game entirely on Game Screen (3:2 aspect ratio) so I don’t mind if the excess width/height got clipped as long as the Game Screen is shown fully.

Yeah - I think it just depends on the game itself whether you can get away with that.

Essentially what you end up with is a game playing on a window in the middle of the device - even though that might not be immediately obvious to the player

I was thinking of doing it like this and moving my HUD around to accommodate different aspect ratios and resolution - but that just got even more complex!

Does it matter whether a device is 4 inches or 5 inches or 6 inches or 10 inches?

Or all what matter is how many pixels are there in width and how many in height of a device?
(I mean while designing the assets and while adjusting it along with the cocos multi resolution policies)

Thanxx :smile:

As far as programming goes, the physical device size doesn’t matter, just the screen resolution.

Then where I should concern it?
While designing assets?

I would ignore it.

I’m not sure you can even find the physical dimensions of a screen by code.

If you run at 1024 x 768 on a phone with a 4 inch screen and then ran the same game on a 20 inch monitor running at 1024 x 768 then I would expect it to look identical - i.e. the physical size of a sprite would be 5x as big on the monitor.

the alternative would be that you would need to shrink the size - so a 25 pixel wide sprite on the phone would only be allowed to be 5 pixels wide on the monitor - which would look terrible!

Since you told me that we cannot get the physical size of the screen with code, then how will I do

I think you want to say vice versa…

Ok finally, do I need to care physical size of screen while designing my assets !!
Like bothering how will it look like on the larger screen with same ppi?

I think ppi matters and not the exact resolution. Isn’t it? :smiley:

THIS ONE IS REALLY TROUBLESOME AND THE HEIGHT OF ALL MY DOUBTS IN MULTI RESOLUTION!!

@Maxxx

Hi, please see my last post also.

@slackmoehrle, could you also please look to my following doubt!!

Okay now,

I suddenly came to realize this
There are android tablets as well as mobiles with same resolution as AxB for both.

Visualize portrait layout:

I am having 4 rectangles sprites to be arranged in a row in such a manner that it is easier for the user to type, I mean in fast typing user does not have to lift his fingers much!

So, suppose I am designing my game for this mobile. I can allow my row to entirely cover the screen’s width, i.e my left edge of left rectangular sprite touches the left edge of mobile and right rectangular sprite touches the right side of the mobile.
And it will be easier for him to type faster because the screen it small !!!

But if I let this code run for the same resolution devices but higher physical size. Then those rectangles sprites will become more wider and longer in height too!!
BUT FINGERS AND HANDS of my user won’t be that big to adjust!!!

So, I need to detect that if it is a tablet, then I should leave some border on the edges unlike mobile case!!

I hope you got my problem, right !!

Thanxx :slight_smile:

No. Say on a small device 10 pixels take up one cm
A larger device with the same pixel resolution, 10 pixels would take up more than once cm - so to make our object take up one cm again, we would have to reduce the number of pixels in it.

Honestly, I don’t know what your app/game is doing, so I can’t tell you if you need to take into account the physical screen size. I don’t know of any app that does - but someone is bound to be doing so somewhere.

Honestly, it depends what you are trying to achieve.

If you want your sprites to look identical (i.e. have the same physical size) across all devices, then you would need to take pixels per inch into account.

Are you saying you want to display (for example_ four rectangles on screen, and regardless of the device, you want them always to appear 1cm x 2cm ?

If that is the case then you do need to take into account the number of pixels per inch of the device.

This link tells you how to do that - (and also shows you how to find the physical screen dimensions)

Something similar. But actually I can allow my 4 rectangle sprites to cover the entire width of the screen when aligned adjacent to each other.
But in tablet the size of the rectangular sprites can be a little bigger but not enough that they will cover the entire width of the screen as above because otherwise player won’t be able to type comfortably. But yes, size can be a little bigger but not according to the logic for mobile devices!!

Hence, it asks for the need to know ppi or physical size of the screen!

Or it is possible to find whether a device is a mobile/phablet or tablet
Becuase I can afford my rectangles to cover entire width uptil phablet devices but not tablet

Let me go through the link. I think we can also find out dpi of the device in cocos2d-x!!

You can get DPI via: Device::getDPI();
But I found that DPI will not help you at all.

I have the problem that some of my testers complain that font is too small on their phones. While on tablets the font looks alright.
So here’s a few measurements I’ve tried (I’m using portrait only for my app):
Tablet, iPad1 - DPI: 132, 768x1024
Tablet, Samsung Tab 3 - DPI: 213, 800x1280
Phone, iPhone6 - DPI: 326, 750x1334
Phone, S4 Mini - DPI: 320, 540x960
Phone, S2 - DPI: 160, 480x640

So there’s really no way to understand from DPI if it’s a phone or a tablet.

I wish I knew about wiwing’s multi-resolution solution when I started on the app. Because now I’ve made special cases depending on which resolution the device has and done all the positioning & scaling manually.
It’s not too late to try it out tho. But wiwing’s solution will NOT help with fonts being too small on some devices.

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()