So, LibGDX rants in a bunch of tutorials about how it is not recommended to use device pixels as coordinates in your world. I can understand the logic and it seems reasonable, so I am updating my camera code to do this:
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
aspect = h / w;
camera = new OrthographicCamera(1.0f, aspect);
camera.setToOrtho(true, 1.0f, aspect);
However a large part of what I do is working with fonts. Currently my font loader looks like this:
glyphLayout = new GlyphLayout();
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("myfont.ttf"));
FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
parameter.size = 100;
parameter.characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.!'()>?:";
parameter.flip = true;
font = generator.generateFont(parameter);
This results in huge sized fonts. I am confused by the apparently conflicting coordinates systems in LibGDX - why do they not recommend using pixels, and yet all font functions deal with pixels?
How can I update this font loading code, so I get fonts which are approximately 20% of the screen size?
You can develop for one resolution (using viewports) and set your preferred font size.
At runtime, you can scale your font size based on the new screen width.
1920x1080, parameter.size = 16 => 1280x720, parameter.size = 16 / 1920 * 1280
Also, with distance field fonts, you can render smooth fonts without using the font ganerator at runtime.
Related
I have an issue with the libgdx ttf font generator. No matter what I try, I get the font pixelated. This is what I have right now that minimizes but makes it still visible:
FreeTypeFontGenerator.FreeTypeFontParameter parameter;
FreeTypeFontGenerator generator;
parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
parameter.minFilter = Texture.TextureFilter.Linear;
parameter.magFilter = Texture.TextureFilter.Linear;
generator = new FreeTypeFontGenerator(Gdx.files.internal(Constants.ROBOTO_CONDENSED_BOLD));
parameter.size = Constants.SELECTION_DESCRIPTION_FONT_SIZE;
parameter.color = Constants.GARAGE_FONT_COLOR;
generator.scaleForPixelHeight(Constants.SELECTION_DESCRIPTION_FONT_SIZE);
descriptionFont = generator.generateFont(parameter);
generator.dispose();
Is it possible that the camera I am using is 854x480 per say, but the screen size is 1920x1080 that causes the pixaltion?
The problem does indeed lie within the resolutions. My hud camera was converting to 854 - 600 width range and height accordingly. Having a screen with resolution 1920x1080 makes the font considerably pixelated with spritebatch being set to hud camera with twice the lower resolution.
I'm using multi resolution technique number three as written in this article
and to determine the scale factor and stage size, I'm using this piece of code originally written by Jeff :
if (Capabilities.screenDPI >= 200) {
if (Capabilities.screenDPI >= 280) {
AssetFactory.contentScaleFactor = 2;
}
else {
AssetFactory.contentScaleFactor = 1.5;
}
}
else {
AssetFactory.contentScaleFactor = 1;
}
var mViewPort:Rectangle = new Rectangle(0, 0, stage.fullScreenWidth, stage.fullScreenHeight);
mStarling = new Starling(Startup, stage,mViewPort);
mStarling.stage.stageWidth = stage.fullScreenWidth / AssetFactory.contentScaleFactor;
mStarling.stage.stageHeight = stage.fullScreenHeight / AssetFactory.contentScaleFactor;
Then I use this scale factor to determine which sized assets I need to pick.
So now, I have a background which I strech to stage width and size. This technique works great when I'm testing with most devices but then we have devices like the Barnes and Noble Nook Color.
The device has a resolution of 600x1024 with 170 dpi. This means that it's going to pick the smallest assets (320x480) and strech it to 600x1024. Which ofcourse is pixalated. Any ideas on how to get over this issue?
I'm also attaching a test application which shows the issue in detail https://dl.dropbox.com/u/2192209/scaling%20test.zip
What worked for me best so far is not scaling Starling's viewport at all. It should always remain the base size (320x480).
Then you have a scale factor about how big the texture should be. It's a built feature of Starling when creating a texture - passing a scale factor.
What this means is that if your stage is 640x960, your scale factor will be 2. Your image (Bitmap object), will have ACTUAL SCREEN size of 320x480 (fullscreen, 1:1 with stage size), BUT it's texture (loaded asset BitmapData) will be twice as big (640x960, 1:1 with phone size).
For easier understanding - the stage of Starling (320x480) will be scaled up to fit your phone's resolution (320 -> 640). But your images will be scaled down to fit in the stage (640 -> 320). So you get perfectly normal images.
This helps you maintain fixed size of stage. It's really helpful, because otherwise it would be hard to position objects - if you want the object to be in the middle, it's sometimes 160, sometimes 320, etc. This means you always have to set position/size with calculations, which is an overload.
Hope that helps!
edit: Just remembered of a site I've used to determine my main size and assets ratios: http://screensiz.es/phone
How about setting max scale size? If the conclusion of the calculations above takes you to scale that is grater than 2, use bigger assets to reduce the scale ratio.
Your calculation only takes screenDPI in count, try combining them with screen resolution as well.
I am making a game using And Engine, when i tried to make it in generic way that works on all devices then i am in trouble...
I need to set a sprite on specific position of background sprite that should work on all screens... My background screen has same size as dimension of Device..
I tried to use pixel let say Glaxy S3 ha dimensions 720*1280
And i set according to it my sprite at location (584,608)
and my HTC experia ha dimensions (320,480)
SO i need to set it on (244,172) ....
I have tried all the following ways to set the position of sprites in generic way but not if any work...
I have tried alot of following things to make some formula that enables me to do it but unable to find any.. please advise
final Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
metrics.density;
metrics.densityDpi;
metrics.heightPixels);
metrics.scaledDensity);
metrics.widthPixels);
metrics.xdpi);
metrics.ydpi);
Point point = getDisplaySize(display);
CAMERA_WIDTH = point.x;
CAMERA_HEIGHT = point.y;
DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm);
double x = Math.pow(dm.widthPixels/dm.xdpi,2);
double y = Math.pow(dm.heightPixels/dm.ydpi,2);
double screenInches = Math.sqrt(x+y);
int widthPix = (int) Math.ceil(dm.widthPixels * (dm.densityDpi / 160.0));
//CAMERA_WIDTH = display.getWidth();
//CAMERA_HEIGHT = display.getHeight();
Problem is little bit complex.. As i told above I tried to use pixel let say Glaxy S3 ha *dimensions 720*1280 And required sprite location is (584,608)
so i set in manner ( CAMERA_WIDTH/1.233f,CAMERA_HEIGHT/2.112f)*
BUT HTC experia has dimensions *320*480 So the required positions according to ( CAMERA_WIDTH/1.233f,CAMERA_HEIGHT/2.112f) is (2599.5,227.27)*
but this wrong according to display...
when i set it on (244,172) for experia its working perfect.... please help.
AndEngine offers multiple resolution policies. They are used to determine the size of the RenderSurfaceView, thus the actual size of the game on the screen, depending on the screen size.
You should use RatioResolutionPolicy: It will use the largest possible size, while keeping a constant ratio between the width and the height. By keeping the camera's size constant, everything it shows will be scaled by this constant ratio which will vary on different devices.
Example: Let CAMERA_WIDTH = 720 and CAMERA_HEIGHT = 480. If we create the camera and the engine options this way:
this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
EngineOptions options = new EngineOptions(..., new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), mCamera);
The ratio is 720 / 480 = 1.5.
When placing a sprite on your scene, use constant coordinates. Let's say we place it in the middle of the screen:
Sprite sprite = new Sprite(CAMERA_WIDTH / 2, CAMERA_HEIGHT / 2, ...);
So:
On a device with screen size 720x480, the sprite will be placed at (360, 240) screen coordinates.
On a device with screen size 480x320, the sprite will be placed at (240, 160) screen coordinates.
On a device with screen size 800x480, the sprite will be placed at (400, 240) screen coordinates.
And so on...
While we're at it, what is the Android equivalent of [UIScreen mainScreen].scale?
Are the following equations correct?
[UIScreen mainScreen].bounds.size.width = displayMetrics.widthPixels
[UIScreen mainScreen].scale = displayMetrics.density
where you get displayMetrics like so:
DisplayMetrics displayMetrics = new DisplayMetrics();
Display display = ((WindowManager) someContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
display.getMetrics(displayMetrics);
The thing is that I'm confused by the wording for iOS versus Android.
The definitions for those UIScreen values are these:
bounds
Contains the bounding rectangle of the screen, measured in points.
(read-only)
scale
The natural scale factor associated with the screen. (read-only)
#property(nonatomic, readonly) CGFloat scale
Discussion
This value reflects the scale factor needed to convert from the
default logical coordinate space into the device coordinate space of
this screen. The default logical coordinate space is measured using
points, where one point is approximately equal to 1/160th of an inch.
If a device’s screen has a reasonably similar pixel density, the scale
factor is typically set to 1.0 so that one point maps to one pixel.
However, a screen with a significantly different pixel density may set
this property to a higher value.
I am wondering whether the width of the bounds is equivalent to the widthPixels of the DisplayMetrics and whether the scale value is equivalent to the density value on Android.
[UIScreen mainScreen].bounds.size.width = displayMetrics.widthPixels
Correct, width of the screen (display) in pixels, nothing complicated here.
[UIScreen mainScreen].scale = displayMetrics.density
Not really. They are similar values but definitely not equal.
I'll try to explain what scale is. We have iPad 1 with screen resolution 1024x768 and we have iPad 3 with double resolution (apple marketing calls it Retina) and we want applications to work on both devices. So, the application works on resolution 1024x768 (logical points) but the OS translates to physical pixels on every device using the scale (scale=1.0 on iPad 1, scale=2.0 on iPad 3).
For example, when you draw a rectangle in logical coordinates (1, 1, 20, 40), on iPad 3 it will be drawn on pixels (2, 2, 40, 80).
There are currently only two values defined: 1.0 and 2.0.
The density is a similar scaling factor but calculated differently
This is a scaling factor for the Density Independent Pixel unit, where one DIP is one pixel on an approximately 160 dpi screen
Note that again it converts logical points (called DIP on Android) into screen pixels.
The difference between iOS scale and Android density is that the logical unit is defined differently.
I use this:
private void SetScreenSizes() {
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
intScreenWidth = displaymetrics.widthPixels;
}
I have read the "screen support API guide "(http://developer.android.com/guide/practices/screens_support.html) and much more resources, but I cannot understand how the dpi works.
I'm developing a game, and I'm not using any layouts (I'm going to draw all myself with functions like canvas.drawbitmap). But when I use the Canvas.Drawbitmap function I need to specify the pixels of the screen where I want to draw the image.
So I'm working now with a fixed resolution (1280x800) and I'm using the drawable-nodpi folder and adjusting the canvas later if the screen of the phone is wider or narrow. The problem with that is that the images look horrible when the resolution is not the native one (1280x800).
What can I do to solve this problem? I've read and read during 3 days, but all explanations and examples are related to Layouts, Nine Patches and so.
Get the density of the device being used and multiply that density by some base size that you pick (how big or small do you actually want it to be drawn?)
Example:
float objectToDrawHeight = 50; //Specified in plain pixels
float objectToDrawWidth = 50; //Specified in plain pixels
float density = getResources().getDisplayMetrics().density;
objectToDrawHeight *= density;
objectToDrawWidth *= density;
//Draw your object using the new (scaled) height and width
//If you are worried about how the object will look on different aspect ratio devices
// you can get the screen dimensions and use that ratio as a multiplier
// just as you did with density
Display display = ((Activity)context).getWindowManager().getDefaultDisplay();
float screenDimensionX = display.getWidth();
float screenDimensionY = display.getHeight();
Using density and possibly screen dimensions should allow you to draw anything and keep it scaled correctly. When using canvas, assume everything is in pixels, and that you must do the dpi conversion.