Android Game Development - 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), 1010null);
3 }

The  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  }

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  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.

Droid in 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 }

It is a plain class with some attributes and a constructor.
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 }

We added the  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), 5050);
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 }

Line  28  creates the  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  }

It is very simple. If the action happened inside the area of our droid’s bitmap we’ll set its touched status to  true

Going back to the  onTouched  method, notice that there is a code block (lines  81 - 86 ) that is executed when the event is of type  MotionEvent.ACTION_MOVE . This event happens when our finger started to move on the screen. It is simple. We check if the droid is  touched  and if so we just update its coordinates accordingly.
That is it. This was the update game state. We have updated the state of our sole object in the game. The touched state and the coordinates. Now it is time to display it.

Check the  onDraw  method. This is triggered at every execution of the main loop inside the thread remember?
It contains 2 lines. Line  99  simply fills the canvas with black and line  100  tells the droid to draw itself on the canvas provided. By doing this is like me giving you a paper to draw yourself onto it, and give the paper back to me so I can continue my drawing.

Check  Droid.java  for the draw implementation. It is dead simple. It takes the bitmap it was instantiated with and draws it to the canvas at the coordinates the droid is at in that moment. Note that the coordinates of the droid are exactly in the center of the bitmap so we need to move the pointer to the top left corner of the image and draw it there. I’m sure you won’t find it hard to understand.

That’s it. Run it and have a play with it.


Download he code for the project  here (droidz.android.02.3-graphics.tar.gz)


Reference:   Displaying Images with Android  from our  JCG  partner Tamas Jano from " Against The Grain " blog.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Paperback: 320 pages Publisher: Packt Publishing (November 25, 2013) Language: English ISBN-10: 1782167781 ISBN-13: 978-1782167785 For C++ developers, this is the book that can swiftly propel you into the potentially profitable world of Android games. The 70+ step-by-step recipes using Android NDK will give you the wide-ranging knowledge you need. Overview Tips and tricks for developing and debugging mobile games on your desktop Enhance your applications by writing multithreaded code for audio playback, network access, and asynchronous resource loading Enhance your game development skills by using modern OpenGL ES and develop applications without using an IDE Features two ready-to-run Android games In Detail Android NDK is used for multimedia applications which require direct access to a system's resources. Android NDK is also the key for portability, which in turn provides a reasonably comfortable development and debugging process using familiar tools such as GCC and Clang toolchains. If your wish to build Android games using this amazing framework, then this book is a must-have. This book provides you with a number of clear step-by-step recipes which will help you to start developing mobile games with Android NDK and boost your productivity debugging them on your computer. This book will also provide you with new ways of working as well as some useful tips and tricks that will demonstrably increase your development speed and efficiency. This book will take you through a number of easy-to-follow recipes that will help you to take advantage of the Android NDK as well as some popular C++ libraries. It presents Android application development in C++ and shows you how to create a complete gaming application. You will learn how to write portable multithreaded C++ code, use HTTP networking, play audio files, use OpenGL ES, to render high-quality text, and how to recognize user gestures on multi-touch devices. If you want to leverage your C++ skills in mobile development and add performance to your Android applications, then this is the book for you. What you will learn from this book Port popular C++ libraries to Android Write portable multithreaded code Play audio with OpenAL Implement gesture recognition Render text with FreeType Use OpenGL ES to port and abstract APIs from the game code to develop games on a desktop PC Debug mobile applications on your desktop Access Flickr and Picasa web services from C++ Extract resources from APK archives Develop Android applications without an IDE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值