Best approach to supporting multiple screens

Problems with Canvas, OpenGL, etc...

Best approach to supporting multiple screens

Postby saps1727 » Fri Aug 06, 2010 8:33 pm

Hey guys, I am new to the Android platform and drawing graphics on predefined screens. I am currently making a game that has similar functionality to a chess game (static background/game board, drag & drop pieces to locations on the game board, etc.).

What is the best approach to supporting multiple screens? Do I start out drawing the game board to fit the medium density screens and then let the OS scale up/down for different screens, or do I draw different size game boards to fit the different screen sizes?

I have been reading through the guides on android developer for supporting multiple screens, but I am a bit confused as where to begin.
saps1727
Junior Developer
Junior Developer
 
Posts: 12
Joined: Thu Jun 24, 2010 4:58 am

Top

Re: Best approach to supporting multiple screens

Postby mast3rpyr0 » Sat Aug 07, 2010 4:37 pm

You can define different layouts for different resolution screens using folders layout-ldpi, layout-mdpi and layout-hdpi with a layout of the same name in each folder, slighly modified for the different screen size.
mast3rpyr0
Freshman
Freshman
 
Posts: 5
Joined: Wed Jun 23, 2010 7:16 am

Re: Best approach to supporting multiple screens

Postby saps1727 » Sun Aug 08, 2010 2:59 am

Ok thanks a lot. But how would I go about piece placement? Currently, I am placing the pieces at certain locations determined by pixels, but the number of pixels is obviously different per screen size. From what I read and understand on android developer, the OS will automatically adjust the pixel placement of my locations if i have the anydensity set to false in the manifest?
saps1727
Junior Developer
Junior Developer
 
Posts: 12
Joined: Thu Jun 24, 2010 4:58 am

Re: Best approach to supporting multiple screens

Postby MichaelEGR » Sun Aug 08, 2010 4:10 am

I assume this is a 2D API game and not using OpenGL ES

Check out DisplayMetrics:
http://developer.android.com/reference/ ... trics.html

What you want to do is represent your piece locations in DIP (density independent pixels). See the density, xdpi and ydpi static member variables of DisplayMetrics.

Also a quick tip is that instead of creating specific graphic assets for each screen size just create the largest version and use the DisplayMetrics density or xdpi/ydpi scaling factors to manually scale your large asset for smaller screen sizes. This prevents the necessity of duplicating assets. You'll also have to mindful of the auto-resizing that the resource system will do. What you really want to do is load unscaled images and that requires a few 1.6 fields in BitmapFactory.Options to modify and if I recall offhand there is a 1.6 method in Bitmap too that assists in loading an unscaled image.

For OpenGL ES there are different approaches. I assume you're doing a 2D app though and that'd be best to attempt if you are just getting into things.
Founder & Principal Architect; EGR Software LLC
http://www.typhonrt.org
http://www.egrsoftware.com
User avatar
MichaelEGR
Senior Developer
Senior Developer
 
Posts: 147
Joined: Thu Jan 21, 2010 5:30 am
Location: San Francisco, CA

Re: Best approach to supporting multiple screens

Postby saps1727 » Mon Aug 09, 2010 2:20 am

Hey thanks a lot. I didnt' even look at the DisplayMetrics section on developer. I will take a look and see if I have any further questions. Thanks againn.
saps1727
Junior Developer
Junior Developer
 
Posts: 12
Joined: Thu Jun 24, 2010 4:58 am

Re: Best approach to supporting multiple screens

Postby saps1727 » Mon Aug 09, 2010 3:15 am

Hey MichaelEGR, I took a look at the DisplayMetrics on the developer website, and I am still a little confused as how to implement this. For example, if one of my piece locations is 20,20,40,40 (left,top,right,bottom), how would I use DisplayMetrics to represent this region on different screen sizes? Thanks for all your help.
saps1727
Junior Developer
Junior Developer
 
Posts: 12
Joined: Thu Jun 24, 2010 4:58 am

Top

Re: Best approach to supporting multiple screens

Postby MichaelEGR » Mon Aug 09, 2010 7:34 am

For a generally rough position you'd multiply your x/y values by the DIsplayMetrics density parameter. I'd have to take another look at xdpi and ydpi, but you'd figure out a scaling value from xdpi and ydpi and be able to multiply your x/y positions by these scaling values to convert to pixel/screen space. A slightly more generic approach is to create or use a smaller helper conversion class that creates a coordinate space and a mapping to pixel space.

I'll be extra nice and post a reduced version of what is found in TyphonRT my middleware that is actually being released really soon. I've not played around with this with Android yet, but it should work as intended. Essentially you set width and height in pixel dimensions of your game board and xMin, xMax, yMin, yMax as the coordinate bounds (-100, 100, -100, 100) or whatever bounds you want. Say you do that and width & height is 480x320 (you can set this to anything you want and in your case whatever the pixel space of the board would be). Note that a non square width/height will introduce a skew of sorts. Also note posOffsetX & posOffesetY which can be set to border pixel offsets if the game board is not full screen and width/height is just part of the screen.

With those values the scaling values become
xScale = ((float) width) / (xMax - xMin);
yScale = ((float) height) / (yMax - yMin);

xScale = 480 / 200 = 2.4
yScale = 320 / 200 = 1.6

If you picked coordinate point (50, 50) and called coordsToPixels

public final void coordsToPixels(float x, float y, Tuple2f out)
{
out.x = (int) (xScale * (x - xMin) + s_OFFSET + posOffsetX);
out.y = (int) (yScale * (yMax - y) + s_OFFSET + posOffsetY);
}

out.x = 2.4 * (50 - (-100)) + 0.5 = 360
out.y = 1.6 * (50 - (-100)) + 0.5 = 240

