Текст книги "Программирование мобильных устройств на платформе .NET Compact Framework"
Автор книги: Иво Салмре
Жанр:
Программирование
сообщить о нарушении
Текущая страница: 37 (всего у книги 69 страниц)
else m_RectangleColor = System.Drawing.Color.Black;
//–
//Освободить старую кисть
//–
m_RectangleBrush.Dispose();
//–
//Создать новую кисть, которую мы собираемся использовать для фона
//–
m_RectangleBrush = new System.Drawing.SolidBrush(m_RectangleColor);
//–
//Сообщить операционной системе, что наш элемент управления
//должен быть перерисован, как только представится возможность
//–
this.Invalidate();
}
//–
//Ради интереса подсчитаем, сколько раз осуществлялась перерисовка
//–
int m_paintCount;
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) {
//–
//ВАЖНО: Вызвать базовый класс и позволить ему
//выполнить работу по рисованию
//–
base.OnPaint(e);
//Увеличить на единицу значение счетчика вызовов
m_paintCount = m_paintCount + 1;
//–
//Важно:
//Вместо того чтобы создавать объект Graphics, мы получаем его
//на время данного вызова. Это означает, что освобождать память путем
//вызова метода .Dispose() объекта – не наша забота
//–
System.Drawing.Graphics myGfx;
myGfx = e.Graphics;
//Нарисовать прямоугольник
myGfx.FillRectangle(m_RectangleBrush, 0, 0, this.Width,this.Height);
//Нарисовать текст
myGfx.DrawString("Button! Paint: " + m_paintCount.ToString(), this.Parent.Font, m_TextBrush, 0, 0);
} //конец функции
} //конец класса
Листинг 11.10. Код, который должен быть помещен в форму для создания экземпляра пользовательского элемента управления
//–
//Этот код будет подключен в качестве нашего обработчика событий
//–
private void CallWhenButtonTurningBlue(object sender, System.EventArgs e) {
System.Windows.Forms.MessageBox.Show("Button is about to turn blue!");
}
//Наша новая кнопка
myButton m_newControl;
//–
//Эта функция подключается для обработки событий
//щелчка на кнопке Button1
//–
private void button1_Click(object sender, System.EventArgs e) {
//–
//Для простоты мы допускаем существование только
//одного экземпляра элемента управления.
//–
if (m_newControl != null) {
return;
}
//Создать экземпляр нашей кнопки
m_newControl = new myButton();
//Указать ему его местоположение внутри родительского объекта
m_newControl.Bounds = new Rectangle(10, 10, 150, 40);
//–
//Присоединить обработчик событий
//–
m_newControl.EventButtonTurningBlue += new System.EventHandler(this.CallWhenButtonTurningBlue);
//Добавить его в список элементов управления данной формы.
//Это сделает его видимым
this.Controls.Add(m_newControl);
}
Создание привлекательной графики – в равной степени и искусство, и ремесло; под этим подразумевается, что одинаково важная роль принадлежит как используемым методикам, так и планированию. Для того чтобы нарисовать на экране одиночный прямоугольник или одиночный фрагмент текста, требуется очень мало времени. Рисование же сложной диаграммы или игрового поля на лету в видимой области экрана, скорее всего, заставят пользователя дожидаться появления результатов в течение некоторого времени. Рассмотрим случай сложной диаграммы, на рисование которой уходит 1,5 секунды. Эта длительность заметно превышает порог человеческого восприятия, и глаз человека в состоянии различить довольно много событий, которые могут произойти на протяжении такого временного промежутка. Если рисование диаграммы состоит из стадий рисования фонового изображения, вычерчивания и сопровождения надписями осей диаграммы, размещения точек, соответствующих фактическим данным, и генерации таблицы ключей, в которой каждый набор данных идентифицируется определенным цветом, то процесс построения диаграммы, происходящий на глазах у пользователя, будет представлять собой весьма неприглядную картину. Результат будет еще более плачевным, если получаемая графика предназначена для динамической игры; в этом случае пользователь столкнется с мерцанием экрана, сопровождающим перерисовку элементов игры при их перемещениях на экране.
Другая причина, по которой не рекомендуется делать процесс рисования видимым для пользователя, заключается в том, что область растровых изображений пользовательского интерфейса обычно не является постоянной. В отличие от внеэкранных битовых карт, принадлежащих вашему коду, экран является разделяемым ресурсом, который совместно используется окнами и элементами управления всех выполняющихся приложений, а также операционной системой. Большинством операционных систем поддержка изображений, которые пользователь может рисовать на поверхности пользовательского интерфейса, не предусматривается. Это означает, что любые изображения, созданные вами в области пользовательского интерфейса, будут утеряны, если окно, в котором ваш код выполнял рисование, будет перекрыто окном другого приложения.
Гораздо менее уязвимым с точки зрения эстетики процесса рисования и подверженности ошибкам является рисование на внеэкранном буфере с последующим копированием результатов на передний план после того, как создание рисунка будет завершено. Кроме того, решения этого типа отличаются лучшей переносимостью, их проще проектировать, сопровождать и отлаживать. Вместо того чтобы погружаться во все тонкости модели рисования, используемой операционной системой, вы можете организовать все так, что изображение будет в максимально возможной степени при надлежать вашему приложению, выполняющему операции рисования в собственном строго определенном окружении и взаимодействующему непосредственно с пользовательским интерфейсом лишь тогда, когда эта работа будет закончена. Подход, основанный на использовании внеэкранных буферов для объектов рисования, почти всегда является наиболее оптимальным для выполнения графических операций любой степени сложности, даже если при этом вам и придется использовать вывод курсора ожидания на период визуализации изображения.
Как уже обсуждалось в предыдущих разделах, в .NET Compact Framework имеются два неплохих способа переноса внеэкранных рисунков в пользовательский интерфейс. Во-первых, это использование элемента управления PictureBox и задание посредством его свойства Image того битового образа, рисование которого вы только что завершили (например, pictureBox1.Image = myNewBitmap).
Второй способ заключается в получении объекта Graphics для того элемента интерфейса, в котором он будет прорисовываться (обычно таковым является объект Form) и вызове метода Graphics.DrawImage() для переноса изображения:
//Получить объект Graphics для формы
System.Drawing.Graphics gfx;
gfx = this.CreateGraphics();
//Нарисовать изображение в объекте с использованием
//начальной точки с координатами x=10, y=15);
gfx.DrawImage(myBitmap, 10, 15);
Следует подчеркнуть, что для метода Graphics.DrawImage() предусмотрено несколько перегруженных версий. Та, которая фигурировала выше, является самой простой и работает быстрее остальных; она просто копирует биты из одного битового образа в другой. Другие перегруженные версии обладают более развитыми возможностями, что позволяет им выполнять такие, например, операции, как перенос в целевое изображение строго определенной области исходного изображения, растягивание или сжатие копируемых изображений или использование масок прозрачности, позволяющих делать прозрачными отдельные области изображения, через которые могут "просматриваться'' другие изображения. Каждая из этих разновидностей метода выполняет определенное преобразование при копировании изображения из объекта-источника в объект назначения. В общем случае, чем сложнее преобразование изображения, которое требует выполнить ваш код, тем дороже оно обходится с точки зрения производительности.
Для поддержания производительности приложения на приемлемом уровне лучше всего стремиться к тому, чтобы исходное и целевое растровые изображения в максимальной степени совпадали друг с другом. По возможности стремитесь к тому, чтобы при переносе изображений создавались их точные битовые копии, а пиксели не растягивались и не сжимались. Маски прозрачности следует использовать лишь тогда, когда в этом есть необходимость. Хотя к .NET Compact Framework это и не относится, но другие среды выполнения могут предлагать вам выбрать количество цветов, которые должны использоваться в изображении, и указать битовую глубину цвета, используемую для поддержания этой информации. Совпадение этой информации для исходного и целевого изображений способно существенно улучшить производительность. Общая задача заключается в сведении к минимуму любых расхождений между исходным и конечным изображениями, чтобы операция переноса изображения была максимально приближена к операции простого копирования битов в память. Оптимизация таких операций для достижения высокой производительности обычно обеспечивается на всех платформах.
Определите собственный процесс визуализацииНетривиальным рисункам свойственна сложная структура. Сначала создают прототип, позволяющий строить диаграммы. В этот прототип добавляются средства, позволяющие не только строить диаграммы, но и снабжать надписями оси. Далее добавляются метки делений, позволяющие задавать, где располагаются точки данных и соединяющие их линии. Затем добавляется поддержка одновременного отображения нескольких наборов данных. После этого добавляется таблица цветовых ключей, идентифицирующих различные наборы данных. Далее добавляется поддержка нескольких цветов. Затем добавляется возможность рисования изображений поверх фонового изображения. Наконец, добавляется возможность присвоения диаграммам названий. Код, предназначенный для построения диаграмм, совершенно неожиданно для вас разрастается до огромных размеров, причем каждая отдельная его часть предусматривает выполнение узкоспециализированной задачи, рассматриваемой в отрыве от контекста обеспечения высокой производительности приложения в целом. Тем же недостатком "нашествия возможностей" страдает и код игр, когда в список того, что должно быть сделано для визуализации игрового поля, постоянно добавляются все новые и новые члены.
В силу указанных причин очень важно не пожалеть времени и постараться рационализировать используемый вами процесс визуализации. Тем самым вы выжмете из своей системы максимально возможную производительность и приобретете дополнительную гибкость в добавлении новых средств. Эта задача должна быть разбита на этапы, позволяющие анализировать любые изменения, вносимые вами в модель визуализации, и рационализировать их на уровне системы, настроенной на обеспечение максимальной общей производительности. Эта работа не является трудной; для этого требуется только записать, какой ряд последовательных действий необходимо выполнить и какие ресурсы используются на каждом шаге.
Рассмотрим следующий пример.
Не рационализированный процесс построения графиков
1. Создать пустую битовую карту (150×150 пикселей).
2. Скопировать фоновое изображение на пустую битовую карту. (Фоновое изображение имеет размеры 150×150 пикселей, непосредственное копирование.)
3. Вычертить координатные оси. (Создаются и уничтожаются перья Red Pen, Blue Pen и Yellow Pen.)
4. Рассчитать количество делений на каждой из осей.
5. Вычертить все линии делений.
6. Вывести текст для каждого деления. (Создается и уничтожается кисть White Brush, создается и уничтожается шрифт 8 пунктов.)
7. Нарисовать данные для каждого из наборов данных, для которых строятся графики. (Создаются и уничтожаются перья Red Pen, Orange Pen, Yellow Pen и Green Pen.)
8. Нарисовать линии между точками.
9. Вычертить квадраты вокруг каждой точки.
10. Нарисовать название графика. (Создается и уничтожается кисть White Brush.)
11. Нарисовать таблицу цветовых ключей, идентифицирующих наборы данных.
12. Нарисовать рамку. (Создается и уничтожается перо White Pen.)
13. Нарисовать шаблонные линии для каждого набора данных. (Создаются и уничтожаются перья Red Pen, Orange Pen, Yellow Pen и Green Pen.)
14. Нарисовать текстовые подписи для каждого набора данных. (Создаются и уничтожаются кисти Red Brush, Orange Brush, Yellow Brush и Green Brush, создается и уничтожается шрифт 8 пунктов.)
Взглянув на описанную выше модель, можно заметить, что мы много раз создаем и уничтожаем одни и те же перья, кисти и шрифты. Можно без особого труда рационализировать эту модель, избавившись от лишних операций распределения ресурсов.
Рассмотрим более рациональный вариант организации процесса построения графиков.
Создание ресурсов
1. Создать битовую карту (150×150 пикселей), если до этого память для нее не была распределена.
2. Создать необходимые перья: Red Pen, Orange Pen, Yellow Pen, Green Pen и Blue Pen.
3. Создать необходимые кисти: White Brush, Red Brush, Orange Brush, Yellow Brush и Green Brush.
4. Создать необходимые шрифты: шрифт 8 пунктов.
5. Очистить битовую карту.
6. Скопировать фоновое изображение на битовую карту.
7. Вычертить координатные оси.
8. Рассчитать количество делений на каждой из осей.
9. Вычертить все линии делений.
10. Нарисовать текст для каждого деления.
11. Нарисовать данные для каждого из наборов данных, для которых строятся графики.
12. Нарисовать линии между точками.
13. Вычертить квадраты вокруг каждой точки.
14. Нарисовать название графика.
15. Нарисовать таблицу цветовых ключей, идентифицирующих наборы данных.
16. Нарисовать рамку.
17. Нарисовать шаблонные линии для каждого набора данных.
18. Нарисовать текстовые подписи для каждого набора данных.
19. Освободить память, занимаемую перьями, кистями и шрифтами.
Отсрочка – зло, используйте предварительные вычисленияПри проектировании высокоуровневого кода пользовательских интерфейсов целесообразно попытаться отложить выполнение некоторых операций на как можно более поздний срок; заполнение элементов управления большими объемами данных, которые, возможно, пользователь никогда не будет просматривать, является бессмысленной тратой процессорного времени. В данном случае стратегия откладывания работы на более поздний срок удачна по той причине, что данные, которыми заполняется интерфейс, являются динамическими, а их возможные объемы часто могут оказываться настолько большими, что заполнять ими интерфейс было бы слишком расточительно. Если же объем информации ограничен и наперед известен, то имеет смысл попытаться заранее вычислить или инициализировать эти данные. Именно с такой ситуацией приходится часто сталкиваться в случае графических данных.
Работа с графикой часто состоит из множества небольших повторяющихся задач, последовательно выполняющихся одна за другой. Если это так, то разумно попытаться использовать заблаговременное вычисление некоторых элементов. Любая задача рисования, которую можно выполнить заранее, сэкономит вам время. Справедливость этого утверждения вдвойне возрастает, если некоторая работа может быть сделана на стадии проектирования, еще до того, как приложение вообще начнет выполняться.
Если такая возможность имеется, исследуйте шаги процесса визуализации изображений и исключите из них те, которые могут быть выполнены до начала его выполнения, и тогда производительность вашего приложения от этого только выиграет.
Чтобы проиллюстрировать это положение рассмотрим два типичных случая.
Пример 1: предварительная визуализация объектов бизнес-диаграммы
На рис. 11.7 приведена довольно красочная картинка, на которой некие (фиктивные) данные отображаются в виде гистограммы. Гистограмма представляет относительные темпы роста экономики различных стран за определенный период времени. Чтобы облегчить визуальное восприятие данных пользователем, было решено представить данные, относящиеся к каждой из стран, в виде столбцов, раскрашенных символами валюты данной страны. Кроме того, для диаграммы предусмотрено фоновое изображение; в данном случае таковым является простой градиентный фоновый цвет, плавно меняющийся от темного к светлому оттенку, но вместо него может быть использовано любое изображение
Приступая к построению гистограммы, мы должны, вероятно, начать с создания пустой битовой карты. Далее на этой карте будут нарисованы фоновый градиент, оси, название гистограммы, метки делений на обеих осях, подписи к делениям и столбцам, добавлен сплошной цвет для каждого столбца гистограммы, на столбцы гистограммы нанесены символы валюты, а поверх них проставлены точные процентные значения. Нарисовать предстоит довольно много. Учитывая тот факт, что суть задачи, заключающаяся в построении гистограммы для отображения экономических показателей для каждой страны, нам известна, мы можем применить ряд оптимизирующих шагов, которые позволят значительно сократить объем работы, которую необходимо выполнить для визуализации гистограммы.

