Сегодня мы будем устанавливать нашим спрайтам случайную скорость по х и у. При этом, спрайт будет начинать движение со случайных координат, которое будет меняться каждый раз как он будет достигает границы экрана. Для тех кто не читал предыдущие статьи — желательно прочитать сперва их, ниже приведены ссылки:
Если Вы прочли эти статьи, значит Вы можете продолжать дальше, начнем с первой части названия статьи.
Sprite.java
Наш спрайт содержит 4 анимации с 3 кадрами в каждой строке.
В зависимости от направления мы должны показать разную анимацию, например:
Нам нужна функция, которая получает в качестве параметров xSpeed и ySpeed и возвращает строку, которую мы будем использовать для создания анимации [0,1,2,3]
Мы собираемся использовать функцию Math.atan2(xSpeed, ySpeed) для расчета направления спрайтов во время выполнения функции.
atan2(х, у) дает угол радиана в double из (-PI до PI), но мы просто хотим получить результат в int — от 0 до 3, чтобы узнать, какую анимацию мы должны использовать.
Давайте рассмотрим следующий рисунок, я описываю координатами (х, у) каждое направление на спрайте, что у нас имеется: вверх (0, -1), вправо (1,0), вниз (0,1) и влево (0, -1).
Хорошо, теперь самая сложная часть, я решил это с помощью этой функции и одной константы массива:
Sprite.java
Ниже я пытаюсь объяснить Вам, что я делаю в этой функции:
Добавляем в конец класса Sprite.java код который я написал выше и переходим к следующей части названия статьи.
В этой части статьи мы будем создавать несколько спрайтов. Каждый спрайт будет иметь собственные позиции, скорости и ориентации движения.
Для начал изменим наш главный класс рисования — GameView.java для внесения в него списка спрайтов. Добавим в начало класса:
Нам нужно скопировать все спрайты которые Вы создали в каталоге drawable, как мы делали с bad1.png во втором уроке. Затем мы создадим новый спрайт с каждым изображением.
GameView.java
Создаем новый метод который будет возвращать изображение спрайта:
GameView.java
и обновляем onDraw():
GameView.java
Если мы запустим игру то увидим что все спрайты расползаются с одной точки, это наверно нужно исправить :)
Добавляем простые две строчки в конструктор Sprite.java:
Sprite.java
Но если Вы сейчас запустите проект то получите сообщение об ошибке потому что width у нас равен 0. Если Вы помните, мы используем метод в surfaceCreated, который знает когда запущена сцена и когда можно рисовать. Для исправления проблемы нам нужно записать в surfaceCreated() метод создания спрайтов, т.е. createSprites();
GameView.java
Все, проблема решена, игра работает. Запускаем и смотрим как человечки бегают по экрану :)
- Пишем игру под Android: Часть 1 — Рисуем картинки на SurfaceView
- Пишем игру под Android: Часть 2 — Создаем первый спрайт
- Пишем игру под Android: Часть 3 — Спрайтовая анимация, работа с несколькими спрайтами
- Пишем игру под Android: Часть 4 — onTouchEvent и определение столкновений
- Пишем игру под Android: Часть 5 — Создание полноценной 2D игры
- Пишем игру под Android: Часть 6: Добавление звука
- Пишем игру под Android: Часть 7: Меню для игры и окно приветствия
- Пишем игру под Android: Часть 8: Фоновая музыка в игре
Если Вы прочли эти статьи, значит Вы можете продолжать дальше, начнем с первой части названия статьи.
Спрайтовая анимация
Открываем наш проект и пишем следующий код:Sprite.java
import java.util.Random;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
public class Sprite {
/**Рядков в спрайте = 4*/
private static final int BMP_ROWS = 4;
/**Колонок в спрайте = 3*/
private static final int BMP_COLUMNS = 3;
/**Объект класса GameView*/
private GameView gameView;
/**Картинка*/
private Bitmap bmp;
/**Позиция по Х=0*/
private int x = 5;
/**Позиция по У=0*/
private int y = 0;
/**Скорость по Х=5*/
private int xSpeed = 5;
private int ySpeed = 5;
/**Текущий кадр = 0*/
private int currentFrame = 0;
/**Ширина*/
private int width;
/**Ввыоста*/
private int height;
/**Конструктор*/
public Sprite(GameView gameView, Bitmap bmp)
{
this.gameView = gameView;
this.bmp = bmp;
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
Random rnd = new Random();
xSpeed = rnd.nextInt(10)-5;
ySpeed = rnd.nextInt(10)-5;
}
/**Перемещение объекта, его направление*/
private void update()
{
if (x >= gameView.getWidth() - width - xSpeed || x + xSpeed <= 0)
{
xSpeed = -xSpeed;
}
x = x + xSpeed;
if (y >= gameView.getHeight() - height - ySpeed || y + ySpeed <= 0)
{
ySpeed = -ySpeed;
}
y = y + ySpeed;
currentFrame = ++currentFrame % BMP_COLUMNS;
}
/**Рисуем наши спрайты*/
public void onDraw(Canvas canvas)
{
update();
int srcX = currentFrame * width;
int srcY = getAnimationRow() * height;
Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
Rect dst = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, src, dst, null);
}
}
Наш спрайт содержит 4 анимации с 3 кадрами в каждой строке.
В зависимости от направления мы должны показать разную анимацию, например:
Нам нужна функция, которая получает в качестве параметров xSpeed и ySpeed и возвращает строку, которую мы будем использовать для создания анимации [0,1,2,3]
Мы собираемся использовать функцию Math.atan2(xSpeed, ySpeed) для расчета направления спрайтов во время выполнения функции.
atan2(х, у) дает угол радиана в double из (-PI до PI), но мы просто хотим получить результат в int — от 0 до 3, чтобы узнать, какую анимацию мы должны использовать.
Давайте рассмотрим следующий рисунок, я описываю координатами (х, у) каждое направление на спрайте, что у нас имеется: вверх (0, -1), вправо (1,0), вниз (0,1) и влево (0, -1).
Когда результат равен углу одного из заданных направлений спрайта мы будем использовать соответствующее движение — вверх, вправо, вниз или влево. Для этого я использую Math.round функции.
Хорошо, теперь самая сложная часть, я решил это с помощью этой функции и одной константы массива:
Sprite.java
// direction = 0 up, 1 left, 2 down, 3 right,
// animation = 3 up, 1 left, 0 down, 2 right
int[] DIRECTION_TO_ANIMATION_MAP = { 3, 1, 0, 2 };
private int getAnimationRow() {
double dirDouble = (Math.atan2(xSpeed, ySpeed) / (Math.PI / 2) + 2);
int direction = (int) Math.round(dirDouble) % BMP_ROWS;
return DIRECTION_TO_ANIMATION_MAP[direction];
}
Ниже я пытаюсь объяснить Вам, что я делаю в этой функции:
- с atan2(xSpeed, ySpeed) Я получаю радиан угла из (-PI до PI)
- Я делю угол PI / 2 и получаю вдвое больше по сравнению с (-2 до 2)
- Я добавляю 2 для изменения диапазона от (0 до 4)
- Я использую %, чтобы уменьшить диапазон (от 0 до 3) (0 и 4, были в том же направлении)
- Задаем на карте каждой строке — направление, к нужной анимации с использованием массива {3, 1, 0, 2}
Добавляем в конец класса Sprite.java код который я написал выше и переходим к следующей части названия статьи.
Работа с несколькими спрайтами
В этой части статьи мы будем создавать несколько спрайтов. Каждый спрайт будет иметь собственные позиции, скорости и ориентации движения.
Для начал изменим наш главный класс рисования — GameView.java для внесения в него списка спрайтов. Добавим в начало класса:
private List<Sprite> sprites = new ArrayList<Sprite>();
Нам нужно скопировать все спрайты которые Вы создали в каталоге drawable, как мы делали с bad1.png во втором уроке. Затем мы создадим новый спрайт с каждым изображением.
GameView.java
sprites.add(createSprite(R.drawable.bad1));
sprites.add(createSprite(R.drawable.bad2));
sprites.add(createSprite(R.drawable.bad3));
sprites.add(createSprite(R.drawable.bad4));
sprites.add(createSprite(R.drawable.bad5));
sprites.add(createSprite(R.drawable.bad6));
sprites.add(createSprite(R.drawable.good1));
sprites.add(createSprite(R.drawable.good2));
sprites.add(createSprite(R.drawable.good3));
sprites.add(createSprite(R.drawable.good4));
sprites.add(createSprite(R.drawable.good5));
sprites.add(createSprite(R.drawable.good6));
Создаем новый метод который будет возвращать изображение спрайта:
GameView.java
private Sprite createSprite(int resouce) {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resouce);
return new Sprite(this,bmp);
}
и обновляем onDraw():
GameView.java
for(Sprite sprite : sprites) {
sprite.onDraw(canvas);
}
Если мы запустим игру то увидим что все спрайты расползаются с одной точки, это наверно нужно исправить :)
Добавляем простые две строчки в конструктор Sprite.java:
Sprite.java
x = rnd.nextInt(gameView.getWidth() - width);
y = rnd.nextInt(gameView.getHeight() - height);
Но если Вы сейчас запустите проект то получите сообщение об ошибке потому что width у нас равен 0. Если Вы помните, мы используем метод в surfaceCreated, который знает когда запущена сцена и когда можно рисовать. Для исправления проблемы нам нужно записать в surfaceCreated() метод создания спрайтов, т.е. createSprites();
GameView.java
public void surfaceCreated(SurfaceHolder holder) {
createSprites();
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
Все, проблема решена, игра работает. Запускаем и смотрим как человечки бегают по экрану :)
Спасибо, за проделанную работу! Осталось собраться и реализовать задуманное:)
ОтветитьУдалитьВ следующем уроке расскажу как удалить объекты с экрана. Будем убивать человечков =)
ОтветитьУдалитьБудем ждать =)
ОтветитьУдалитьсделал на основе твоего урока за пару часов типа игры -перетаскивать человечков http://dl.dropbox.com/u/6114624/MultiplySprites.apk
ОтветитьУдалитьhttp://dl.dropbox.com/u/6114624/multsprytes.zip
чтоб они в квадрат не попали,без подсчета очков и тд,но как демонстрация актуальности твоих уроков самое то,особенно учитывая что я начинающий в андроиде да и в самой java
Событие онТач я буду рассматривать в 4й части)) Забежал даже дальше чем я рассказал)
УдалитьУхты,Спасибо большущее за такие материалы. Сам не тупой, по английски читаю кой че, но на родном языке явно легче разобратся -_-. Спасиб
ОтветитьУдалитьПожалуйста.
УдалитьВ конструкторе спрайта при рандоме приложение вылетает, а когда явно задаёшь число (x=50 или y=50), то всё запускается. Пробовал рандом вынести в GameView.java - тоже самое. В чем может быть проблема ?
ОтветитьУдалить50 это очень много. Явно с таким я не сталкивался, но я точно могу сказать что 10 вам будет достаточно, этот параметр означает скорость, вы ставите около 400 фпс, вот у вас оно и вылетает скорее всего, попробуйте поменьше числа ставить.
Удалить