libgdx resolution/density scaling assets - libgdx

Quick question,
I am working on a game in libgdx and have hit a snag. I'm trying to scale my assets and I'm using Gdx.graphics.getDensity() to get the density and then setting my asset size using that as a multiplier. The issue I'm having is that on a tablet that has a 2560x1600 resolution has a density of 2.0, yet the nexus 5 emulator that has 1080x1920 has a density of 2.652... how does the tablet have a smaller density then the smaller phone?
What should I be using to get my multiplier for scaling if density is not reliable based on the android app screen size?

To answer your first question, it's a hardware thing. The Nexus 5 probably has a higher PPI (pixels per inch) ratio than the second, even though the resolution is smaller.
As to your second question, I would propose an alternative to Gdx.graphics.getDensity(): If you are trying to make sure that your asset is the same size relative to the screen (i.e. a 80x80 asset on a 2560x1600 display would be half the size on a 1280x800 display), then I think you want to leave your assets the same size and change the size of your camera instead.
When you create a game in libGDX (or any game engine), you need to keep in mind the difference between three sets of sizes/coordinates in your game:
Viewport size is the size of the space on your screen where your game will draw. It is measured in pixels and defaults to your window size (in a fullscreen game, the size of the screen).
game world size/coordinates are completely arbitrary. They are measured in whatever unit you want (be it meters, inches, bananas, F16s, etc.). You'll know you're working in game world units because you have floats.
camera size is the amount 'world' you can see at one time measured in game units. You can make your camera show a 1280x800 portion of the world or a 3x5 portion of the world or a 137.6x42 portion. The tricky thing is that libGDX's OrthographicCamera class defaults your viewport size, acting as though 1 game unit == 1 pixel.
Hopefully that made sense. Let's look at the implications:
Say I have a 800x600 GU (game unit) asset at 0,0 in my game world. My viewport size is 2560x1600, and my camera is scaled to 2560x1600 as well. My 800x600 GU object will render a 800x600 px image on the screen.
Now suppose I want to port my game to other screen sizes with the same ratio (just to keep things simple for now). I still have a 2560x1600 viewport size, but I change my camera to 8x5 GU and my game object to 2.5x1.875 GU. These sizes will be set explicitely- independent of the viewport size. This makes 1 GU = 320px. The net result is that my game object will still render a 800x600px image on the screen.
Now let's see how this would work on a 1280x800px resolution: My viewport is 1280x800 px, but my camera stays at 8x5 GU and my game object at 2.5x1.875 GU. Because of the size of the camera, 1 GU = 160px, which means my game object renders at 400x300, which means it is proportionally the same size on the smaller screen.
Hopefully that made sense without pictures. When you start using screens with different aspect ratios (i.e. you go from an 8x5 screen to a 3x2 screen), you need a little extra logic to keep the aspect ratio of your viewport the same as your camera (otherwise things get all stretched). Fortunately, libGDX provides some viewports which will do this for you.
You can find an external tutorial by the libGDX community here that talks more about this issue.

Related

How to use Capabilities in Air AS3 to determine correct dpi

I am currently looking into the best practices of implementing images and graphics to a new Adobe air project and would like to know which is the best practice in using images . I have a fair bit of experience in Flash with web development and am familiar with a lot of the standard coding issues however as I'm new to integrating data into the mobile domain would like to ensure I'm doing it in the best possible way as the information available is often contradictory to tutorials and existing material online.
I am currently building the project with the following : Adobe Air, Flash CC for Android, testing on a Samsung g6.
I have my main app class and so now have set a class to determine the system Capabilities etc and now have access to the following information to pre plan my layout etc :
dpi : 640
stageResolution : 1440 width x 2464 height.
Adobe Templates for android as3 projects are 480 x 800.
Is it wise to stick with this as a size even though my target app is a higher resolution and to create all images and MovieClips to this size and to integrate a scaling mechanism for lower/higher resolution, or is it common practice to keep to the 480 x 800 template and allow for all resizing options within the code?
Having trawled through a number of links and articles on how the Capabilities doesn't faithfully cover the exact sizes and specifications etc, what dpi is best for images being loaded into the the app?
For background images and gallery images, ie splashScreen embedded images etc, what dpi is best used for maximum quality?
I loaded a 1440 x 2464 *.jpg #72 dpi and it filled the screen perfectly on mobile, I also loaded a 1440 x 2464 *.jpg #640 dpi and couldn't notice any difference so is this effectively not worth worrying about?
Should I just use relative images to size at 72 dpi for everything? Backgrounds, buttons etc, and or resize or bitmapData with them when I add them to the stage.
Example, I create a series of new images in photoshop, set them to 1 cm x 1 cm for a button in the app. I create the same in 72, 160, 640 dpi for variation and to see the difference.
I load them all into my project as is next to each other.
The 72 dpi 1cm x 1cm = Actual size on screen, just over 1 mm.
The 160 dpi 1cm x 1cm = Actual size on screen, just over 2.5 mm.
The 640 dpi 1cm x 1cm = Actual size on screen, just over 1.1 cm.
Clearly the definition and size is relative, the 640 dpi image is almost right to the scale on screen despite it being slightly larger than the size of the image I created, only 1mm but ok, but if I were to plan my layout using cm/mm in photoshop or whatever program, it would fail miserably in regards to layout if I relied on these equations!?
I sourced links like this http://www.dallinjones.com/ whereby it helps give an insight into conversion etc, however it still doesn't add up as it should.
According to the Pixels to Millimeters algorythm:
mm = ( pixels * 25.4) / dpi;
My equation in as3 amounts to the following :
1440 x 25.4 = 36,576 / 640 = 57.15mm
The actual screen size of the phone is 63+ mm !?
Also I've seen that vector graphics aren't as effective when being used on mobiles.
I've seen documentation suggesting that vectors need to be set to 'cache As Bitmap' also, is this for all vectors and drawn graphics?
Say I want to dynamically draw a background panel with rounded corners and a gradient that fills the stage.
drawBackgroundPanel(0, 0, stage.stageWidth, stage.stageHeight).
I create the rectangle, draw add backgroundPanel to stage. Do I then have to cache as bitmap also?
Thank you for your help.

