Статьи

Разработка игр для Android — Отображение изображений с Android

Прежде чем перейти к реальному игровому циклу, давайте отобразим некоторую графику, чтобы мы могли выполнить некоторые измерения. Если вы еще не проверили это, пожалуйста, сделайте так, чтобы вы понимали, как поток обновляет экран. Вы можете проверить это здесь .

Отображение изображения с помощью Android чрезвычайно просто.
Чтобы уменьшить проблему, мы просто отобразим изображение в верхнем левом углу. Нам нужно изображение для отображения. Я предпочитаю форматы .png, и я только что создал один с именем droid_1.png. Размер изображения 20 × 20 пикселей. Вы можете использовать любой инструмент, который вам нравится. Я использую Gimp или Photoshop.

Чтобы сделать его доступным для вашего приложения, просто скопируйте изображение в каталог / res / drawable-mdpi (самый простой способ — перетащить его туда).
Я выбрал mdpi, что означает нормальную плотность экрана. Чтобы прочитать на экране типов проверить документацию Android .

Измените класс MainGamePanel.java и измените метод onDraw (Canvas canvas), чтобы он выглядел следующим образом:

1
2
3
protected void onDraw(Canvas canvas) {
 canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.droid_1), 10, 10, null);
}

Метод drawBitmap рисует изображение droid_1 с координатами 10,10.
Мы получаем растровое изображение из ресурсов приложения, передавая идентификатор нашего изображения (ресурса), который в нашем случае равен droid_1 . Когда мы скопировали droid_1.png в каталог ресурсов, Eclipse обнаружил его, и плагин выполнил необходимые сценарии в фоновом режиме, поэтому у нас есть идентификатор droid_1 в файле R.java . R.java содержит идентификаторы ресурсов.

Поток тоже претерпел некоторые изменения. Изучите новый метод run () .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
public void run() {
  Canvas canvas;
  Log.d(TAG, "Starting game loop");
  while (running) {
   canvas = null;
   // try locking the canvas for exclusive pixel editing on the surface
   try {
    canvas = this.surfaceHolder.lockCanvas();
    synchronized (surfaceHolder) {
     // update game state
     // draws the canvas on the panel
     this.gamePanel.onDraw(canvas);
    }
   } finally {
    // in case of an exception the surface is not left in
    // an inconsistent state
    if (canvas != null) {
     surfaceHolder.unlockCanvasAndPost(canvas);
    }
   } // end finally
  }
 }

В строке 02 мы объявляем холст, на котором будем рисовать наше изображение. Холст — это растровое изображение поверхности, на которое мы можем рисовать и редактировать его пиксели. В строке 08 мы пытаемся заполучить его, а в строке 12 запускаем событие onDraw панели, которому мы передаем полученный холст. Обратите внимание, что это синхронизированный блок, который означает, что у нас есть эксклюзивность, и ничто не может изменить его, пока мы его используем.
Функциональность очень простая и базовая. При каждом выполнении игрового цикла мы получаем холст и передаем его на игровую панель для рисования на нем. Игровая панель просто отображает изображение в координатах 10,10. Теперь вернемся к FPS. Если количество отображаемых изображений в секунду падает ниже 20, мы, люди, начинаем становиться заметными. Задача состоит в том, чтобы сохранить этот уровень выше установленного уровня, и мы увидим, как скоро.

Попробуйте запустить код, и вы должны увидеть нашего дроида рядом с верхним левым углом.

Дроид в левом верхнем углу

Перемещение изображения

Теперь, когда мы его отобразили, давайте попробуем переместить его. Как? Мы будем использовать наш палец. Мы реализуем простую функциональность перетаскивания. Чтобы подобрать изображение, мы просто прикоснемся к нему, и пока наш палец будет на экране, мы соответствующим образом обновим координаты изображения. Когда касание закончено, мы оставляем изображение там, где было записано последнее касание.

Нам нужно создать объект, который будет содержать наше изображение и координаты.
Я создал Droid.java для этого. Обратите внимание, что я поместил класс в пакет net.obviam.droidz.model .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package net.obviam.droidz.model;
 
import android.graphics.Bitmap;
 
public class Droid {
 
 private Bitmap bitmap; // the actual bitmap
 private int x;   // the X coordinate
 private int y;   // the Y coordinate
 
