Устранение эффекта мигания в играх. Двойная буферизация

Автор: content Вторник, Апрель 10th, 2012 Нет комментариев

Рубрика: Java Mobile

В состав Mobile Information Device Profile (MIDP) входит низкоуровневый пользовательский интерфейс, позволяющий рисовать непосредственно на экране устройства. В статье «MIDP низкоуровневый API пользовательского интерфейса» рассказывается как использовать классы API для рисования. Эта статья является ее логическим продолжением. Мы обсудим вопрос использования двойной буферизации для создания «не мигающей» графики.

Термин «двойная буферизация» обозначает технику, широко использующуюся в компьютерной графике. Если рассматривать дисплей как буфер памяти в который осуществляется запись графических примитивов (рисование примитивов осуществляется базовыми методами, такими как drawLine и drawArc), то двойная буферизация — это запись во второй буфер, который не отображается, а затем копирование его содержания в экранный буфер. Операция копирования осуществляется очень быстро, поэтому обновление экрана происходит плавно. Как правило, при рисовании в буфер экрана напрямую, все операции рисования не укладываются в промежуток времени между двумя обновлениями экрана. В результате пользователь видит промежуточный результат и у него создается впечатление, что картинка все время мигает. Использование двойной буферизации позволяет избежать этого неприятного эффекта.

В MIDP двойная буферизация реализуется очень просто. Нужно использовать класс Image (все классы используемые в данной статье входят в пакет javax.microedition.lcdui) для создания внеэкранного буфера. Это позволяет работать с ним точно также, как и с простым экраном, посредствам методов класса Graphics. Для копирования содержания внеэкранного буфера на дисплей, также используется метод класса Graphics. Вообще, для использования двойной буферизации достаточно изменить пару строк в вашей программе.

Первя вещь, которую вам стоит сделать — это определить, действительно ли необходима двойная буферизация в вашей программе. Возможно двойная буферизация автоматически поддерживается системой. Другими словами, когда система вызывает метод paint класса canvas, объект Graphics, передаваемый этому методу, представляет собой внеэкранный буфер, созданный системой. Система сама заботится о копировании внеэкранного буфера на дисплей. Чтобы узнать, поддерживается ли двойная буферизация, вызовите метод isDoubleBuffered:

public class MyCanvas extends Canvas {

private Image offscreen = null;
private int height;
private int width;

public MyCanvas(){
height = getHeight();
width = getWidth();

if( !isDoubleBuffered() ){
offscreen = Image.createImage( width, height );
}

….. // other initialization as appropriate
}

…… // other code, including paint method
}

Разберем работу приведенного примера. Если isDoubleBuffered возвращает false, конструктор создает внеэкранный буфер, размер которого соответствует размеру экрана. Если двойная буферизация поддерживается системой, isDoubleBuffered возвращает true и буфер не создается.

Внеэкранный буфер создается вызовом Image.createImage. Существуют четыре варианта этого метода.

Загрузка рисунка из JAR файла.
Создание копии существующего изображения.
Создание изображения на основе необработанных двоичных данных.
Создание пустого изображения заданного размера.

Для двойной буферизации используется последний способ. Другие три не подходят, поскольку они создают изображение, которое нельзя изменять, и только последний позволяет модифицировать созданное изображение. После того как изображение создано, Вы можете вызвать метод getGraphics для получения объекта Graphics, который может использоваться для рисования в буфере изображения.

Все рисование осуществляется в методе paint. Этот метод может выглядеть, например, так:

protected void paint( Graphics g ){
g.setColor( 255, 255, 255 );
g.fillRect( 0, 0, width, height );
}

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

protected void paint( Graphics g ){
Graphics saved = g;

if( offscreen != null ){
g = offscreen.getGraphics();
}

g.setColor( 255, 255, 255 );
g.fillRect( 0, 0, width, height );

if( g != saved ){
saved.drawImage( offscreen, 0, 0,
Graphics.LEFT | Graphics.TOP );
}
}

Фактически, все, что Вам надо сделать, это получить объект Graphics внеэкранного буфера и использовать его для рисования. Когда картинка будет нарисована, содержание внеэкранного буфера надо скопировать на экран. Заметьте, что это нужно делать, если двойная буферизация не поддерживается устройством автоматически. В нашем примере вы просто следите за тем, был ли создан внеэкранный буфер. Если буферизация поддерживается, Вы рисуете непосредственно на экране, а о смене буферов заботится система.

Не забывайте о том, что двойная буферизация отъедает часть системных ресурсов: Вам придется потратить часть памяти на создание буфера. Поэтому сведите число вспомогательных буферов к минимуму (вы же понимаете, что можно использовать и несколько внеэкранных буферов) и удаляйте их всякий раз, когда они не нужны. Удаление/восстановление буферов удобно осуществлять внутри переопределенных методов hideNotify и showNotify класса canvas. Если изменения на экране незначительны, двойная буферизация может только замедлить работу приложения. Кроме того на некоторых старых моделях телефонов копирование буферов осуществляется очень медленно и даже использование двойной буферизации не спасает от мигания.

Источник: http://www.javaportal.ru/mobiljava/articles/Elimination_blinking.html
Автор оригинала Eric Giguere Перевод: aRix

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты