Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых
[Назад]

Библиотека примеров приложений Java

Оглавление
Простейший пример
Создание двух потоков
Управление потоками
Спрайтовая анимация
Панели с двигающимся текстом
Бегущая строка с мерцанием
Устранение мерцания
Поток для записи в файл
Контроль за выводом в файл
Чтение с сервера Web

Назад Вперед

6.4. Спрайтовая анимация

В этом примере мы покажем, как можно использовать многопоточность для организации в приложениях Java спрайтовой анимации.

Исходный текст примера

Архив проекта для Java WorkShop 2.0

Демонстрация
(ваш браузер должен уметь работать с аплетами Java JDK 1.1)

Немного теории

Многопоточность находит свое применение в создании анимационных изображений, оживляющих приложения Java.

Как создать анимацию?

Простейший способ заключается в использовании спрайтов - набора изображений для всех кадров анимации. При поочередном отображении этих кадров в окне приложения с достаточно высокой скоростью возникает эффект анимации.

Прежде чем приложение Java приступит к анимации, оно должно дождаться завершения загрузки всех кадров. Это необходимо потому, что время загрузки файлов отдельных спрайтов через сеть Internet может быть значительным. К счастью, приложениям Java доступен класс MediaTracker, специально предназначенный для решения такой задачи.

Что же касается самого процесса рисования спрайтов, то он должен выполняться в отдельном потоке при помощи метода drawImage.

Описание примера

Наш пример аплета рисует в своем окне фрагмент неба с облаками, который раскачивается из одной стороны в другую. В верхней части окна вы можете увидеть номер текущего отображаемого фрейма (рис. 1).

pic1.gif (4179 bytes)

Рис. 1. Бегущие облака в окне аплета

Сразу после инициализации аплет приступает к загрузке спрайтов, о чем можно судить по стоке Loading (рис. 2).

pic2.gif (2366 bytes)

Рис. 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...". После загрузки данная строка затирается спрайтами.


Назад Вперед

[Назад]