Game graphics took me a lot of time but my first android game is about 70% finished now. As I could only work on it in my spare time, I am pretty happy with the progress. Hopefully I can release it to the world in 1 or 2 weeks of time. Things look a bit amateurish but I learned A LOT in the process. I am quite excited about it.
One thing I don't like developing games for the Android platform is that there are too many different screen sizes. I mean, it is fine to have screens with different sizes / resolutions, but it would be great if they all are of the same aspect ratio. (In this post I calculate aspect ratios by
screen height / screen width.) So we have the common 480 x 800 / ratio 1.67 ones (Desire / Nexus One / Liquid). We have some slightly taller ones 480 x 854 / ratio 1.78 (Milestone / Defy). We also have some small ones: 240 x 320 / ratio 1.33 (Tattoo / Wildfire). And then some more... Well, don't forget the tablets too.
It is good to the customers as they got more choices at different price levels but that is probably a burden to the developers.
For application developers, it means they need to
design their GUI layouts carefully and possibly provide different sets of their GUI graphics for different screen classes. I haven't really looked into the application development side yet, so I am not sure how difficult / trouble that actually is.
For game developers, they first need to make scalable game graphics and then they have to pay attention to the screen aspect ratio issue.
Using OpenGL, what the player see on the screen is basically a portion of the game world through the viewport (think of it as a window). Usually we just fit the viewport to the whole screen. Viewport and screen can have different sizes / resolutions. For example, the viewport can be of size 1000x1000 and your screen size can be of size 1200x600. In that case, your game world objects will look fatter than they actually are because you have more screen pixels for the width than the height.
So there are many different screen aspect ratios and they can be quite different, for example, it could be 1.33 vs 1.78. If you designed your game graphics for the screens with aspect ratio 1.33, and then you simply scale all your game graphics for other screens, that is, fitting the same viewport to different screens, then your game graphics may look just fine on the 1.33 screens but look too tall and weird on those 1.78 screens.
There are two ways of solving this.
The first one is to change the size of the viewport according to the screen size. For example, if the screen size is 480 x 800, then you will set the viewport size to 480 x 800 or 240 x 400 so that their aspect ratios match each other. Therefore, instead of showing taller than usual game world objects in a big screen with an aspect ratio of 1.78, you may just vertically expand your viewport to avoid destroying the apparent aspect ratio of the game world objects. By changing the viewport size according to the screen size, the player will see different sizes of the game world portion with different screens. It might be fine for some. However, this approach doesn't work for those games that require some kind of "fairness". For example, if the players of your game can compete with each others through the internet, then players that can see a larger portion of the game world may have an unfair advantage over the ones that can only see a smaller portion of the game world.
The second approach would be only using a part of the screen for the viewport. For example, if you want the viewport to be always showing a square portion of the game world, then in a 800x480 screen you will only use the 480x480 region in the middle as the viewport, and in a 320x240 screen you will only use the 240x240 region in the middle. You may not be able to use the whole screen for your game but all players will see the same size of the game world portion.
The code of setting up the viewport using the second approach looks something like this with OpenGL or any game library that uses it (I used libgdx myself):
viewportWidth = screenWidth;
viewportHeight = screenWidth * fixedViewportAspectRatio;
if( viewportHeight > screenHeight )
{
viewportHeight = screenHeight;
viewportWidth = screenHeight * 1 / fixedViewportAspectRatio;
}
viewportX = ( screenWidth - viewportWidth ) / 2;
viewportY = ( screenHeight - viewportHeight ) / 2;
glViewport( viewportX, viewportY, viewportWidth, viewportHeight );
glScissor( viewportX, viewportY, viewportWidth, viewportHeight );
glEnable( GL_SCISSOR_TEST );
At first I didn't have the last two lines. When I ran the game I found that in the Android emulator the regions outside my viewport were being rendered. (interestingly, those regions were not rendered on my desktop) I did some searching with Google, and it turns out that believing that the viewport would clip or scissor is a
common OpenGL pitfall. It s necessary to use a
scissor box to make sure nothing got rendered outside the viewport. I added those 2 lines, and now I have a "proper viewport" that keeps my game graphics from getting destroyed by "bad scaling".
Update 1 (2011/11/04): Fixed some typos - I was too sleepy when I wrote this post last night. :P
Update 2 (2011/11/14): I found that glScissor falis on HTC devices. A solution is posted there.