Рис. 11.7. Гистограмма, представляющая темпы роста экономики различных стран
Первое, что мы можем сделать в плане оптимизации, – это определить все то, что будет оставаться неизменным в любой диаграмме, и превратить эти объекты в готовый фон. Сказанное иллюстрируется на рис. 11.8. Мы решили заранее нарисовать на фоновой битовой карте градиентную заливку фоновым цветом, вертикальные и горизонтальные линии и часть названия диаграммы. Было решено не включать в фоновое изображение следующие данные: собственно столбцы гистограммы, названия стран и их позиции на гистограмме, числовые метки для каждого деления на вертикальной шкале, текст над каждым из столбцов гистограммы и заполнение самих столбцов. Все эти объекты должны быть динамически сгенерированы во время выполнения приложения.

Рис. 11.8. Заблаговременно подготовленное фоновое изображение для гистограммы
Теперь нам предстоит принять очень важное решение относительно того, какому варианту отдать предпочтение: однократно прорисовывать фоновый битовый образ при каждом запуске приложения или же создать это изображение на стадии проектирования, скомпилировать в виде ресурса приложения и только загружать его на стадии выполнения. Если такое растровое изображение является статическим или необходимо иметь всего лишь несколько его различных вариантов, то, вероятно, имеет смысл подготовить их на настольном компьютере и включить в приложение как двоичный ресурс. Дополнительным преимуществом проведения такой подготовительной работы на стадии проектирования является то, что мы можем поручить ее профессиональному художнику-графику, который выполнит работу на высоком эстетическом уровне. Как бы то ни было, в любом случае мы сэкономим массу процессорного времени, поскольку каждый раз, когда будет требоваться повторная визуализация диаграммы, мы уже будем располагать ее заблаговременно подготовленной сложной частью, кэшированной для нужд приложения.
Дополнительная оптимизация возможна также на стадии визуализации диаграммы. Исходя из предположения, что отображаемый текст является действительно динамическим, связанные с ним вычисления и перерисовка экрана должны осуществляться средствами графического вывода текста, предоставляемыми каркасом приложения. При этом, однако, все еще остается неразрешенным непростой вопрос о том, каким образом следует визуализировать декорированные столбцы диаграммы.
В соответствии с нашими планами относительно исходного варианта реализации мы могли бы нарисовать прямоугольники для каждого столбца и вывести над каждым из них соответствующий текст, но это было бы нерациональной тратой времени. Существует также проблема визуализации лишь части линий текста. Задача визуализации символов $$$ на 38 процентов высоты или символов €€€ на 76 процентов высоты средствами каркаса приложения может оказаться не столь уж простой. Учитывая сложность реализации этого подхода, от использования символов валюты можно было бы вообще отказаться, но это был бы позорный поступок с нашей стороны, поскольку наличие обозначений валюты на столбцах упрощает установление соответствия между странами и столбцами и поэтому снижает вероятность неправильного истолкования данных пользователем. Поэтому от всех этих "украшений" мы не отказываемся, но и платить за них лишнее не собираемся.
В качестве оптимизации первого порядка мы могли бы создать битовые образы строк символов валюты для каждой страны, то есть растровое изображение 30×10 пикселей для строки $$$ и аналогичные изображения для других видов валют. Вероятно, такие битовые образы можно было бы очень быстро копировать поверх нашего фонового изображения, предусмотрев для этого цикл, который выполнялся бы столько раз, сколько необходимо, с последующим отсечением верхушки символов в соответствующих точках, чтобы обеспечить нужную высоту столбцов. В действительности, мы можем поступить еще лучше. Почему бы не заготовить заранее битовые образы, представляющие для каждой валюты столбцы максимальной высоты? Всего нам нужно четыре таких заготовки: одна для США (US), одна для Японии (Japan), одна для Великобритании (UK) и одна для стран Европейского Союза (EU). Когда нашему приложению необходимо нарисовать любой из этих столбцов, оно просто использует соответствующий битовый образ и копирует его часть на поверхность нашего рисунка. Как и в случае фонового изображения, если имеется возможность создавать изображения на стадии проектирования, то можно прибегнуть к услугам дизайнеров, которые придадут изображениям максимально привлекательный внешний вид. Пример таких заранее заготовленных столбцов представлен на рис. 11.9.

