J2J.RU - cовременная система продвижения сайтов
Меню сайта

Категории раздела

Наш опрос
Меня больше интересуют приложения и игры для:
Всего ответов: 22

Файлы
Новые Популярные Лучшие


Теги
Android (34)
uCoz (8)
mobile (3)
sistem (3)
xml (3)
google (2)
html (2)
Oboi (2)
opera (2)
Rest (2)
soap (2)
action (1)
ajax (1)
App2SD (1)
apps (1)
CSS (1)
Ddms (1)
editor (1)
gmail (1)
gobook (1)
java (1)
legend (1)
Lite (1)
live (1)
mp3 (1)
mrtm (1)
Muse (1)
ninja (1)
pdf (1)
php (1)
Root (1)
sensor (1)
shazam (1)
sql (1)
thread (1)
touch (1)
UI (1)
Widget (1)
Worms (1)
Xplore (1)
Zirco (1)

RSS
  
Новостная лента.

Форумная лента.

Файловая лента.  

Главная » Статьи » Программинг » Программирование [ Добавить статью ]

Пишем игру для Android. Часть 4 - Спрайтовая анимация

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


Давайте на какое-то время отвлечемся от игры и поговорим об анимации вообще. Представим, что нам требуется нарисовать человечка, который шагает слева направо по экрану. Как это можно реализовать? Обычно новичкам эта задача кажется непомерно трудной. На самом деле здесь нет ничего сложного. Идея взята из кинематографа. У нас должен быть набор изображений, представляющий собой "фотографии" нашего человечка в разные, достаточно близкие,  моменты времени. Быстро меняя кадры, мы увидим, что наша картинка начала двигаться. Ситуацию с походкой упрощает тот факт, что она носит периодический характер. Грубо говоря, чтобы получить красивую и достоверную анимацию нам достаточно иметь кадры с момента, когда человечек опирается, скажем, на левую ногу, до момента, когда он сделав два шага вновь на нее обопрется.

Давайте рассмотрим пример, состоящий из нескольких кадров. Не будем заморачиваться на графике и возьмем готовый рисунок из некогда популярной компьютерной игры Monkey Island.

В компьютерной графике и gamedev-е широко используется понятие спрайт (sprite). В современной трактовке оно означает графический объект, который может перемешаться по экрану и при этом изменять свой вид. Со спрайтом связан рисунок, содержащий раскадровку и, в зависимости от ситуации, спрайт имеет вид того или иного кадра. Ниже приведет пример рисунка с последовательностью кадров, который будет использоваться нами для создания спрайта. 

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

Чтобы создать анимацию мы можем загрузить каждый кадр, как отдельную картинку и затем через равные интервалы времени выводить их последовательно на экран. Можно сделать по-другому: загрузить одну картинку, содержащую все кадры, а затем налету разбивать ее на кадры и выводить требуемый в данный момент кадр.  На самом деле это довольно просто. Мы знаем, что наша картинка содержит 5 кадров шириной 30 пикселей. Определим прямоугольник, имеющий ширину кадра (30 точек) и высоту всего изображения. На приведенном ниже рисунке синими прямоугольниками отмечены первые два кадра.

Давайте создадим проект. За основу возьмем разработанный на предыдущих уроках пример Droid_03. Добавим в папку res/drawable-mdpi проекта файл walk_elaine.png Создадим новый класс для нашего персонажа. Поскольку в Monkey Island персонаж зовут Elaine, назовем класс ElaineAnimated.

public class ElaineAnimated {
 
 private static final String TAG = ElaineAnimated.class.getSimpleName();
 
 private Bitmap bitmap; // Картинка с анимационной последовательностью
 private Rect sourceRect; // Прямоугольная область в bitmap, которую нужно нарисовать
 private int frameNr; // Число кадров в анимации
 private int currentFrame; // Текущий кадр
 private long frameTicker; // время обновления последнего кадра
 private int framePeriod; // сколько миллисекунд должно пройти перед сменой кадра (1000/fps)
 
 private int spriteWidth; // ширина спрайта (одного кадра)
 private int spriteHeight; // высота спрайта
 
 private int x; // X координата спрайта (верхний левый угол картинки)
 private int y; // Y координата спрайта (верхний левый угол картинки)
}

Здесь bitmap - png рисунок, содержащий все кадры; sourceRect - прямоугольная область, которая "очерчивает" в рисунке границы текущего кадра; frameTicker - переменная, содержащая время, которое прошло с момента последной смены кадра анимации. Указанная в комментарии переменная fps обозначает не fps игры, а fps спрайта, то есть сколько раз изменяется кадр спрайта за секунду. Для плавной анимации это значение должно иметь величину порядка 25-30, однако для наших учебных целей подойдет и более скромное число 5. Мы не можем поставить здесь большее значение, поскольку у нас всего 5 кадров в рисунке. framePeriod  - период между сменой кадра в миллисекундах. Для нашего случая, когда мы хотим менять 5 кадров в секунду эта величина равна 200 мс.

Напишем конструктор

public ElaineAnimated(Bitmap bitmap, int x, int y, int width, int height, int fps, int frameCount) {
 this.bitmap = bitmap;
 this.x = x;
 this.y = y;
 currentFrame = 0;
 frameNr = frameCount;
 spriteWidth = bitmap.getWidth() / frameCount;
 spriteHeight = bitmap.getHeight();
 sourceRect = new Rect(0, 0, spriteWidth, spriteHeight);
 framePeriod = 1000 / fps;
 frameTicker = 0l;
 }