 public Droid(Bitmap bitmap, int x, int y) {
  this.bitmap = bitmap;
  this.x = x;
  this.y = y;
 }
 
 public Bitmap getBitmap() {
  return bitmap;
 }
 public void setBitmap(Bitmap bitmap) {
  this.bitmap = bitmap;
 }
 public int getX() {
  return x;
 }
 public void setX(int x) {
  this.x = x;
 }
 public int getY() {
  return y;
 }
 public void setY(int y) {
  this.y = y;
 }
}

Это простой класс с некоторыми атрибутами и конструктором.
Х и у — координаты дроида. Растровое изображение содержит изображение, которое будет отображаться как дроид. Это графическое представление этого.

Пока ничего особенного. Но чтобы поиграть с этим, нам нужно добавить некоторое состояние. Для простоты у дроида есть только 2 состояния. Тронутый и нетронутый . Под прикосновением я подразумеваю, когда наш палец коснулся дроида на экране. Мы сохраняем состояние касания истинным, пока держим палец на экране в позиции дроида. В противном случае дроид останется нетронутым (состояние установлено в false ).

Проверьте новый класс дроидов.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package net.obviam.droidz.model;
 
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.view.MotionEvent;
 
public class Droid {
 
 private Bitmap bitmap; // the actual bitmap
 private int x;   // the X coordinate
 private int y;   // the Y coordinate
 private boolean touched; // if droid is touched/picked up
 
 public Droid(Bitmap bitmap, int x, int y) {
  this.bitmap = bitmap;
  this.x = x;
  this.y = y;
 }
 
 public Bitmap getBitmap() {
  return bitmap;
 }
 public void setBitmap(Bitmap bitmap) {
  this.bitmap = bitmap;
 }
 public int getX() {
  return x;
 }
 public void setX(int x) {
  this.x = x;
 }
 public int getY() {
  return y;
 }
 public void setY(int y) {
  this.y = y;
 }
 
 public boolean isTouched() {
  return touched;
 }
 
 public void setTouched(boolean touched) {
  this.touched = touched;
 }
 
 public void draw(Canvas canvas) {
  canvas.drawBitmap(bitmap, x - (bitmap.getWidth() / 2), y - (bitmap.getHeight() / 2), null);
 }
 
 public void handleActionDown(int eventX, int eventY) {
  if (eventX >= (x - bitmap.getWidth() / 2) && (eventX <= (x + bitmap.getWidth()/2))) {
   if (eventY >= (y - bitmap.getHeight() / 2) && (y <= (y + bitmap.getHeight() / 2))) {
    // droid touched
    setTouched(true);
   } else {
    setTouched(false);
   }
  } else {
   setTouched(false);
  }
 
 }
}

Мы добавили поле касания, чтобы отслеживать состояние нашего дроида. Вы заметите еще два метода: public void draw (Canvas canvas) и public void handleActionDown (int eventX, int eventY) .
Эти методы обсуждаются позже.
Теперь давайте посмотрим на MainGamePanel.java . Это изменилось довольно сильно.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
package net.obviam.droidz;
 
import net.obviam.droidz.model.Droid;
import android.app.Activity;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
 
