http://obviam.net/index.php/displaying-graphics-with-android/
Displaying an image using Android is extremely simple.
To scale the problem down we will just display the image in the top left corner. We need an image to display. I prefer .png formats and I have just created one named droid_1.png. The size of the image is 20×20 pixels. You can use whatever tool you like. I use Gimp or Photoshop.

To make it available for your application just copy the image into the
I have chosen mdpi which stands for normal screen medium density. To read on screen types check the android documentation.
Modify the
The
We obtain the bitmap from the application resources by passing the id of our image (resource), which is
The thread suffered some changes too. Examine the new
In line 02 we declare the canvas on which we will draw our image. The canvas is the surface’s bitmap onto which we can draw and we can edit its pixels. In line 08 we try to get hold of it and in line 12 we trigger the panel’s
The functionality is very simple and basic. On every execution of the game loop we get hold of the canvas and we pass it to the game panel to draw on it. The game panel just displays the image at coordinates 10,10. Now back to the FPS. If the number of times per second the image is displayed drops below 20, it starts to get noticeable by us humans. The challenge is to keep this rate above a set level and we will see how shortly.
Try running the code and you should see our droid displayed close to the top left corner.
We need to create an object that will hold our image and the coordinates.
I have created
It is a plain class with some attributes and a constructor.
The
So far nothing special. But to play around with it we need to add some state. To keep it simple, the droid has only 2 states. Touched and untouched. By touched I mean when our finger touched the droid on the screen. We keep the touched state true while we hold our finger down on the screen at the droid’s position. Otherwise the droid remains untouched (state set to false).
Check out the new droid class.
We added the
These methods are discussed later.
Now let’s have a look at the
Line 28 creates the
It is declared as an attribute in line 20.
In the
Displaying Images with Android
Before moving to the actual game loop let’s display some graphics so we can get some measurements done. If you haven’t checked it out please do as it is imperative that you understand how a thread updates the screen. You can check it out here.Displaying an image using Android is extremely simple.
To scale the problem down we will just display the image in the top left corner. We need an image to display. I prefer .png formats and I have just created one named droid_1.png. The size of the image is 20×20 pixels. You can use whatever tool you like. I use Gimp or Photoshop.
To make it available for your application just copy the image into the
/res/drawable-mdpi directory (the easiest way is to drag and drop it there).I have chosen mdpi which stands for normal screen medium density. To read on screen types check the android documentation.
Modify the
MainGamePanel.java class and change the onDraw(Canvas canvas) method to look like this:1 | protected void onDraw(Canvas canvas) { |
2 | canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.droid_1), 10, 10, null); |
3 | } |
drawBitmap method draws the droid_1 image to the coordinates 10,10.We obtain the bitmap from the application resources by passing the id of our image (resource), which is
droid_1 in our case. When we copied the droid_1.png into the resource directory eclipse detected it and the plugin executed the necessary scripts in the background so we have the droid_1 identifier in the R.java file. The R.java holds the resource identifiers.The thread suffered some changes too. Examine the new
run() method.01 | public void run() { |
02 | Canvas canvas; |
03 | Log.d(TAG, "Starting game loop"); |
04 | while (running) { |
05 | canvas = null; |
06 | // try locking the canvas for exclusive pixel editing on the surface |
07 | try { |
08 | canvas = this.surfaceHolder.lockCanvas(); |
09 | synchronized (surfaceHolder) { |
10 | // update game state |
11 | // draws the canvas on the panel |
12 | this.gamePanel.onDraw(canvas); |
13 | } |
14 | } finally { |
15 | // in case of an exception the surface is not left in |
16 | // an inconsistent state |
17 | if (canvas != null) { |
18 | surfaceHolder.unlockCanvasAndPost(canvas); |
19 | } |
20 | } // end finally |
21 | } |
22 | } |
onDraw event to which we pass the obtained canvas. Note that it is a synchronised block which means that we have exclusivity on it and nothing can modify it while we are using it.The functionality is very simple and basic. On every execution of the game loop we get hold of the canvas and we pass it to the game panel to draw on it. The game panel just displays the image at coordinates 10,10. Now back to the FPS. If the number of times per second the image is displayed drops below 20, it starts to get noticeable by us humans. The challenge is to keep this rate above a set level and we will see how shortly.
Try running the code and you should see our droid displayed close to the top left corner.
Moving the Image
Now that we have displayed it, let’s try moving it. How? We will use our finger. We will implement a simple drag and drop functionality. To pick up an image we will simply touch it and while our finger is on the screen we will update the image’s coordinates accordingly. Once the touch is finished we leave the image there where the last touch was recorded.We need to create an object that will hold our image and the coordinates.
I have created
Droid.java for this. Note that I have put the class into the net.obviam.droidz.model package.01 | package net.obviam.droidz.model; |
02 |
03 | import android.graphics.Bitmap; |
04 |
05 | public class Droid { |
06 |
07 | private Bitmap bitmap; // the actual bitmap |
08 | private int x; // the X coordinate |
09 | private int y; // the Y coordinate |
10 |
11 | public Droid(Bitmap bitmap, int x, int y) { |
12 | this.bitmap = bitmap; |
13 | this.x = x; |
14 | this.y = y; |
15 | } |
16 |
17 | public Bitmap getBitmap() { |
18 | return bitmap; |
19 | } |
20 | public void setBitmap(Bitmap bitmap) { |
21 | this.bitmap = bitmap; |
22 | } |
23 | public int getX() { |
24 | return x; |
25 | } |
26 | public void setX(int x) { |
27 | this.x = x; |
28 | } |
29 | public int getY() { |
30 | return y; |
31 | } |
32 | public void setY(int y) { |
33 | this.y = y; |
34 | } |
35 | } |
The
x and y are the coordinates of the droid. The bitmap holds the image that will be displayed as the droid. It is the graphical representation of it.So far nothing special. But to play around with it we need to add some state. To keep it simple, the droid has only 2 states. Touched and untouched. By touched I mean when our finger touched the droid on the screen. We keep the touched state true while we hold our finger down on the screen at the droid’s position. Otherwise the droid remains untouched (state set to false).
Check out the new droid class.
01 | package net.obviam.droidz.model; |
02 |
03 | import android.graphics.Bitmap; |
04 | import android.graphics.Canvas; |
05 | import android.view.MotionEvent; |
06 |
07 | public class Droid { |
08 |
09 | private Bitmap bitmap; // the actual bitmap |
10 | private int x; // the X coordinate |
11 | private int y; // the Y coordinate |
12 | private boolean touched; // if droid is touched/picked up |
13 |
14 | public Droid(Bitmap bitmap, int x, int y) { |
15 | this.bitmap = bitmap; |
16 | this.x = x; |
17 | this.y = y; |
18 | } |
19 |
20 | public Bitmap getBitmap() { |
21 | return bitmap; |
22 | } |
23 | public void setBitmap(Bitmap bitmap) { |
24 | this.bitmap = bitmap; |
25 | } |
26 | public int getX() { |
27 | return x; |
28 | } |
29 | public void setX(int x) { |
30 | this.x = x; |
31 | } |
32 | public int getY() { |
33 | return y; |
34 | } |
35 | public void setY(int y) { |
36 | this.y = y; |
37 | } |
38 |
39 | public boolean isTouched() { |
40 | return touched; |
41 | } |
42 |
43 | public void setTouched(boolean touched) { |
44 | this.touched = touched; |
45 | } |
46 |
47 | public void draw(Canvas canvas) { |
48 | canvas.drawBitmap(bitmap, x - (bitmap.getWidth() / 2), y - (bitmap.getHeight() / 2), null); |
49 | } |
50 |
51 | public void handleActionDown(int eventX, int eventY) { |
52 | if (eventX >= (x - bitmap.getWidth() / 2) && (eventX <= (x + bitmap.getWidth()/2))) { |
53 | if (eventY >= (y - bitmap.getHeight() / 2) && (y <= (y + bitmap.getHeight() / 2))) { |
54 | // droid touched |
55 | setTouched(true); |
56 | } else { |
57 | setTouched(false); |
58 | } |
59 | } else { |
60 | setTouched(false); |
61 | } |
62 |
63 | } |
64 | } |
touched field to keep track of the state of our droid. You will notice two more methods: public void draw(Canvas canvas) and public void handleActionDown(int eventX, int eventY).These methods are discussed later.
Now let’s have a look at the
MainGamePanel.java. It changed quite a lot.001 | package net.obviam.droidz; |
002 |
003 | import net.obviam.droidz.model.Droid; |
004 | import android.app.Activity; |
005 | import android.content.Context; |
006 | import android.graphics.BitmapFactory; |
007 | import android.graphics.Canvas; |
008 | import android.graphics.Color; |
009 | import android.util.Log; |
010 | import android.view.MotionEvent; |
011 | import android.view.SurfaceHolder; |
012 | import android.view.SurfaceView; |
013 |
014 | public class MainGamePanel extends SurfaceView implements |
015 | SurfaceHolder.Callback { |
016 |
017 | private static final String TAG = MainGamePanel.class.getSimpleName(); |
018 |
019 | private MainThread thread; |
020 | private Droid droid; |
021 |
022 | public MainGamePanel(Context context) { |
023 | super(context); |
024 | // adding the callback (this) to the surface holder to intercept events |
025 | getHolder().addCallback(this); |
026 |
027 | // create droid and load bitmap |
028 | droid = new Droid(BitmapFactory.decodeResource(getResources(), R.drawable.droid_1), 50, 50); |
029 |
030 | // create the game loop thread |
031 | thread = new MainThread(getHolder(), this); |
032 |
033 | // make the GamePanel focusable so it can handle events |
034 | setFocusable(true); |
035 | } |
036 |
037 | @Override |
038 | public void surfaceChanged(SurfaceHolder holder, int format, int width, |
039 | int height) { |
040 | } |
041 |
042 | @Override |
043 | public void surfaceCreated(SurfaceHolder holder) { |
044 | // at this point the surface is created and |
045 | // we can safely start the game loop |
046 | thread.setRunning(true); |
047 | thread.start(); |
048 | } |
049 |
050 | @Override |
051 | public void surfaceDestroyed(SurfaceHolder holder) { |
052 | Log.d(TAG, "Surface is being destroyed"); |
053 | // tell the thread to shut down and wait for it to finish |
054 | // this is a clean shutdown |
055 | boolean retry = true; |
056 | while (retry) { |
057 | try { |
058 | thread.join(); |
059 | retry = false; |
060 | } catch (InterruptedException e) { |
061 | // try again shutting down the thread |
062 | } |
063 | } |
064 | Log.d(TAG, "Thread was shut down cleanly"); |
065 | } |
066 |
067 | @Override |
068 | public boolean onTouchEvent(MotionEvent event) { |
069 | if (event.getAction() == MotionEvent.ACTION_DOWN) { |
070 | // delegating event handling to the droid |
071 | droid.handleActionDown((int)event.getX(), (int)event.getY()); |
072 |
073 | // check if in the lower part of the screen we exit |
074 | if (event.getY() > getHeight() - 50) { |
075 | thread.setRunning(false); |
076 | ((Activity)getContext()).finish(); |
077 | } else { |
078 | Log.d(TAG, "Coords: x=" + event.getX() + ",y=" + event.getY()); |
079 | } |
080 | } if (event.getAction() == MotionEvent.ACTION_MOVE) { |
081 | // the gestures |
082 | if (droid.isTouched()) { |
083 | // the droid was picked up and is being dragged |
084 | droid.setX((int)event.getX()); |
085 | droid.setY((int)event.getY()); |
086 | } |
087 | } if (event.getAction() == MotionEvent.ACTION_UP) { |
088 | // touch was released |
089 | if (droid.isTouched()) { |
090 | droid.setTouched(false); |
091 | } |
092 | } |
093 | return true; |
094 | } |
095 |
096 | @Override |
097 | protected void onDraw(Canvas canvas) { |
098 | // fills the canvas with black |
099 | canvas.drawColor(Color.BLACK); |
100 | droid.draw(canvas); |
101 | } |
102 | } |
droid object at the the coordinates 50,50.It is declared as an attribute in line 20.
In the
onTouchEvent (method line 71) if the action is the touch of the screen (MotionEvent.ACTION_DOWN) we want to know if our finger landed on the droid. To do this is easy. We need to check if the event’s coordinates are inside the droid’s bitmap. In order not to clutter the onTouch event we just delegate this to the droid object. Now you can go back to the Droid.java class and check the handleActionDown method.01 | public void handleActionDown(int eventX, int eventY) { |
02 | if (eventX >= (x - bitmap.getWidth() / 2) && (eventX <= (x + bitmap.getWidth()/2))) { |
03 | if (eventY >= (y - bitmap.getHeight() / 2) && (y <= (y + bitmap.getHeight() / 2))) { |
04 | // droid touched |
05 | setTouched(true); |
06 | } else { |
07 | setTouched(false); |
08 | } |
09 | } else { |
10 | setTouched(false); |
11 | } |
12 |
13 | } |
No comments:
Post a Comment