Maxxx
April 3, 2015, 11:08am
#21
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
hydex86
September 12, 2015, 1:31am
#22
Continuing the discussion from Am I overthinking this? (Multi-resolution support) :
wiwing:
Doesn’t cocos2d-x already offer multi-resolution support in their pipeline? why did you reinvent the wheel with that complex calculation. Usually for multi-resolution, I combined what cocos2d-x has offered with this http://v-play.net/doc/vplay-different-screen-sizes/ and adjust the size a little bit.
So I classified all screens resolution into 3 design size categories which are: RETINA_HD (RETINA), HD and SD. And the design size for each categories are as follow:
#define SCREEN_WIDTH_SD 627
#define SCREEN_HEIGHT_SD 396
#define SCREEN_WIDTH_HD 1254
#define SCREEN_HEIGHT_HD 792
#define SCREEN_WIDTH_RETINA 2508
#define SCREEN_HEIGHT_RETINA 1584
#define GAME_WIDTH_SD 528
#define GAME_HEIGHT_SD 360
#define GAME_WIDTH_HD 1056
#define GAME_HEIGHT_HD 704
#define GAME_WIDTH_RETINA 2112
#define GAME_HEIGHT_RETINA 1408
From the previous link, we need to set the aspect ratio for the design size around 19:12 and design everything that happened in the gameplay should be inside a 3:2 aspect ratio screen in order to maintain support for all screen resolution without cutting anything during gameplay. As you can see from the code snippet, all those design size categories have the same pattern such as: HD design is half of RETINA design, and SD design is half of HD design. Thus can make everything easier when the artists made the assets for the game. They just need to create the assets for the largest resolution, then resize the image accordingly
Then on the AppDelegate, we just need to implement multi-resolution calculation from cocos2d-x pipeline. In my case, I’ve decided to design the game without showing any black border, so I used NO_BORDER resolution policy and design everything on the largest resolution.
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);
Then cocos2d-x will do all the complex things by itself and you don’t need to worry about this anymore.
well, the bad thing about this kind of implementation is we need to put the assets in a designated folder’s name and make the folder as blue folder in Xcode project which is sometimes annoying because you need to clean and rebuild everything when you add new assets into the folder.
I hope this can be helpful.
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?
wiwing
September 12, 2015, 5:16am
#23
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
hydex86:
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.
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
hydex86
September 12, 2015, 10:07am
#24
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
wiwing
November 25, 2015, 4:40am
#26
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()