Подразумевается, что кадры имеют одинаковую ширину, поэтому spriteWidth вычисляется, как общая ширина рисунков поделенная на число кадров. В конструктор передается параметр fps, который обозначает число кадров спрайта в секунду.

Добавим в конструктор класса MainGamePanel строку, создающую объект для нашего нового анимированного персонажа

 
public MainGamePanel(Context context) {
 super(context);
 // Сообщаем, что обработчик событий от поверхности будет реализован
 // в этом классе.
 getHolder().addCallback(this);
 elaine = new ElaineAnimated(
 BitmapFactory.decodeResource(getResources(), R.drawable.walk_elaine)
 , 10, 50 // начальное положение
 , 30, 47 // ширина и высота спрайта
 , 5, 5); // FPS и число кадров в анимации
...


Добавим в класс метод update, который будет изменять текущий кадр в зависимости от текущего времени. Мы специально не привязываемся к частоте обновления игрового цикла, чтобы не нарушать процессор лишней работой. Например, допустим, что наша программа запущена на очень продвинутом телефоне, который обеспечивает проход итерации игрового цикла за 20 мс, допустим также, что менять картинку спрайта нужно раз в 200 мс, таким образом, мы должны обновлять спрайт каждый десятый шаг игрового цикла.

public void update(long gameTime) {
 if (gameTime > frameTicker + framePeriod) {
 frameTicker = gameTime;
 // увеличиваем номер текущего кадра
 currentFrame++;
 //если текущий кадр превышает номер последнего кадра в 
 // анимационной последовательности, то переходим на нулевой кадр
 if (currentFrame >= frameNr) {
 currentFrame = 0; 
 }
 }
 // Определяем область на рисунке с раскадровкой, соответствующую текущему кадру
 this.sourceRect.left = currentFrame * spriteWidth;
 this.sourceRect.right = this.sourceRect.left + spriteWidth;
}


Этот метод получает в качестве параметра текущее время и если это время превышает сумму времени последнего обновления (frameTicker) и длительности показа кадра (framePeriod), то необходимо перейти к показу следующего кадра. Для этого увеличиваем на единицу значение переменная  currentFrame, а затем на основании ее значения вычисляем заново границы кадра (sourceRect.left и sourceRect.right).

Внесем изменение в метод update класса MainGamePanel

public void update() {
 elaine.update(System.currentTimeMillis());
...


Теперь у нашего спрайта меняются кадры, но мы не видим этого. Добавим в класс  ElaineAnimated метод  draw, который будет выводить на экран текущий кадр

 public void draw(Canvas canvas) {
 // область, где рисуется спрайт
 Rect destRect = new Rect(x, y, x + spriteWidth, y + spriteHeight);
 //комманда вывода рисунка на экран.
 canvas.drawBitmap(bitmap, sourceRect, destRect, null);
 }

Команда canvas.drawBitmap рисует прямоугольную область sourceRect из рисунка bitmap в прямоугольной области destRect.

Изменим также метод onDraw, добавив туда вызов метода перерисовки спрайта

 protected void onDraw(Canvas canvas) {
 // Заливаем canvas черным цветом
 canvas.drawColor(Color.BLACK); 
 //рисуем анимированный спрайт
 elaine.draw(canvas);
...


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

public void draw(Canvas canvas) {
 // область, где рисуется спрайт
 Rect destRect = new Rect(x, y, x + spriteWidth, y + spriteHeight);
 canvas.drawBitmap(bitmap, sourceRect, destRect, null);
 canvas.drawBitmap(bitmap, 20, 150, null);
 Paint paint = new Paint();
 paint.setARGB(50, 0, 255, 0);
 canvas.drawRect(20 + (currentFrame * destRect.width()), 150, 20 + 
 (currentFrame * destRect.width()) + destRect.width(), 150 + destRect.height(), paint);
}
 


Категория: Программирование | Добавил: Virus (29.11.2012)

Похожие темы на пост "Пишем игру для Android. Часть 4 - Спрайтовая анимация"

Схожие темы выбранные по тегам : gamedev, часть, игру, Спрайтовая, Android., пишем, анимация
  
Просмотров: 2483 | Рейтинг: 0.0/0

Дорогие пользователи и гости сайта!!! Пожалуйста, если вам не сложно, оставте комментарий или ваше мнение о портале в Гостевой книге. Ваше мнение очень важно для нас и очень поможет в поиске дальнейшего пути развития сайта. С уважением, Администрация сайта AndroBum!



Так же рекомендуем:
Всего комментариев: 0
Информация:
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.

[ Регистрация | Вход ]
Поиск

Мини-чат

Block title
Virus
файлов: 69
Постов: 38
Комментов: 1005
Репутация: 0
Ранг:

droid
файлов: 3
Постов: 0
Комментов: 0
Репутация: 100
Ранг:

Serge
файлов: 1
Постов: 0
Комментов: 0
Репутация: 0
Ранг:

Sergey
файлов: 1
Постов: 0
Комментов: 0
Репутация: 0
Ранг:

Аватар не установлен! Blackfoxxx
файлов: 0
Постов: 0
Комментов: 0
Репутация: 0
Ранг:


Друзья сайта
  • Официальный блог
  • скрипты, шаблоны, html, css
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz

  • Статистика Сайта
    Статистика сайта как на сайте

    Пользователей всего: +0
    Материалов всего [?]: +
    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0
    Гости сайта Пользователи

    Яндекс.Метрика




    Пользователи онлайн:


    Flag Counter



    Все материалы размещенные на сайте принадлежат их владельцам.
    Copyright dodomo.do.am © 2010-2012