Use Libgdx and TexturePacker with xxxdpi images get distorted

I'm an android developer, building my first game using LibGDX. After reading A LOT, there is still one thing I don't understand.
I realize I should have one set of images, for the highest resolution 2560x1440 (For preventing ugly scaling up not vector images).
I'm using TexturePacker to pack my images and even using linear linear to get max quality:
TexturePacker.Settings settings = new TexturePacker.Settings();
settings.filterMin = Texture.TextureFilter.Linear;
settings.filterMag = Texture.TextureFilter.Linear;
settings.maxWidth = 4096;
settings.maxHeight = 2048;
TexturePacker.process(settings, inputDir, outputDir, packFileName);
I've set my camera, as recommended in several SO's, to fixed meters and avoid all the PPM stuff. From Screen's C'TOR:
mCamera = new OrthographicCamera();
mCamera.viewportWidth = 25.6f; ; // 2560 / 100
mCamera.viewportHeight = 14.4f ; // 1440 / 100
mCamera.position.set(mCamera.viewportWidth / 2, mCamera.viewportHeight / 2, 0f);
mCamera.update();
As you can see I chose to work with 1 meter = 100 pixels.
Now, that means I should draw my sprites with a 1/100 size, which i'm doing here:
TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("images/pack.atlas"));
mImage = atlas.createSprite("image"));
mImage.setSize(mImage.getWidth() / 100 , mImage.getHeight() / 100);
This works and the images are displayed as intended. BUT, they are distorted as hell! a perfectly round image looks pixelated on the edges and not round.
So, my questions are:
Is this the best practice or should I work differently?
Am I correct having only the highest quality images?
Is the distortion means that my code is really scaling down the sprite and somehow libgdx has scaled it up again and damaged the quality?
Thanks!
EDIT
I'm gonna adapt #Tenfour04's answers to (1) and (2).
Regarding (3), the problem is with Genymotion :( , its pixelating the game. I've test it on real devices with several resolutions and it looks perfect.
You have one error in setting up your camera: You assume that the screen is always the same aspect ratio, but in reality it will vary. It's better to pick a constant height or width (choose based on the type of game you're making) and adjust the opposite dimension based on the aspect ratio of the current screen. For example:
mCamera.viewportHeight = 25.6f; //game screen always 25.6 meters tall
mCamera.viewportWidth = 25.6f / (float)Gdx.graphics.getHeight() *
(float)Gdx.graphics.getWidth();
"I should have one set of images for the highest resolution" This is not necessarily true. If you do this, you will have to load very high resolution images on devices that can't take advantage of them. This will use a lot of memory and inflate load times. It may be fine during development, but down the road you will probably want to have two or three different smaller resolution versions that you can selectively load.
For this reason, I also would avoid hard-coding that 100 everywhere in your code. Make pixelsPerMeter a variable that is set once when the game starts up. For now it can just be 100, but if you decide to make some smaller resolution art later, you can adjust it accordingly then without having to find all the occurrences of 100 in your code.
Your min filter should be MipMapLinearLinear or MipMapLinearNearest. Otherwise, performance will suffer when sprites are drawn smaller than their native resolution, and may look distorted as you described. You can look up mip mapping to see why this is the case.

Cocos2d-x: how to make full screen background?

