Android game working on all screen sizes - android

I'm trying to specify the art sizes for an Android game with ~10 screens. I want the game to run on API 8+, and on all size screens except "small".
Since we're using API 8, I use the old "4 categories of screen" feature - I plan to support
normal (480 x 320, and up to 640 x 480)
large (640 x 480, and up to 960 x 720)
xlarge (960 x 720, and up to 1920 x 1200)
A 1920x1200 png file is ~4.1MB. So 10 of them is 41MB, and we've almost blown our 50 MB app size limit (Play Store).
So three questions:
1. how do people support detailed artwork for game screens? Do I have to use bland colored 9 patch pngs files for the backgrounds? Or is it feasible to store all art at the 960x720 size, and allow it to be resized by Android for large and normal screens? 10 background files of this size total to about 15 MB, which leaves 35 MB for everything else.
What if I used jpgs instead of pngs? How much quality would I lose? Since I would only ever be downsizing, this should be OK, right? 10 jpgs of 960x720 is only 4.3MB.
If I allow Android to resize it, how do I support screens that have a different aspect ratio than the 4:3 of 960x720? Is there a way to specify in the layout XML "use the drawables from the large folder, but "letter box" it onto the screen, so that the longest dimension just fits" ? (And for xlarge screens bigger than 960x720, just put the drawable in the middle of the screen - don't stretch it at all)?
DPI resolution of the screen doesn't factor in this at all? DPI only needs to be taken into account when you want something to be roughly the same size on different res screens, like an icon or button. Correct?
Seems like this should be a solved problem with a well known pattern or template to follow. How have other people done it? Does everyone use either huge downloads post install (want to avoid) or 9 patch backgrounds?
Thanks in advance for any advice. I searched here on several terms, and looked at about 25 past answers, without finding what I am looking for.
Peter

Resurrecting the dead (thread): one way of doing things could be to provide just one set of bitmaps and do the scaling yourself. You can either provide large bitmaps and scale them down, or provide middle of the road bitmaps and scale them up (for large screens) and down (for smaller sizes).
The benefits of the former are that your art looks great on large screens and you are a bit more future proof (if you provide for this in your code). The downside is that you could (and actually likely will) run into Out Of Memory/Exceeding VM errors when decoding/loading these bitmaps on lower-end devices, even when doing it carefully. So I usually go for the second approach.
Scaling up can be done a number of ways, but one is to just load in the bmp at it's default size (use getResources().openRawResource(id) or BitmapFactory.decodeResource(etc) or even better use inputstreams or [according to some the best method] load/create using the FileDescriptor methods) and then scale it either by creating another bmp using createScaledBitmap() or if drawing to a canvas draw it to a destination Rectangle (better memory wise).
For scaling down you can either use BitmapOptions like .inScaled or, again, use a smaller destination Rect in your canvas drawcall.
Doing it this way is way better and (for a game) faster than letting Android scale for you using those buckets (hdpi etc) and uses less memory if done right.
But beware as some bitmap loading methods are a bit buggy and create 'the bmp is too big for the VM' errors. Also learn to dispose of your bmps properly; a lot of people and Google/Googlers say Android does this and you don't have to set your bmps to null and recycle() them, but so far I've found that you do. Another caveat is to set the proper options (filtering/antialiasing etc) to prevent blurry bmps. And take care of un-optimal color/format/dpi settings on BitmapOptions/canvasses/SurfaceViews and even windows.
There's much more, but this should help anyone get started.

Related

My app slows down when background image is added in the drawable folder

I have read on this forum that the answer is to split the image in different resolutions and put it in different folders and the other way is to put the image in one folder without splitting it up so that android doesn't resize it.
My question is in which folder exactly do we put it on so it doesn't resize itself and shows as it is?
My res folder looks like this
Based on your updated question with the image and the clarity.
You are asking how to avoid scaling. You can either use the drawable directory or the drawable-nodpi to avoid prescaling. Either one will work for you.
I made a document on this once for the UI team I was working with, so this document is a little specific to their request and that app, but it might help you.
https://drive.google.com/file/d/1gJjT-F5AU57TCAr5I18l0jAvNG5-vLUb/view?usp=sharing
For vector drawables just use "drawable" standard directory. Make sure you are not violating any of the unsupported tags such as gradients and linear tags or you will have issues.
Next the -24 -26, etc.. folders are used for version specific. For example, let's say you have one type of image for pre 24 Android, but a different type for post 24, you can use -24 for the post image, and all others will check standard folder for it. This sometimes happens when you use something bleeding edge that isn't supported back far enough for your app's minimum SDK. You are not likely to use this for images, I can't even think of a problem where this would arise in the image buckets, but it's there all the same.
For deciding what resolution you need for each bucket, there are a couple of options here. First you could simply do the math. Decide how many inches you want it to take up and determine how many pixels are needed to accomodate that size and label that MDPI, than scale from there using the multipliers. Another less mathematical solution would be to open a preview on Android select an MDPI device and start playing with width = 100px height = 100px and adjust until you like the size. Write that down, it is MDPI, and begin your scaling from there.
As for a rough estimate of pixels to size, you can see what an app icon looks like and see what Android uses for that below.
So even though each bucket has a different pixel by pixel resolution, they will be identical sized and pixels per inch resolution on all devices due to bucket placement.
Hopefully that all makes sense.
--I'll leave the below from the original answer in case it helps someone--
You may have gotten some bad information.
https://developer.android.com/training/multiscreen/screendensities
Android is a widely dispersed resolution and size market.
In order to accommodate this they allow for DP and Buckets.
There are buckets for languages, screensizes, orientation, and resolutions.
You are looking for resolution support.
drawable-ldpi -.75 multiplier on size (1dp = .75px)
drawable-mdpi -baseline 1dp = 1px
drawable-hdpi -1.5x multiplier on size (1dp = 1.5px
drawable-xhdpi -2x multiplier on size (1dp = 2px
drawable-xxhdpi -3x multiplier on size (1dp = 3px
drawable-xxxhdpi -4x mulipvlier on size (1dp = 4px
each bucket has a multiplier associated to help the image look the same approximate size on each device. So even though it is 1 inch by 1 inch on one mdpi phone with your 100px x 100px image (pseudo size, don't calculate it ;)
it will need to be 150px x 150px on the hdpi to have the same quality and resolution of pixels per inch.
Now if you put all your images in the drawable bucket. Android will just ignore the scaling of these and you end up with varying space consumption depending on the device which will be very inconsistent on how much space it takes up on each type of phone.
If you put all your images in the correct folder you will at least have better quality. For example, let's say you have maybe 750px x 750px image that is meant to fill up a 1 inch area. You would be better suited to put it in the XXHDPI folder or XXXHDPI folder so Android knows to scale it DOWN rather than UP. This will give you better resolution for each device resolution that it scales for.
However, this is still poor practice. You are relying on Android operating system which can be very slow and weak on many cheap devices to do your scaling for you. I would recommend using GIMP and scaling to each multiplier on your own, then putting it into the respective resolution buckets.
This way Android decides based on the device which bucket resolution image it needs which decreases the amount of scaling exponentially.
Now, if you have Vector Graphics that you have imported, those will end up in the drawable folder which tells Android to ignore the resolution, and just draw these as vector graphics. This is the best option in my opinion as you only need one set of images per image. Although, Vector graphics aren't quite as fast at loading as a JPG or PNG, but it keeps your package size down quite a bit and development maintenance is so much nicer.
Hope that helps.
Happy Coding.

Libgdx - Font that is smotth uses mega RAM

I have a viewport (360x640), but if I render fonts on that they are ugly. So I made higher size's and downscaled them. But now they go disoriented. (size == 30)
I made a 4x bigger viewport then so I didn't need to downscale them. But now my game instead of taking 15mb ram takes up 50mb. (size == 120)
And this is not acceptable. That my textures take 30x less ram than shitty 3 TTFs.
See https://github.com/libgdx/libgdx/wiki/Coordinate-systems#world-coordinates.
Use 2 viewports:
One which is near pixel perfect (around the same as the screen resolution of your reference target device), which you use only for the GUI like labels, buttons, etc.
And one which fits your game logic best (although 360x640 gives the impression you are using banana units (imaginary pixels), which you shouldn't do) and you only for rendering game objects and such.
Either way, the size of your assets (either on disk, in RAM or in VRAM) are not in any way related to the size of your viewport: when you change the size of your viewport then you should not scale your assets. The size of your assets should be around the same size as they are when they are projected on the screen. So it doesn't matter whether you use a viewport of 3 by 5 meters or a viewport 1440 by 2560 bananas. What matters is the size in pixels on the actual screen (e.g. take a screenshot and measure it). The size of the assets should be around that same size for best results.
If that means that you need a very large font, e.g. because you use a reference target device with a very high resolution (e.g. Retina Display), then that's how it is. You could work around that in several ways, e.g. by rendering to a smaller FBO, using texture filtering, etc. But reality is that devices with such large resolutions are equipped with at least enough memory to hold the assets for such resolution. So, in that case using more memory isn't really an issue.
If you like to target multiple resolutions which have different restrictions on the asset size then you can use multiple assets sets. For example by using ResolutionFileHandleResolver.
Although not related to your question, note that BitmapFont by default assumes a near pixel perfect projection and therefor uses integer positions to prevent aliasing. If you really don't want use a near pixel perfect projection then you disable that using the BitmapFont#setUseIntegerPositions method.

Android UI Images vs Layout xml

I am wondering what your thoughts are on which is the better strategy when designing UI for android devices.
Which do you preffer:
Setting the size of elements in the XML files, for each denisty (and size when needed), using only one set of images (xxhdpi images) which will scale down when needed.
Pros - smaller apps (less resources)
Less work on images for UI people.
Cons - more work on XML files (a whole lot sometimes)
Create images for each denisty (and size if neede) using Wrap_content most of the time.
Pros - Only one set of XML layout files.
Cons - more images and larger sized apk.
more work on images for UI people.
What other approaches are you using?
Thanks!
I think you are misunderstanding what Android is doing when it scales images that you do not provide. The Android docs state:
By default, Android scales your bitmap drawables (.png, .jpg, and .gif files) and Nine-Patch drawables (.9.png files) so that they render at the appropriate physical size on each device. For example, if your application provides bitmap drawables only for the baseline, medium screen density (mdpi), then the system scales them up when on a high-density screen, and scales them down when on a low-density screen. This scaling can cause artifacts in the bitmaps. To ensure your bitmaps look their best, you should include alternative versions at different resolutions for different screen densities.
All this means is that if you do not provide alternate density versions of images, Android will fill in the missing ones (created and the correct proportional size) using the ones you have provided, but at the cost of some quality of the image, since Android is not going to scale an image as well as say Photoshop. If you are concerned with application size, you can consider if the loss of image quality from omitting certain density versions is an acceptable tradeoff in order to make your .apk smaller.
So, #1 and #2 can both use wrap_content, and neither has to set the size of an image manually, unless the image needs to be larger or smaller than the original size (which in that case you should just create the image at the right size). #1 also does not and should not require more layout work. And for #2, saving an image at several sizes is not very much extra work at all.
I personally follow these rules:
Create images for every density (except ldpi / tvdpi - too few devices, I'm ok with the image quality loss on them).
Use wrap_content and match_parent as needed with images.
Only use dp for images downloaded at runtime, where size cannot be guaranteed.
my choice is a mixed one. I create differet images for those which are complex and has a chance of being abnormal for automatic compression. But for usual images I only used the first approach.

Android drawables DPI

I have an Android app with 4 versions of the same image, in each of these folders:
drawable-ldpi/
drawable-mdpi/
drawable-hdpi/
drawable-xhdpi/
The only difference between the images is the size, I simply took the original large image and scaled it down according to the formula:
120dp lpdi, 1 dp=0.75 px
160dp mpdi, 1 dp=1 px
240dp hdpi, 1 dp=1.5 px
320dp xhpdi, 1 dp=2 px
The problem is I intend to have over 100 images, so to reduce the file size can't I just put the xhdpi versions in the drawables/ folder instead of having 4 versions of each image, then Android can scale the image as required? What is the disadvantage of doing it this way? Is it simply a trade off between performance and file size?
You can just put the xhdpi versions in the drawable resources. Then in your layout/xml files specify the images dimensions in dp. Android will downscale your images accordingly. As long as you are downscaling the drawable resources quality of the image wont change.
having only the xhdpi resource will degrade A LOT your app performance. Plus on low-range devices (small screens and small memory) it's very likely that the VM will run out of memory and crash whilst processing those large bitmaps.
You can develop everything on your high end device and use a simple photoshop automation to create the other resources but it's better to have a bigger APK than your app not working on mid and low range devices.
Another option might be to export several APK (one for each screen type) and use the manifest to specify which screen sizes it does support and let the market filter the right APK to the right device.
You can. The disadvantage may be slightly worse image quality: consider for hdpi display you need to scale 240/320 times, that is, 0.75, or to speak e.g. in 1D pixel line you make up 3 target pixels out of 4 source pixels. Most of the time it will look very good, but I imagine some pixel art may be an exception. I guess this may be slower as well, and use more memory than it could, but I didn't measure that so I can't tell for sure.
P.S. I'm using this method (providing xhdpi resources only) myself too.

Bitmap scaling to fit different screen size/density

I do not really understand all those things about pixel density and device independant pixels and I want to know if I should worry about this.
More specifically, here is how my application work right now:
For the “layout screens”, I’m using RelativeLayout or LinearLayout and I never use pixels or dp, so I guess that this will look good on every device
For the main game screen, there is only a SurfaceView on the screen. With the values given by onSurfaceCreated() (pixels or dp? I don’t know), I compute the size and position of every element of the game, then I load the Bitmaps (with BitmapFactory.decodeResource() and then Bitmap.createScaledBitmap()) and put them on the screen with drawBitmap()
I tested on my phone (480 × 800 hdpi) and on the emulator (240 × 320 mdpi), and both looks good.
My questions are:
Is this the right thing to do? I do not understand how (and why) I could use the fact that some devices are hdpi and others are mdpi.
Should I provide different bitmaps for different screen densities, and why? (right now I have everything in res/drawable-hdpi)
What size should my .png have? Can I create them much bigger (2 ×) than their expected size, in order to be sure that this will not look blur or aliased?
My knowledge about this is limited, as i never developed games.. as i supposed you are doing.
Is this the right thing to do? I do
not understand how (and why) I could
use the fact that some devices are
hdpi and others are mdpi.
With this information you can load different images automatically. You can you the directories:
drawable-hdpi
drawables-mdpi
...
Should I provide different bitmaps for
different screen densities, and why?
(right now I have everything in
res/drawable-hdpi)
If you have all in hdpi then the images will be shrinked i think, to be smaller due to the lack of specific images o that scale. Providing the images will give you more control over the final product and it will spend less processing.
What size should my .png have? Can I
create them much bigger (2 ×) than
their expected size, in order to be
sure that this will not look blur or
aliased?
I think they can be exactly the size needed. But as i said above.. not much experience.

Categories

Resources