So out.x = 360 and out.y = 240 which is precisely 75% of the width/height of the screen in pixel space and (50,50) in coordinate space is 75% / 75% of the coordinate space mapping (-100 to 100 in x/y).

Regarding the Tuple2f class that is a standard vector math class defined in the javax.vecmath library/API. You can find a free version here:
http://www.objectclub.jp/download/vecmath_e

TyphonRT uses a modified version of the standard javax.vecmath library/API.

Note there are also methods for converting from pixel space into coordinate space with the methods pixelsToCoords

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public class CoordsConverter2D
  2. {
  3.    public static final float  s_OFFSET = 0.5f;  // Used instead of Math.round()
  4.  
  5.    public float               xMin, xMax, deltaX, yMin, yMax, deltaY;
  6.    public int                 width, height;
  7.    public int                 posOffsetX, posOffsetY;               // Internal offset of component; borders, etc.
  8.  
  9.    float                      additionalSize = 50f;
  10.    float                      xScale, yScale;
  11.  
  12.    public CoordsConverter2D(int width, int height)
  13.    {
  14.       this.width = width;
  15.       this.height = height;
  16.       setScale();
  17.       deltaX = deltaY = 1.0f;
  18.    }
  19.  
  20.    public CoordsConverter2D(int width, int height, float xMin, float xMax, float yMin, float yMax)
  21.    {
  22.       this.width = width;
  23.       this.height = height;
  24.       this.xMin = xMin;
  25.       this.xMax = xMax;
  26.       this.yMin = yMin;
  27.       this.yMax = yMax;
  28.       setScale();
  29.       deltaX = deltaY = 1.0f;
  30.    }
  31.  
  32.    private void setScale()
  33.    {
  34.       xScale = ((float) width) / (xMax - xMin);
  35.       yScale = ((float) height) / (yMax - yMin);
  36.    }
  37.  
  38.    public void setPixels(int height, int width)
  39.    {
  40.       this.height = height;
  41.       this.width = width;
  42.       setScale();
  43.    }
  44.  
  45.    public void setCoords(float xMin, float xMax, float yMin, float yMax)
  46.    {
  47.       this.xMin = xMin;
  48.       this.xMax = xMax;
  49.       this.yMin = yMin;
  50.       this.yMax = yMax;
  51.  
  52.       setScale();
  53.    }
  54.  
  55.    public void setDeltas(float deltaX, float deltaY)
  56.    {
  57.       this.deltaX = deltaX;
  58.       this.deltaY = deltaY;
  59.    }
  60.  
  61. // coordsToPixels 2D --------------------------------------
  62.  
  63.    public final void coordsToPixels(float x, float y, Tuple2f out)
  64.    {
  65.       out.x = (int) (xScale * (x - xMin) + s_OFFSET + posOffsetX);
  66.       out.y = (int) (yScale * (yMax - y) + s_OFFSET + posOffsetY);
  67.    }
  68.  
  69.    public final void coordsToPixels(Tuple2f v, Tuple2f out)
  70.    {
  71.       out.x = (int) (xScale * (v.x - xMin) + s_OFFSET + posOffsetX);
  72.       out.y = (int) (yScale * (yMax - v.y) + s_OFFSET + posOffsetY);
  73.    }
  74.  
  75.    public final void coordsToPixels(Tuple2f v, int xVal[], int yVal[], int index)
  76.    {
  77.       xVal[index] = (int)(xScale * (v.x - xMin) + s_OFFSET + posOffsetX);
  78.       yVal[index] = (int)(yScale * (yMax - v.y) + s_OFFSET + posOffsetY);
  79.    }
  80.  
  81. // pixelsToCoords --------------------------------------
  82.  
  83.    public final void pixelsToCoords(int x, int y, Tuple2f out)
  84.    {
  85.       out.x = (float) x / xScale + xMin;
  86.       out.y = yMax - (float) y / yScale;
  87.    }
  88.  
  89.    public final void pixelsToCoords(Tuple2f p, Tuple2f out)
  90.    {
  91.       out.x = p.x / xScale + xMin;
  92.       out.y = yMax - p.y / yScale;
  93.    }
  94. }
  95.  
Parsed in 0.040 seconds, using GeSHi 1.0.8.4
Founder & Principal Architect; EGR Software LLC
http://www.typhonrt.org
http://www.egrsoftware.com
User avatar
MichaelEGR
Senior Developer
Senior Developer
 
Posts: 147
Joined: Thu Jan 21, 2010 5:30 am
Location: San Francisco, CA

Re: Best approach to supporting multiple screens

Postby MichaelEGR » Mon Aug 09, 2010 11:28 am

Note I made a small mistake with this line due to duplicating the out.x coordinate line quickly.

wrong:
out.y = 1.6 * (50 - (-100)) + 0.5 = 240

should be:
out.y = 1.6 * (100 - 50) + 0.5 = 80
out.y = (int) (yScale * (yMax - y) + s_OFFSET + posOffsetY);


Take note that the coordinate system is cartesian with positive y pointing up; pixel space or normal screen orientation in a 2D context has positive y going down (0, 0) in the top left. If we picked the point (50, -50) and plugged that into coordsToPixels then out.x = 360 and out.y = 240
Founder & Principal Architect; EGR Software LLC
http://www.typhonrt.org
http://www.egrsoftware.com
User avatar
MichaelEGR
Senior Developer
Senior Developer
 
Posts: 147
Joined: Thu Jan 21, 2010 5:30 am
Location: San Francisco, CA

Top

Return to Android 2D/3D Graphics - OpenGL Problems

Who is online

Users browsing this forum: No registered users and 2 guests