Назад
Вперед
6.4. Спрайтовая анимация
В этом примере мы покажем, как можно
использовать многопоточность для организации в
приложениях Java спрайтовой анимации.
Исходный текст примера
Архив проекта для Java WorkShop 2.0
Демонстрация
(ваш браузер должен уметь работать с аплетами
Java JDK 1.1)
Немного теории
Многопоточность находит свое применение в
создании анимационных изображений, оживляющих
приложения Java.
Как создать анимацию?
Простейший способ заключается в использовании
спрайтов - набора изображений для всех кадров
анимации. При поочередном отображении этих
кадров в окне приложения с достаточно высокой
скоростью возникает эффект анимации.
Прежде чем приложение Java приступит к анимации,
оно должно дождаться завершения загрузки всех
кадров. Это необходимо потому, что время загрузки
файлов отдельных спрайтов через сеть Internet может
быть значительным. К счастью, приложениям Java
доступен класс MediaTracker, специально
предназначенный для решения такой задачи.
Что же касается самого процесса рисования
спрайтов, то он должен выполняться в отдельном
потоке при помощи метода drawImage.
Описание примера
Наш пример аплета рисует в своем окне фрагмент
неба с облаками, который раскачивается из одной
стороны в другую. В верхней части окна вы можете
увидеть номер текущего отображаемого
фрейма (рис. 1).
Рис. 1. Бегущие облака в окне аплета
Сразу после инициализации аплет приступает к
загрузке спрайтов, о чем можно судить по стоке
Loading (рис. 2).
Рис. 2. Идет загрузка файлов отдельных спрайтов
Рассмотрим исходный текст аплета.
Главный класс аплета
Главный класс аплета создан на базе класса Applet
и реализует интерфейс Runnable:
import java.applet.Applet;
import java.awt.*;
public class SkyMove extends Applet
implements Runnable
{
. . .
}
В нем мы определили четыре поля.
Поле thr класса Thread хранит ссылку на поток,
выполняющий анимацию в окне аплета:
Thread thr = null;
Поле bImagesLoaded используется как признак
завершения процесса загрузки изображений
спрайтов:
boolean bImagesLoaded = false;
В поле nCurrentImage мы храним номер текущего спрайта,
отображаемого в процессе анимации:
int nCurrentImage = 0;
И, наконец, массив im хранит ссылки на все
изображения спрайтов, составляющих анимацию:
Image[] im;
Методы start и stop
Эти методы запускают и останавливают поток
анимации, соответственно, при активизации аплета
и при прекращении его работы:
public void start()
{
if(thr == null)
{
thr = new Thread(this);
thr.start();
}
}
public void stop()
{
if(thr != null)
{
thr.stop();
thr = null;
}
}
Они устроены также, как и аналогичные методы в
наших предыдущих приложениях.
Метод run
Рассмотрим исходный текст метода run.
Прежде всего этот метод устанавливает
начальное значение для номер текущего
отображаемого кадра анимации, равное нулю:
nCurrentImage = 0;
Далее если изображения еще не загружены (а
сразу после первого запуска метода run так оно и
будет), метод выполняет в цикле загрузку всех
спрайтов:
if(!bImagesLoaded)
{
im = new Image[40];
MediaTracker mt = new MediaTracker(this);
String s;
for(int i = 1; i < 41; i++)
{
s = "pic" + ((i < 10) ? "0" : "")
+ i + ".gif";
im[i - 1] =
getImage(getDocumentBase(), s);
mt.addImage(im[i - 1], 0);
}
. . .
}
Ссылки на загруженные изображения
записываются в массив im.
Чтобы дождаться завершения процесса загрузки,
мы пользуемся методом waitForAll:
try
{
mt.waitForAll();
bImagesLoaded = !mt.isErrorAny();
}
catch(InterruptedException ie)
{
stop();
}
Этот метод возвращает признак успешного
завершения загрузки, инверсное значение
которого сохраняется в переменной bImagesLoaded.
На следующем этапе загруженные спрайты будут
отображаться в окне аплета.
Вначале мы получаем ссылку на контекст
отображения g и устанавливаем флаг направления
отображения спрайтов flip:
Graphics g = getGraphics();
boolean flip = true;
При этом спрайты будут отображаться в прямом
направлении, то есть от первого к последнему.
Отображение выполняется в цикле и только при
условии, что все изображения загружены:
while(true)
{
if(bImagesLoaded)
{
. . .
}
}
Мы рисуем спрайт (методом drawImage) и его номер
(методом drawString):
g.drawImage(im[nCurrentImage],
0, 0, null);
g.drawString("Frame: " +
(nCurrentImage + 1), 10, 30);
Далее мы проверяем флаг направления
отображения спрайтов и изменяем соответствующим
образом номер текущего спрайта:
if(flip)
{
nCurrentImage++;
if(nCurrentImage > 38)
flip = false;
}
else
{
nCurrentImage--;
if(nCurrentImage < 1)
flip = true;
}
В конце каждой итерации выполняется задержка
на 30 миллисекунд:
try
{
thr.sleep(30);
}
catch(InterruptedException ie)
{
stop();
}
Метод paint
Исходный текст метода paint выглядит следующим
образом:
public void paint(Graphics g)
{
if(!bImagesLoaded)
g.drawString("Loading...", 10, 30);
}
Если изображения не загружены, метод рисует в
окне строку "Loading...". После загрузки данная
строка затирается спрайтами.
Назад Вперед |