Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pixels to dips, desktop and android

I am using Libgdx to code an android game and as you may know, many screen resolutions cause some problems if done incorrectly. So I am trying to use this DP unit rather than pixels.

However, I have this method here:

public static float pixelToDP(float dp){
    return dp * Gdx.graphics.getDensity();
}

the Gdx.graphics.getDensity() method actually gets the SCALE, so it's already done for me.

Now the problem, libgdx is cross platform which is good for testing. When I launch this on my S4 which has a resolution of 1920x1080 with a dpi of a whopping 480, opposed to my terrible and overpriced laptop which has 1366x768 @ 92dpi it is placed exactly where I want it. On desktop it is way off, a good few hundred pixels on the X and Y axis.

Is this due to the fact my screen dpi is measured @92dpi, the resolution is a lot lower and the actual game is not fullscreen on the desktop?

Here is the code for drawing the object:

table.setPosition(MathHelper.pixelToDP(150), MathHelper.pixelToDP(200));

In order to get it perfect on desktop I have to do:

table.setPosition(MathHelper.pixelToDP(480), MathHelper.pixelToDP(700));

Which is not even visible on my phone, since the scale is actually 3x, which puts it a good 200 pixels off the screen on the Y axis.

Is there a way around this? Or am I basically going to have to deal with doing platform checks and different blocks of code?

Possible solution:

So I changed my dp conversion method, if I was to do 100 * 0.5 it would return a new value of 50 but in reality I want the orignal value of 100 + 100 * 0.5.

Not sure if this is a proper fix or not but regardless by table is drew in the exact same place on both laptop and phone:

public static float pixelToDP(float dp){
    if(Gdx.graphics.getDensity() < 1)
        return dp + dp * Gdx.graphics.getDensity();
    return dp * Gdx.graphics.getDensity();

Is this just a cheap fix or is this pretty much how it should be done?

like image 940
Gibbo Avatar asked Dec 13 '13 16:12

Gibbo


People also ask

What is 4x pixel density?

In 4x screen (~640 DPI) it takes four times as many pixels (352 x 144 PX) to fill the area of 88 x 36 density-independent-pixels.

How many pixels is 1dp?

If device-independent pixel (dp) is used as the unit of length, then the operating system of the device maps the dp value to a corresponding number of pixels based on the resolution of the device screen. For this mapping, 1 dp is considered to be equal to 1 pixel on a 160 dpi resolution screen.

What is the best image size for Android?

The best image resolution for most smartphones is 640 by 320 pixels, although you should ideally maintain the aspect ratio of the original image or the output image will be distorted.

What is dp and px in Android?

Pixels - corresponds to actual pixels on the screen. dp or dip. Density-independent Pixels - an abstract unit that is based on the physical density of the screen. These units are relative to a 160 dpi screen, so one dp is one pixel on a 160 dpi screen.


3 Answers

Usage of density independent pixels implies that the physical size of the table on all screens should be same. Since your laptop screen is (physically) much bigger, you would see the table to be lot smaller than expected.

I would suggest an alternative approach of placing objects in fractions of size. e.g. 30% of width or 45% of height.

To implement this, just assume a stage resolution and place objects as you like then change viewport in resize method such that you get full view. Hope it helps.

For more, https://code.google.com/p/libgdx-users/wiki/AspectRatio

like image 165
Tanmay Patil Avatar answered Sep 16 '22 21:09

Tanmay Patil


The best approach for this is to manipulate the density based on the execution target.

So what I usually do is to store the density in a field in a singleton, and set it based on the scenario:

public class Game {

 public static float density;

  public static initDensity(){
    if (GDX.app.getTarget() == 0){
      density = 2.0f;
    }else {
       density = GDX.graphics.getDensity();
    }
  }

  public float toPixel(float dip){
    return dip * density;
  }
} 

with this approach you can "simulate" a more dense screen then you actually have, and by using properties in your run config like -Ddensity=2 and System.getPropery("density") you can vary the screens you like to simulate.

like image 31
joecks Avatar answered Sep 19 '22 21:09

joecks


One approach is having a fixed viewport size. Create your camera for example 1366x768 and place all your objects using that coordinate. Then the camera will fill the whole screen of every other resolution.

cam = new OrthographicCamera(1366, 768);
like image 35
Lestat Avatar answered Sep 16 '22 21:09

Lestat