So I need to resize my sprites with respect to the phones screen size,
I do the following:
final Display display = getWindowManager().getDefaultDisplay();
cameraWidth = display.getWidth();
cameraHeight = display.getHeight();
//check to load male or female
Intent sender=getIntent();
String extraData=sender.getExtras().getString("char");
if(extraData.contains("1"))
{
isMale = 1;
}
else
{
isMale = 0;
}
mCamera = new Camera(0, 0, cameraWidth, cameraHeight);
return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE,
new RatioResolutionPolicy(cameraWidth, cameraHeight), mCamera)
.setNeedsMusic(true).setNeedsSound(true));
However, for sprites, ie the player and enemies, I give them an arbitrary size such as 50 pix by 50pix - Now on small screens they appear really large! how can I resize them with respect to the screen size?
Also, These images are loaded from assets folder, so they have nothing to do with HDPI and LHPI image folders.
Thanks in advance community.
You should either use SVG graphics that are scalable on different device screens.
What i would suggest is you set the CAMERA_WIDTH and HEIGHT to a screen size no matter what size device it is on.
For example, for a project i am making i have a camera width and height of 800x480.
This way you dont have to worry about resizing any sprites. They all appear the same on each device while scaling up by the engine with the RationResolutionPolicy.
This is the best way to go about this.
If you set the screens size based on the device you will have to supple different graphics for each.
So i would recommend using SVG graphics so that when the images are scaled up automatically by the engine they dont loose quality. OR you can use png's and make them large, that way they will only be scaled down. And as you know they wont lose image quality by scaling down.
Related
I am working on my first libgdx app, a game. I have made some apps in IntelliJ before, but this is different. I am struggling with how my game will look over several devices, how to make everything scale appropriately.
If you can take a look at how I have it now, and maybe help me understand how it 'should' be to get the most out of it?
I have three classes, 'MyGame', 'MainMenuScreen' and 'GameScreen'.
// MyGame.java
WIDTH = Gdx.graphics.getWidth();
HEIGHT = Gdx.graphics.getHeight();
// MainMenuScreen
public void show(){
WIDTH = Gdx.graphics.getWidth();
HEIGHT = Gdx.graphics.getHeight();
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
}
// GameScreen
public void show(){
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
}
So, the 800, 480 is pixels, lets say I want to add something to this, and make it 32x32px (height, width), will it look the same on all devices? Bigger on large screens, and smaller on small screens, but always relevant to, lets say a background that is 800x480px?
I hope you understand what I am getting at. I posted the code I thought was relevant to the question, if u want more code, just say so, just tell me what you need.
My application needs to capture some pictures of a given size (lets say WxH) in a portrait orientation mode.
In a general case the size WxH I want is not supported by the camera therefore I will need to crop the captured picture in order to match my specifications.
This apparently simple program is driving me crazy for the problem of "good" corrispondence among preview and picture sizes and format.
Let me explain:
I need a format (let's give some numbers: 800x600) for the output image, and I have to take pictures in a portrait screen orientation. My camera by default is in Landscape mode therefore it takes pictures with a Width much larger than the height. But since I want a portrait preview I need to rotate the image and as a consequence I get images with an height much larger than the width (the transpose of the original image I guess).
In this scenario I need to cut a horizontally extended rectangle from a bigger vertically extended rectangle and I would like to do that by having an accettable large preview.
the problem of cropping the out image from the picture does not scare me (for the moment), the mean problem is the matching among what the user sees into the preview and what the camera actually captures.
for each possible phone I need to:
- chose a suitable camera picture size with respect the desired image format
- chose a suitable camera preview size with respect to the picture size and format.
- hide the preview parts that will be cropped.
And with the constraints of no distortion and large preview.
How to do it in general?
What I thought and tried:
the main algorithm steps are:
- get the optimal picture size once known the desired format
- get the optimal preview size once known the picture size
- hide the parts not capturable of the preview
- crop the image
tried method 1)
A) I get the optimal picture size by minimizing the area difference (I could also check the aspect ratio affinity is not very important). (Size is a custom type different from Camera.Size)
public Size getOptimalPictureSize(List<Camera.Size> sizes) {
Size opt = new Size();
float objf = Float.MAX_VALUE;
float v;
for(Camera.Size s : sizes){
if(s.height<target_size.width || s.width<target_size.height)
continue;
v = (s.height-target_size.width)*s.width + (s.width-target_size.height)*target_size.width;
if(v<objf){
opt.width=s.width;
opt.height=s.height;
objf=v;
}
}
return opt;
}
B) I get the optimal preview size by finding the best compromise among different aspect ratio (with respect to the picture size) :
#Override
public Size getOptimalPreviewSize(Size picSize,List<android.hardware.Camera.Size> sizes) {
Size opt = new Size();
double objf = Double.MAX_VALUE;
double aspratio = picSize.getAspectRatio();
double v;
for(Camera.Size s : sizes){
v = Math.abs( ((double)s.width)/((double)s.height) - aspratio )/(Math.max(((double)s.width)/((double)s.height), aspratio));
if(v<objf){
objf=v;
opt.width=s.width;
opt.height=s.height;
}
}
return opt;
}
C) hiding methods for displaying only capturable parts....(discussed later)
** Trial 2) **
A) I get the picture and preview sizes by minimizing an optimality functions that weights at the same time the misfit among camera image aspect ratio and desired one and the misfit among the preview and picture aspect ratio.
public void setOptimalCameraSizes(List<Camera.Size> preview_sizes,List<Camera.Size> picture_sizes,Size preview_out, Size picture_out) {
double objf=Double.MAX_VALUE;
double tmp;
for(Camera.Size pts : picture_sizes){
for(Camera.Size pws : preview_sizes){
tmp = percv(((double)pws.height)/((double)pws.width),target_size.getAspectRatio())
+ percv(((double)pws.width)/((double)pws.height),((double)pts.width)/((double)pts.height));
if(tmp<objf){
preview_out.set(pws.width, pws.height);
picture_out.set(pts.width, pts.height);
objf=tmp;
}
}
}
}
where
percv(a,b) = |a-b|/max(|a|,|b|) measures the relative deviation (and thus is dimensionless).
C) some hiding methods...
Ok this two sizes selection methods are the best I found and chose good sizes, but they have a physiological problem that comes from the camera landscape orientation... they can only produce vertical rectangular images and this implies that when I draw the preview I can get two cases:
1. I set the surface dimensions so as not distort the preview image -> due to the huge height this reflects in a very small valid area in which the image is visible (so the user experience is hurted)
2. I set the maximum possible width -> I can obtain (it depends on the preview aspect ratio) distorted previews but much bigger than in case 1.
How to avoid these problems??
What I though is work on phase C) of the algorithm (hiding phase) and I tried to:
trial 1: make the camera preview go beyond the screen sizes. This will allow me to make an arbitrary zoom in the area of interest and make the screen crop the preview. I tried using a scrollview but it didn't work and I don't know why. The topology was simple a root scrollview and inside a FrameLayout with the attached surfaceview but the surface always filled the screen leading to horrible distortions.
trial 2: capture the camera frame and manipulate them directly by overriding the onPreviewFrame(.) method: I got a misteryous error in locking the canvas (IllegalArgumentException)
How can I solve this?
I'm starting with AndEngine following this tutorial:
http://www.matim-dev.com/full-game-tutorial---part-1.html
But this guy looks like it's using a low resolution device for this test, I'm using a Galaxy S4 with a 1920x1080 resolution, yeah, damn high.
I know the thing about the RatioResolutionPolicy, but even though I'm using 800x480 in my S4 I got 2 white stripes from both sides (LANDSCAPE) like if it wasn't good resized, do I need to include another wallpaper for very high screen resolution devices?
Also, some coordinates that this guy used on the tutorial are bad placed on my S4, How am I supposed to make all devices compatible with this?
ADDING CODE:
private static int CAMERA_WIDTH = 800;
private static int CAMERA_HEIGHT = 480;
#Override
public EngineOptions onCreateEngineOptions() {
camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.camera);
engineOptions.getAudioOptions().setNeedsMusic(true).setNeedsSound(true);
engineOptions.setWakeLockOptions(WakeLockOptions.SCREEN_ON);
return engineOptions;
}
Your problem is not the resolution, but the ratio. your camera has a ratio of 1.66, while your device has a ratio of 1.77, that is almost the same, but not the same.
You Need to calculate the ratio. Andengine will project the camera in any device, that's the magic of opengl and the camera, but if the ratio is not the same, it has to put that lines to avoid the image to be cropped or distorted, like when you see a 4:3 movie in a 16:9 tv
The solution would be to have a camera that has the same ratio has the device, so if the ratio is different, you dont have white stripes, but for example some extra background.
For example, in your case, you get the device size, get the ratio (1920/1080=1.7777) so you create a camera with that ratio. ie:
float device_ratio = DEVICE_HEIGHT/DEVICE_WIDTH;// in this case 1.7777
CAMERA_WIDTH = 800;
CAMERA_HEIGHT = 800/device_ratio ; /// this will be 450
So, you will have a camera of 800x450, and you can have backgrounds of that size (or some bigger that you can crop). This is, you don't have to use images of the full size of the device, but just create a camera of the same size of the device, and create backgrounds that look ok in that camera. You create your world in that 800x450 "canvas", and andengine will project it in the real device. Since the ratio is the same, everything will look ok. nothing cropped, nothing distorted, and no extra lines.
Now you has to think in a more relative way, since your camera will not be always be exactly the same, depending on the device. This is straightforward if you don't have many hardcoded values.
I have a game what I made in 480x320 resolution (I have set it in the build settings) in Unity. But I would like to publish my game for every Android device with every resolution. How can I do it, to tell Unity to scale my game up to the device's resolution? Is it possible to do?
Thanks in advance!
The answer to your question largely depends on how you've implemented the game. If you've created it using GUI textures, then it largely depends on how you've placed/sized your objects versus screen size, which makes things a little tricky.
If the majority of your game is done using objects (such as planes, cubes, etc) then there's two methods I usually choose to use.
1) First method is very easy to implement, though doesn't always look too good. You can simply change the camera's aspect ratio to match the one you've designed your game around. So in your case, since you've designed your game at 4:3, you'd do something like this:
Camera.aspect = 4f/3f;
However, if someone's playing on a screen meant for 16:9, the game will end up looking distorted and stretched.
2) The second method isn't as easy, requiring quite a bit of work and calculations, but will give a much cleaner looking result for you. If you're using an orthographic camera, one important thing to keep in mind is that regardless of what screen resolution is being used, the orthographic camera keeps the height at a set height and only changes the width. For example, with an orthographic camera at a size of 10, the height will be set to 2. With this in mind what you'd need to do is compensate for the widest possible camera within each level (for example, have a wide background) or dynamically change the Orthographic Size of the camera until its width matches what you've created.
If you've done a 3d game with a stereoscopic camera , screen resolution shouldn't really affect how it looks, but I guess that depends on the game, so more info would be required
The way i did is to change camera viewport according to device aspect ratio
Consider you made the game for 800x1280
The you can do this in any one of the script
float xFactor = Screen.width / 800f;
float yFactor = Screen.height / 1280f;
Camera.main.rect=new Rect(0,0,1,xFactor/yFactor);
and this works like magic
A easy way to do this is considering your target, I mean if you're doing a game for Iphone 5 then the aspect ratio is 9:16 v or 16:9 h.
public float targetRatio = 9f/16f; //The aspect ratio you did for the game.
void Start()
{
Camera cam = GetComponent<Camera>();
cam.aspect = targetRatio;
}
Here is my script for scaling the ortographic camera in 2D games
public float screenHeight = 1920f;
public float screenWidth = 1080f;
public float targetAspect = 9f / 16f;
public float orthographicSize;
private Camera mainCamera;
// Use this for initialization
void Start () {
// Initialize variables
mainCamera = Camera.main;
orthographicSize = mainCamera.orthographicSize;
// Calculating ortographic width
float orthoWidth = orthographicSize / screenHeight * screenWidth;
// Setting aspect ration
orthoWidth = orthoWidth / (targetAspect / mainCamera.aspect);
// Setting Size
Camera.main.orthographicSize = (orthoWidth / Screen.width * Screen.height);
}
I assume it's 2D instead of 3D, this what I do:
Create a Canvas object
Set the Canvas Scaler to Scale with Screen Size
Set the Reference Resolution to for example: 480x320
Set the Screen Match Mode to match width or height
Set the match to 1 if your current screen width is smaller (0 if height is smaller)
Create an Image as background inside the Canvas
Add Aspect Ratio Fitter script
Set the Aspect Mode to Fit in Parent (so the UI anchor can be anywhere)
Set the Aspect Ratio to 480/320 = 1.5
And add this snippet on main Canvas' Awake method:
var canvasScaler = GetComponent<CanvasScaler>();
var ratio = Screen.height / (float) Screen.width;
var rr = canvasScaler.referenceResolution;
canvasScaler.matchWidthOrHeight = (ratio < rr.x / rr.y) ? 1 : 0;
//Make sure to add Using Unity.UI on top of your Aspect Ratio Script!
For 3D objects you can use any of the answers above
The best solution for me is to use the theorem of intersecting lines so that there is neither a cut-off on the sides nor a distortion of the game view. That means that you have to step back or forward depending on the different aspect ratio.
If you like, I have an asset on the Unity asset store which automatically corrects the camera distance so you never have a distortion or a cut off no matter which handheld device you are using.
I am developing a game using a surface panel. I've done a lot of research about how to properly scale and position drawables in the canvas for multiple devices and I came up with a solution that is working fine on phones but has some flaws when I try it on tablets. I am aware that I can use different resources for tablets (and i might end up doing that) but let's assume for now that I don't want to do it, I want to use the same resources for every single different phone in the market.
All the resources that I have are located it in the hdpi folder, and they are properly sized for a 480x800 device.
My approach is similar to the one described here, please take a look on the explanation below, and I would like to know if there is a better solution for this problem!
I have a Galaxy S2 for testing my apps. So my first approach was to manually insert position everything directly in the canvas by trying and finding the best position for everything. Taking the first character position as an example:
draw_x = (float) (19);
draw_y = (float) (279);
canvas.drawBitmap(toDrawBitmap, draw_x, draw_y, null);
When I first tested it in different devices, everything as a mess, out of scale. So digging around I thought about using the density for scaling the resources.
// I am dividing by 1.5 because my initial positions are on a high density device
// so when it goes for a medium density it should scale for 0.66 and a small density
// for 0.5 of my positions.
float scale = getResources().getDisplayMetrics().density /1.5;
draw_x = (float) (19) * scale;
draw_y = (float) (279) * scale;
canvas.drawBitmap(toDrawBitmap, draw_x, draw_y, null);
And at first impression this worked like a charm. It all my characters were in the proper positions. But I noticed that if the device has a different scale widht/height compared to the Galaxy S2 that I am using the problems begin. Although everything was properly positioned part of the image was cut out of the screen, the canvas was calculated larger than the phone screen.
Galaxy S2 is 480x800. My background is also 480x800. When I tested it in the emulator on a small screen resolution 320x480 Android didn't scale my background correctly as I expected it to do so. Instead of scaling it for the right resolution it gave me a background larger than my canvas 320x533.
With some simple math we figure that 320x533 / 480x800 = 0.66. So instead of properly scaling the background in the canvas, it just scaled using the density of the devices.
So my workaround for this problem was the simplest I could think of. I know the resolution of my background, I know the resolution of the phone, so I can calculate the proportion I need and force a resize.
//Set the proportions for scaling in multiple devices
public void setProportions(float screenWidth,float ScreenHeight,Bitmap background){
this.heightProportion = ScreenHeight/background.getHeight();
this.widthProportion = screenWidth/background.getWidth();
}
public Bitmap scaleBitmaps(Bitmap bitmap) {
Bitmap out = Bitmap.createScaledBitmap(bitmap, (int) (bitmap.getWidth() * widthProportion),
(int) (bitmap.getHeight()*heightProportion), false);
return out;
}
That worked fine for the sizes of the drawables, so I just needed to do the same for the positions, using the scale and this new Proportion I was able to calculate using a fixed size background image
public float convertX(float x){
return x* scale * widthProportion;
}
public float convertY(float y){
return y* scale * heightProportion;
}
//calculate the positions applying the scale and the proportion
draw_x = convertX((float) (19));
draw_y = convertY((float) (279));
//draw the bitmap with the scaled position
canvas.drawBitmap(toDrawBitmap, draw_x, draw_y, null);
Long story short, to properly position the drawables I manually set the desired position in my device, calculated a scale between the densities and a porportion between the background image size and the screen size.
To re-size the drawables I just used the proportion because android automatically applies the density scale.
I tested in several different phones and tablets and this approach works perfectly for phones. On tablets it gives me some minor mistakes in the re-sizing of the drawables.
Finally after all this, my question is, what is the problem with this solution? Can I make it work on every phone regardless of the size or there is a better solution for this?
Please note that this strict to Canvas. The same background is re-sized correctly for every phone if I use it in the XML layout. If I wasn't clear or I should give more information please let me know!
The first thing you have to know before solve this problem is about device phone running system. Though you suggest the phone will choose either hdpi or other versions, it depends on each phone running system.
A. Size fitting problem
The problem is how do you process the bitmap. Though you re-scale the bitmap with any math formula, the size of original bitmap will have different output for each different phone. To solve this, you have to set inScaled of bitmap to false.
B. Position fitting problem
Thus you have the problem in fitting the size of bitmap, the position of bitmap will synchronize the position depends on your phone screen size. You should define the background object and positioning the object x and y based on the background. For example if you want to put an object in the middle of phone screen no matter what phone we use it, the code must be `
canvas.drawBitmap(toDrawBitmap, background.getwidth()/2, background.getheight()/2, null);
to solve the fitting position problem.
Let me know what happen.