Рис. 11.9. Заранее заготовленные декорированные столбцы гистограмм
Какой дополнительный объем памяти потребуется для реализации такого подхода? Предположим, что максимальная высота столбцов составляет 180 пикселей, а их ширина – 32 пикселя. Пусть, далее, для хранения информации о цвете каждого пикселя требуется 4 байта. Тогда для хранения в памяти битового образа одного столбца диаграммы потребуется 180×32×4 = 23040 байт, или 22,5 Кбайт. В зависимости от ситуации такой объем может быть для нас как приемлемым, так и неприемлемым. Насколько велик этот объем по сравнению с теми объемами памяти, которые требуются для хранения других объектов? Если предположить, что размеры фонового изображения составляют 200×200 пикселей, то для него потребуется 200×200×4 = 156,25 Кбайт памяти.
Для построения окончательного изображения диаграмм нам потребуется еще одна битовая карта такого же размера, на которую будут копироваться графические данные заднего и переднего планов; в результате этого суммарный необходимый объем памяти достигает 312,5 Кбайт, что не так уж мало, но вполне приемлемо для большинства мобильных устройств. Битовые образы всех четырех столбцов суммарно потребуют 22,5×4=90 Кбайт, что значительно меньше того, что требуется для фонового изображения и пустой битовой карты, на которой все наши изображения будут объединены в одно целое. Учитывая тот факт, что, затрачивая 90 Кбайт дополнительной памяти, мы избавляемся от необходимости многократно создавать в памяти копии небольших изображений или каждый раз рисовать текст поверх столбцов, такую оптимизацию, по всей видимости, можно считать эффективной.
Пример 2: предварительная визуализация объектов для сюжетной игры
Любопытно отметить, что оптимизация визуализации изображений для сюжетных игр имеет много общего с оптимизацией этого процесса, которую мы рассмотрели на примере диаграмм. На рис. 11.10 представлено изображение для сюжетной игры, которую я написал для .NET Compact Framework, чтобы продемонстрировать концепции графики.
HA ЗАМЕТКУ
Те, кого интересует исходный текст этого приложения, могут найти его на Web-сайте. Приложение было написано на языке VB.NET и названо "HankTheCaveMan" ("Пещерный человек Хэнк"). Оно позволяет продемонстрировать многие из концепций графики, которые обсуждаются в этой главе. Полный исходный код приложения доступен для загрузки на сайте обмена исходными кодами www.gotdotnet.com вместе с бесчисленным множеством других примеров и информации.