public class MainGamePanel extends SurfaceView implements
  SurfaceHolder.Callback {
 
 private static final String TAG = MainGamePanel.class.getSimpleName();
 
 private MainThread thread;
 private Droid droid;
 
 public MainGamePanel(Context context) {
  super(context);
  // adding the callback (this) to the surface holder to intercept events
  getHolder().addCallback(this);
 
  // create droid and load bitmap
  droid = new Droid(BitmapFactory.decodeResource(getResources(), R.drawable.droid_1), 50, 50);
 
  // create the game loop thread
  thread = new MainThread(getHolder(), this);
 
  // make the GamePanel focusable so it can handle events
  setFocusable(true);
 }
 
 @Override
 public void surfaceChanged(SurfaceHolder holder, int format, int width,
   int height) {
 }
 
 @Override
 public void surfaceCreated(SurfaceHolder holder) {
  // at this point the surface is created and
  // we can safely start the game loop
  thread.setRunning(true);
  thread.start();
 }
 
 @Override
 public void surfaceDestroyed(SurfaceHolder holder) {
  Log.d(TAG, "Surface is being destroyed");
  // tell the thread to shut down and wait for it to finish
  // this is a clean shutdown
  boolean retry = true;
  while (retry) {
   try {
    thread.join();
    retry = false;
   } catch (InterruptedException e) {
    // try again shutting down the thread
   }
  }
  Log.d(TAG, "Thread was shut down cleanly");
 }
 
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  if (event.getAction() == MotionEvent.ACTION_DOWN) {
   // delegating event handling to the droid
   droid.handleActionDown((int)event.getX(), (int)event.getY());
 
   // check if in the lower part of the screen we exit
   if (event.getY() > getHeight() - 50) {
    thread.setRunning(false);
    ((Activity)getContext()).finish();
   } else {
    Log.d(TAG, "Coords: x=" + event.getX() + ",y=" + event.getY());
   }
  } if (event.getAction() == MotionEvent.ACTION_MOVE) {
   // the gestures
   if (droid.isTouched()) {
    // the droid was picked up and is being dragged
    droid.setX((int)event.getX());
    droid.setY((int)event.getY());
   }
  } if (event.getAction() == MotionEvent.ACTION_UP) {
   // touch was released
   if (droid.isTouched()) {
    droid.setTouched(false);
   }
  }
  return true;
 }
 
 @Override
 protected void onDraw(Canvas canvas) {
  // fills the canvas with black
  canvas.drawColor(Color.BLACK);
  droid.draw(canvas);
 }
}

Линия 28 создает объект дроида в координатах 50,50 .
Он объявлен как атрибут в строке 20 .

В onTouchEvent (строка метода 71 ), если действие является касанием экрана ( MotionEvent.ACTION_DOWN ), мы хотим знать, приземлился ли наш палец на дроида. Сделать это легко. Нам нужно проверить, находятся ли координаты события внутри битовой карты дроида. Чтобы не загромождать событие onTouch, мы просто делегируем это объекту droid. Теперь вы можете вернуться к классу Droid.java и проверить метод handleActionDown .

01
02
03
04
05
06
07
08
09
10
11
12
13
public void handleActionDown(int eventX, int eventY) {
  if (eventX >= (x - bitmap.getWidth() / 2) && (eventX <= (x + bitmap.getWidth()/2))) {
   if (eventY >= (y - bitmap.getHeight() / 2) && (y <= (y + bitmap.getHeight() / 2))) {
    // droid touched
    setTouched(true);
   } else {
    setTouched(false);
   }
  } else {
   setTouched(false);
  }
 
 }

Это очень просто. Если действие произошло в области растрового изображения нашего дроида, мы установим его статус касания в true

Возвращаясь к методу onTouched , обратите внимание, что существует блок кода (строки 81–86 ), который выполняется, когда событие имеет тип MotionEvent.ACTION_MOVE . Это событие происходит, когда наш палец начинает двигаться на экране. Это просто. Мы проверяем, касался ли дроид, и если да, то просто обновляем его координаты.
Вот и все. Это было обновление игрового состояния. Мы обновили состояние нашего единственного объекта в игре. Тронутое состояние и координаты. Теперь пришло время показать это.

Проверьте метод onDraw . Это срабатывает при каждом выполнении основного цикла внутри потока, помните?
Содержит 2 строки. Линия 99 просто заполняет холст черным, а линия 100 говорит дроиду нарисовать себя на предоставленном холсте. Это похоже на то, как я даю вам бумагу, чтобы нарисовать себя на ней, и отдаю мне бумагу, чтобы я мог продолжить свой рисунок.

Проверьте Droid.java для реализации отрисовки. Это очень просто. Он берет растровое изображение, с которым он был создан, и рисует его на холсте в координатах, в которых находится дроид в тот момент. Обратите внимание, что координаты дроида находятся точно в центре растрового изображения, поэтому нам нужно переместить указатель в верхний левый угол изображения и нарисовать его там. Я уверен, что вам не трудно это понять.

Вот и все. Запустите его и поиграйте с ним.

Скачать код проекта можно здесь (droidz.android.02.3-graphics.tar.gz)

Ссылка: Отображение изображений с Android от нашего партнера JCG Тамаса Яно из блога « Против зерна ».

Не забудьте проверить нашу новую Android игру ArkDroid (скриншоты ниже) . Ваш отзыв будет более чем полезным!
Статьи по Теме: