Сегодня я хочу Вам рассказать о
примитивах использования класса SurfaceView.
Статьи по теме:
Статьи по теме:
И так, задача:
Для начала просто нарисуем ic_launcher.png на нашем Surface.
Для этого — создаем проект — Eclipse — New — Android project — MyFirstGame — Main.java.
Заходим в res/layout/main.xml и пишем вот такое:
Вместо package пишите тот пак который у вас в проекте.
Открываем создавшийся файл Main.java и вносим в него одну строку, между super.onCreate() и setContentView().
Вот как оно будет выглядеть полностью:
Main.java
Дальше нам нужно создать класс GameView.java который будет производить отрисовку нашей графики на сцене и унаследуем его от класса SurfaceView, для того что бы производить
GameView.java
Для отрисовки мы вызываем метод OnDraw() который реализуется непосредственно программистом в коде игры. Что бы представить как работает Canvas — можете представить его как доску на которой можно рисовать то, что Вам вздумается. Для того что бы рисовать на сцене (Canvas) — получаем команду рисовать, при помощи функции OnDraw().
Рисование будет происходить в отдельном потоке для того что бы при отрисовке в нужный момент мы могли получить картинку для этого мы блокируем Canvas, а для продолжения рисования разблокируем его.
Мы должны принять во внимание, что во время отрисовки у нас есть ресурс который заблокирован и мы теряем производительность и очень важно, свести к минимуму время блокировки. Пока что у Вас должно получиться только вот такое:

Добавляем анимацию
Теперь можно добавить немного анимации, пусть наша картинка движется в каком-то направлении, я хочу что бы она медленно передвигалась вправо. Вот сейчас мы это и сделаем.
Игра это цикл повторений. Основные направления деятельности:
1. Физика обновления, это обновление данных игры, как, например х и у координаты позиции для маленьких символов.
2. Рисование, это отрисовка картинки, которую вы видите на экране. При вызове этого метода оно дает вам восприятие анимации.
Мы собираемся выполнить цикл игры в отдельном потоке. В одном потоке мы создаем обновления и рисование, а в основном потоке мы обрабатываем события. Для этого создаем еще один файл GameManager.java и вставляем в него следующий код:
GameManager.java
Работает поле флаг, позволяющий остановить цикл игры. Внутри цикла мы вызываем метод OnDraw() о котором мы узнали в прошлом уроке. В этом случае для простоты мы делаем обновление и рисование в OnDraw() методе. Мы используем синхронизации, чтобы избежать других потоков, что бы потоки не конфликтовали.
В SurfaceView мы просто добавим интовое поле int х, координата по которой будет двигаться наша картинка Кроме того, в методе OnDraw() мы увеличиваем х на 1, если он не достиг правой границы, конечно же мы это будет делать на нашей сцене, а значит в файле GameView.java. Вот какой вид будет иметь GameView.java
GameView.java
Мы ограничили отрисовку до 10 кадров в секунду, что составляет 100 мс (миллисекунды). Мы используем метод sleep() за оставшееся время, чтобы получить 100 мс. Если цикл занимает больше, чем 100 мс мы спим 10 мс в любом случае, наше приложение будет требовать слишком много памяти процессора. Немного усложним код, в GameManager.java заменяем старый код на этот:
GameManager.java
В итоге должно получиться то же самое изображение только оно движется в правую сторону.
Для начала просто нарисуем ic_launcher.png на нашем Surface.
Для этого — создаем проект — Eclipse — New — Android project — MyFirstGame — Main.java.
Заходим в res/layout/main.xml и пишем вот такое:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<package.GameView
android:id="@+id/game"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
Вместо package пишите тот пак который у вас в проекте.
Открываем создавшийся файл Main.java и вносим в него одну строку, между super.onCreate() и setContentView().
//эта строка позволяет спрятать верхнее меню с экрана телефона
requestWindowFeature(Window.FEATURE_NO_TITLE);
Вот как оно будет выглядеть полностью:
Main.java
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
public class Main extends Activity {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new GameView(this));
}
}
Дальше нам нужно создать класс GameView.java который будет производить отрисовку нашей графики на сцене и унаследуем его от класса SurfaceView, для того что бы производить
GameView.java
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.View;
public class GameView extends SurfaceView {
/**Загружаемая картинка*/
private Bitmap bmp;
/**Наше поле рисования*/
private SurfaceHolder holder;
//конструктор
public GameView(Context context)
{
super(context);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback()
{
public void surfaceDestroyed(SurfaceHolder holder)
{
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
Canvas c = holder.lockCanvas(null);
onDraw(c);
holder.unlockCanvasAndPost(c);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
}
});
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
}
//Рисуем нашу картинку на черном фоне
protected void onDraw(Canvas canvas)
{
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(bmp, 10, 10, null);
}
}
Для отрисовки мы вызываем метод OnDraw() который реализуется непосредственно программистом в коде игры. Что бы представить как работает Canvas — можете представить его как доску на которой можно рисовать то, что Вам вздумается. Для того что бы рисовать на сцене (Canvas) — получаем команду рисовать, при помощи функции OnDraw().
Рисование будет происходить в отдельном потоке для того что бы при отрисовке в нужный момент мы могли получить картинку для этого мы блокируем Canvas, а для продолжения рисования разблокируем его.
Мы должны принять во внимание, что во время отрисовки у нас есть ресурс который заблокирован и мы теряем производительность и очень важно, свести к минимуму время блокировки. Пока что у Вас должно получиться только вот такое:
Добавляем анимацию
Теперь можно добавить немного анимации, пусть наша картинка движется в каком-то направлении, я хочу что бы она медленно передвигалась вправо. Вот сейчас мы это и сделаем.
Игра это цикл повторений. Основные направления деятельности:
1. Физика обновления, это обновление данных игры, как, например х и у координаты позиции для маленьких символов.
2. Рисование, это отрисовка картинки, которую вы видите на экране. При вызове этого метода оно дает вам восприятие анимации.
Мы собираемся выполнить цикл игры в отдельном потоке. В одном потоке мы создаем обновления и рисование, а в основном потоке мы обрабатываем события. Для этого создаем еще один файл GameManager.java и вставляем в него следующий код:
GameManager.java
import android.graphics.Canvas;
public class GameManager extends Thread {
/**Объект класса*/
private GameView view;
/**Переменная задавания состояния потока рисования*/
private boolean running = false;
/**Конструктор класса*/
public GameManager(GameView view)
{
this.view = view;
}
/**Задание состояния потока*/
public void setRunning(boolean run)
{
running = run;
}
/** Действия, выполняемые в потоке */
public void run() {
while (running) {
Canvas c = null;
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
view.onDraw(c);
}
} finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
}
}
}
Работает поле флаг, позволяющий остановить цикл игры. Внутри цикла мы вызываем метод OnDraw() о котором мы узнали в прошлом уроке. В этом случае для простоты мы делаем обновление и рисование в OnDraw() методе. Мы используем синхронизации, чтобы избежать других потоков, что бы потоки не конфликтовали.
В SurfaceView мы просто добавим интовое поле int х, координата по которой будет двигаться наша картинка Кроме того, в методе OnDraw() мы увеличиваем х на 1, если он не достиг правой границы, конечно же мы это будет делать на нашей сцене, а значит в файле GameView.java. Вот какой вид будет иметь GameView.java
GameView.java
public class GameView extends SurfaceView {
/**Загружаемая картинка*/
private Bitmap bmp;
/**Наше поле рисования*/
private SurfaceHolder holder;
/**Объект класса GameManager*/
private GameManager gameLoopThread;
/** Координата движения по Х=0*/
private int x = 0;
/**Скорость изображения = 1*/
private int xSpeed = 1;
public GameView(Context context)
{
super(context);
gameLoopThread = new GameManager(this);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback()
{
/** Уничтожение области рисования */
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
gameLoopThread.setRunning(false);
while (retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
/** Создание области рисования */
public void surfaceCreated(SurfaceHolder holder)
{
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
/** Изменение области рисования */
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
}
});
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
}
@Override
protected void onDraw(Canvas canvas)
{
if (x == getWidth() - bmp.getWidth())
{
xSpeed = -1;
}
if (x == 0)
{
xSpeed = 1;
}
x = x + xSpeed;
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(bmp, x , 10, null);
}
}
Мы ограничили отрисовку до 10 кадров в секунду, что составляет 100 мс (миллисекунды). Мы используем метод sleep() за оставшееся время, чтобы получить 100 мс. Если цикл занимает больше, чем 100 мс мы спим 10 мс в любом случае, наше приложение будет требовать слишком много памяти процессора. Немного усложним код, в GameManager.java заменяем старый код на этот:
GameManager.java
public class GameManager extends Thread
{
/**Наша скорость в мс = 10*/
static final long FPS = 10;
/**Объект класса GameView*/
private GameView view;
/**Задаем состояние потока*/
private boolean running = false;
/**Конструктор класса*/
public GameManager(GameView view)
{
this.view = view;
}
/**Задание состояния потока*/
public void setRunning(boolean run)
{
running = run;
}
/** Действия, выполняемые в потоке */
@Override
public void run()
{
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running) {
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
view.onDraw(c);
}
} finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e) {}
}
}
}
В итоге должно получиться то же самое изображение только оно движется в правую сторону.
Комментариев нет:
Отправить комментарий