Рис. 11.10. Сюжетная игра, написанная для .NET Compact Framework
Существует три слоя изображений для игр, которые должны визуализироваться на экране:
1. Фоновая картинка. В играх предусматривается статическая фотография, используемая в качестве фонового изображения.
2. Статический передний план. К этой категории относятся изображения, находящиеся на переднем плане, которые не изменяются от кадра к кадру. На нашем игровом поле такими элементами являются настилы и лестницы. Эти изображения являются важными элементами переднего плана и изменяются при переходе с одного уровня игры на другой, но не изменяются при смене кадров при визуализации игры.
3. Динамический передний план. К этой категории относятся активные экранные изображения, которые могут изменяться от кадра к кадру. В нашей игре они представляют пещерного человека, пещерную женщину, два валуна, птицу и четыре факела. Эту разновидность графических элементов обычно называют "спрайтами". Кроме того, к динамическому переднему плану относятся индикатор запаса энергии, который находится в верхней части игрового поля слева, и индикатор Score/Bonus (Счет/Бонус), расположенный в верхней части игрового поля справа. В программе все эти элементы представлены объектами одной коллекции
Циклу визуализации предшествует загрузка фонового изображения и создание на нем рисунка настилов и лестниц. Эти изображения комбинируются в памяти и xpaнятся как наше фоновое изображение. Настилы и лестницы не изменяются при переходе от кадра к кадру, поэтому нет смысла визуализировать их вместе с каждым кадром. Поскольку фоновое изображение уже и так должно загружаться, мы не занимаем лишнюю память, рисуя на нем статическое игровое поле.
В основе механизма визуализации лежат простые принципы. С каждым активным элементом на экране ассоциирован объект, в котором хранится позиция элемента на игровом поле, а также инструкции относительно того, как его визуализировать. В цикле визуализации хранится целевая битовая карта. Она имеет те же размеры, что и фоновое изображение. Объект Graphics для нее создается и сопровождается на протяжении всего времени существования приложения. Все необходимые для рисования шрифты, кисти и перья также хранятся в глобальной области памяти, так что любой нуждающийся в этих объектах код, предназначенный для визуализации изображений, может просто воспользоваться ими, а не распределять для них дополнительную память.
Когда выполняется визуализация кадра, то сначала в целевую битовую карту копируется фоновое изображение. После этого каждому из объектов визуализируемой коллекции направляется запрос на то, чтобы он визуализировал себя на целевой битовой карте. Некоторые из этих объектов являются текстовыми; такие объекты для прорисовки своего текста на целевой битовой карте вызывают метод Graphics.DrawString(). Одним из нетекстовых объектов является "энергетическая шкала", которая состоит из двух прямоугольников – внешней рамки и внутреннего закрашенного прямоугольника. Остальные объекты являются многокадровыми растровыми изображениями, то есть несколько таких изображений представляют различные возможные состояния спрайта; это обеспечивает возможность анимации объектов путем быстрого переключения между их различными изображениями.
С Хэнком (пещерным человеком) ассоциированы 8 изображений; 2 – для бега влево, 2 – для бега вправо, 2 – для подъема и 2 – для спуска. Для каждого спрайта предусмотрена внутренний конечный автомат, который следит за тем, какое изображение должно отображаться в процессе визуализации. Изображения имеют небольшие размеры; размеры изображения Хэнка составляют 21×35 пикселей, или, округляя в большую сторону до ближайшего кратного 4 (чтобы учесть возможное выравнивание границ размещения объектов в памяти), 24×36 = 864 пикселя. Всего для одного изображения требуется 864×4 байт/пиксель, что составляет примерно 3,5 Кбайт. Для загрузки всех 8 изображений Хэнка в память потребуется порядка 28 Кбайт, что вполне приемлемо.
Каждый из этих небольших спрайтов визуализируется с использованием одной и той же маски прозрачности при их копировании на фоновое изображение. Это означает, что один из цветов битового изображения спрайта назначен в качестве прозрачного и позволяет фоновому изображению "проступать" через скопированный на него спрайт. Это работает не так быстро, как непосредственное копирование в память непрозрачных прямоугольных изображений, но результат выглядит гораздо привлекательнее из-за того, что изображение лишается своих прямоугольных очертаний.
Как уже отмечалось, описанная модель визуализации игры имеет много общего с процедурой рисования диаграмм. В данной игре вне цикла визуализации выполняется максимально возможный объем работы. Кроме того, при любой удобной возможности в ней используется предварительное создание изображений. В цикле визуализации выполняются лишь простые операции побитового копирования фонового изображения, а также рисуются несколько небольших спрайтов, частично прозрачных для фона, немного текста и несколько простых прямоугольников. Поскольку в игре не распределяется память и исключены напрасные траты процессорного времени внутри цикла визуализации, все это может происходить очень быстро.