In my cocos2d-x game, my design resolution is 768x1024 (portrait), and I using "kResolutionShowAll" strategy (since I want to obey assets ratio). On some screen resolutions (e.g. Windows 8 PC 1920 x 1080), I have black borders on the sides.
I want to avoid these borders. My idea is to place some image as a background and to stretch it in order to fill the whole screen, and this way to avoid black borders (so, the scene should be rendered on top of that background).
My question is: how to do that? No matter how I trying to scale my background image, it always rendered within display resolution...
Thanks!
First thing first, find out the max resolution of the device family you are targeting. For example, if you are targeting Android family then the max resolution is >>> 2560x1600 (nexus series)
You can create your assets in this resolution then scale them according to different aspect ratios of devices (the scaling strategy, which in your case would be "kResolutionExactFit")
Btw, there is no harm in showing borders, several games do that. When we faced this issue, we applied the same strategy as I mentioned above(2560x1600 resolution images, with kResolutionShowAll strategy) Also, we set "setDesignResolutionSize" to "(1600, 2560)"
So, on 2560x1600 res. devices it fit well, but on 1920x1080/1280x720 devices there were borders. Please note that images that large can also result in a black screen when rendered, i.e, if a device is incapable of rendering an image(image greater than maxtexturesize of the device), cocos2dx won't render it.
In this case you can use,
CCConfiguration* conf = CCConfiguration::sharedConfiguration();
conf->getMaxTextureSize() // to check if a device is capable of rendering such image, if not you can use a lower resolution version
Or, you can also have 2 diff design resolutions.
Having said that, if you stick with "kResolutionShowAll", your game might look stretched. Just for reference, I have shared the definitions of different strategies;
kResolutionShowAll
According to the width and height of screen and design resolution to determine the scale factor, choose the smaller value of factor as the scale factor. This can make sure that all the design area can display on screen, but may leave some area black on screen.
kResolutionExactFit
Set the width ratio of the screen and design resolution as scale factor in X axis, set the height ratio of the screen and design resolution as scale factor in Y axis. This can make sure the design area cover the whole screen, but the picture maybe stretched.
kResolutionNoBorder
According to the width and height of screen and design resolution to determine the scale factor, choose the larger one as the scale factor. This can make sure that one axis can always fully display on screen, but another may scale out of the screen.
taken from,
http://www.cocos2d-x.org/wiki/Detailed_explanation_of_Cocos2d-x_Multi-resolution_adaptation

Supporting Multiple screen sizes Android AIR by making stage MAX resolution

Hey everyone so this is not a duplicate! The question I have is if i make the stage width and height of my Android AIR 4.0 Application using FLASH CS6 to say 1080x1920 and make all my movieClips etc... fit the stage. Will it then be able to fit all lower screen sizes and scale automatically? instead of having to create multiple XML files and create a different size image for all available screen sizes?
I don't know a really good method of doing this, so i thought that this might be a logical approach since it's the largest possible already can't it just shrink down to all devices? I tested on my small screen and the only problem I am having is it not filling the whole width of the screen.
But then I Add this line of code in my Constructor and everything fits perfectly:
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.EXACT_FIT;
stage.displayState = StageDisplayState.FULL_SCREEN;
Any thoughts?
If you follow the Flex model, it's the other way around. Flex apps are generally built for the lowest screen density (not resolution) and scale upwards. The sizing and placements respond naturally to the screen size. At each screen density range, a new set of images are used and a new multiplier is used for all of the sizes and positions.
So let's look at it this way. In Flex, there are a set of DPI ranges. 120 (generally ignored), 160, 240, 320, 480, and 640. Every device uses a single one of those settings. Take the iPhone. You build for 160, but the iPhone is 320dpi. So all of the values you use, built for 160dpi, are doubled for your app on the iPhone. You use images twice the size, too.
For most of my apps, I have at least four different sizes (one each for 160, 240, 320, and 480 dpi ranges) of every single image in my project. The images only scale if I don't have an image for the dpi range. The goal should be to never scale any images, up or down. In each range, the images remain the same size at all times and the only thing that changes is the positioning of them.
Now, I've used Flex as my example here, since the layout engine it uses is extremely thorough and well thought out, but it is entirely possible to build a simple system for this in AS3 as well (I did it last year with relative ease).
The biggest thing you need to do is forget about screen resolution. In this day and age, especially with Android where there are hundreds of different screens in use, screen size and resolution are irrelevant. Screen density, on the other hand, is everything

Images pixelated in higher resolutions

I'm developing a game using libGDX framework but I have some problems trying to adapt it to different resolutions. I'll give an example of the problems I'm having.
I use Scene2D to show a simple menu. That menu have some buttons with textures loaded from a texture atlas (button textures are 9patch). In desktop, with a resolution of 800x480 the buttons look nice (even the BitmapFont) but in Android, where I use setViewport to keep the width (800px) but scale the height keeping the aspect ratio, I get pixelated images. I think that this is because my mobile higher resolution. The whole stage must be scaled to fit so the images appear pixelated.
So, my question is, what is the best way to solve this? How can I support different resolutions without end with a pixel art look?
What resolution is the android device you tested it on? You said you've used 9-patch images. This should not produce pix-elated results unless your setting them to a size and then modifying their scale(difference between screen resolution and viewport size). If you don't want any scaling you should use your screens width or height for the viewport and calculate the other one by keeping your aspect ratio. This means that you'll have to build all your object's sizes at runtime based on your new viewport.
There isn't a one way fit all solution for such problems so you'll have to find which one suits your app. You can define your button sizes as % of screen's width or height; Or set them to a fixed value and adjust the spaces between them; or a combination of both(make an object partially bigger and modify the space between them).