Руководство по actionscript. часть 5, стр. 018
Листинг 25.5. Класс Star
package org. moock. drawing { // Представляет фигуру звезды, которая может быть нарисована на экране public class Star extends Polygon { // Конструктор
public function Star (numTips:int.
innerRadius:Number, outerRadius:Number, angle-.Number = 0) {
super( );
setStar(numTips, innerRadius. outerRadius, angle):
}
// Устанавливает физические характеристики звезды.
// За основу взяты методы рисования Рика Эвинга (Ric Ewing) для языка
// ActionScript 1.0. доступные по адресу:
// http://www. adobe. com/devnet/flash/articles/adv_draw_methods. html
// numTips Количество концов (должно быть 3 или больше)
// innerRadius Радиус основания концов
// outerRadius Радиус вершин концов
// angle Начальный угол в градусах (по умолчанию 0)
public function setStar (numTips:int.
Руководство по actionscript. часть 5, стр. 019
InnerRadius:Number, outerRadius:Number, angle:Number = 0):void { // Вычисляем точки многоугольника-звезды if (numTips > 2) { // Инициализируем переменные var pointsX:Array = []; var pointsY:Array = []; var centerX:Number = outerRadius: var centerY:Number = outerRadius;
var step-.Number, half Step: Number,
startAngle-.Number, dx:Number, dy:Number; // Вычисляем расстояние между концами step = (Math. PI*2)/numTips; halfStep = step/2;
// Вычисляем начальный угол, в радианах startAngle = (angle/180)*Math. PI: // Задаем начальную точку
pointsX[0] = centerX+(Math. cos(startAngle)*outerRadius); pointsY[0] = centerY-(Math. sin(startAngle)*outerRadius); // Добавляем оставшиеся точки for (var i:int=l; i <= numtips; i++) {
dx = centerX+Math. cos(startAngle+(step*i)-halfStep)*innerRadi us;
dy = centerY-Math. si n(startAngle+(step*i)-halfStep)*innerRadi us:
pointsX. push(dx);
pointsY. push(dy);
dx = centerX+Math. cos(startAngle+(step*i))*outerRadius; dy = centerY-Math. sin(startAngle+(step*i))*outerRadius; pointsX. push(dx); pointsY. push(dy);
}
// Сохраняем вычисленные точки звезды setPoints(pointsX, pointsY);
}
}
}
}
Наконец, в листинге 25.6 представлен класс ShapeRandomizer, который демонстрирует использование библиотеки классов фигур из пяти предыдущих примеров. Метод-конструктор класса ShapeRandomizer создает четыре фигуры. Щелчок кнопкой мыши на сцене случайным образом изменяет штриховку, заливку и контуры данных фигур.
Руководство по actionscript. часть 5, стр. 020
Листинг 25.6. Класс ShapeRandomizer
package { import flash. display. Sprite; import flash. events. MouseEvent;
import org. moock. drawing.*;
// Демонстрация использования библиотеки org. moock. drawing.
// Создает случайные фигуры, когда пользователь
// щелкает кнопкой мыши на сцене.
public class ShapeRandomizer extends Sprite {
// Фигуры
private var rect:Rectangle; private var ell:El 1ipse; private var poly:Polygon; private var star:Star; // Конструктор
public function ShapeRandomizer ( ) { // Создаем прямоугольник rect = new Rectanglе(50. 100): rect. setStrokeSty1e(1, OxFFOOOO); rect. setFillStyle(OxOOOOFF);
// Создаем эллипс
ell = new Ellipse(250. 50);
ell. setStrokeStyle(2, OxFFFFOO);
ell. setFi11 Sty1e(0xED994F):
// Создаем треугольник (то есть трехгранный объект Polygon) poly = new Polygon([0. 50, 100], [50, 0. 50]); poly. setStrokeStyle(4. 0×333333); poly. setFilIStyle(OxOOFFOO);
// Создаем звезду
star = new Star(5, 30, 80);
star. setStrokeStyle(4, 0×666666);
star. setFillStyle(OxFFOOOO);
// Добавляем фигуры в список отображения
addChiId(rect);
addChild(ell);
addChild(poly);
addChild(star);
// Регистрируем приемник для событий // щелчка кнопкой мыши
stage. addEventLi stener(MouseEvent. MOUSEJDOWN, mouseDownLi stener);
}
// Приемник событий, вызываемый в тот момент, когда пользователь щелкает // в области отображения среды выполнения Flash Player private function mouseDownListener (e:MouseEvent)-.void {
// Изменяем фигуры случайным образом
rect. width = randomd. 300);
rect. height = randomd, 300);
rect. setStrokeStyle(random(l. 10), random(0, OxFFFFFF)); rect. setFillStyle(random(0, OxFFFFFF), Math. random( ));
ell. width = randomd, 300); ell. height = randomd. 300);
ell. setStrokeStyle(randomd. 10). random(0. OxFFFFFF)); el 1.setFi11Style(random(0. OxFFFFFF), Math. random( ));
poly. setPoints(.
Руководство по actionscript. часть 5, стр. 021
[randomd. 300), randomd. 300), randomd. 300)]); poly. setStrokeStyle(randomd. 10). random(0. OxFFFFFF)); poly. setFillStyle(random(0, OxFFFFFF). Math. random( )); star. setStar(random(3. 15), randomdO. 20). random(30. 80));
star. setStrokeStylе(randomd, 10). random(0. OxFFFFFF)); star. setFillStyle(random(0. OxFFFFFF), Math. randomC ));
}
// Возвращает число в диапазоне от minVal до maxVal включительно public function random (minVal:int, maxVal:int):int { return minVal + Math. floor(Math. random( ) * (maxVal + 1 — minVal));
}
}
}
На рис. 25.6 продемонстрирован набор случайных фигур, созданных классом ShapeRandomizer.
Рис. 25.6. Фигуры, созданные классом ShapeRandomizer
От линий к пикселам
В этой главе вы узнали, как создавать векторное графическое содержимое и управлять им. В следующей главе мы рассмотрим методики создания и управления растровым графическим содержимым.
Руководство по actionscript. часть 5, стр. 022
I Дополнительную информацию по векторной графике можно найти в документации по [%: 4 ^ классу Graphics в справочнике по языку ActionScript корпорации Adobe.
ГЛАВА 26
Программирование растровой графики
В терминах программирования растровое изображение — это изображение, которое хранится в растровом формате данных. Растровый формат данных представляет изображение в виде прямоугольной сетки пикселов, в которой каждому пикселу присваивается число, обозначающее его цвет.
Например, если изображение, ширина и высота которого составляют 16 пикселов, представить в растровом формате данных, то оно будет сохранено в виде списка, состоящего из 256 чисел, каждое из которых обозначает конкретный цвет. Этот пример проиллюстрирован на рис. 26.1 — изображение размером 16 х 16 пикселов увеличено с целью отображения его отдельных пикселов. В правой части рисунка указаны позиции в таблице и значения цвета для трех выбранных в изображении пикселов. Обратите внимание, что позиции в таблице начинаются с нуля, поэтому координатой левого верхнего пиксела является (0; 0), а правого нижнего-(15; 15).
X Y Значение цвета
14 2 4294967295
X Y Значение цвета
11 8 4294901760
X Y Значение цвета
12 14 4286015078
Исходное изображение
Увеличенное изображение для показа пикселов
Координаты и значения цвета выбранных пикселов
Рис. 26.1. Пример растрового изображения
В этой главе мы рассмотрим ряд распространенных методик, связанных с программированием растровой графики. Тем не менее имейте в виду, что исчерпывающему описанию программирования растровой графики в языке ActionScript могла бы быть посвящена целая книга. /
В качестве источника информации для дальнейшего изучения можно использовать справочник по языку ActionScript корпорации Adobe.
Руководство по actionscript. часть 5, стр. 023
Классы BitmapData и Bitmap
В языке ActionScript класс BitmapData представляет данные изображения в растровом формате наподобие того, которое показано на рис. 26.1. Каждый экземпляр класса BitmapData содержит список значений цвета пикселов и переменные экземпляра width и height, которые управляют размещением этих пикселов на экране. С помощью класса BitmapData мы можем создать данные для совершенно нового растрового изображения или просмотреть и изменить данные любого существующего растрового изображения, включая растровые изображения, загружаемые извне.
Класс BitmapData предоставляет широкий набор инструментов для установки или получения значения цвета некоторого пиксела или группы пикселов, а также для создания распространенных графических эффектов, например эффекта размытия или падающей тени. Как мы увидим далее, класс BitmapData может быть использован даже для создания анимированных эффектов и определения столкновений на основе растровых изображений. Для работы с большей частью инструментов класса BitmapData мы должны получить представление о формате, используемом языком ActionScript для описания значения цвета пиксела, который рассматривается в следующем разделе.
Как видно из названия, объект BitmapData сам по себе не является изображением; он лишь хранит представляющие изображение данные в растровом формате. Чтобы создать реальное, отображаемое на экране изображение, используя информацию, хранящуюся в объекте BitmapData, мы должны соединить этот объект с экземпляром класса Bitmap, как описано далее в разд. «Создание нового растрового изображения». Класс Bitmap является потомком класса DisplayOb j ect, осуществляющим отображение объекта BitmapData на экране.
-
^ I При работе с растровыми изображениями класс Bitmap используется для управления А. щ изображением как отображаемым объектом, а класс BitmapData — для управления нижележащими пиксельными данными изображения.
Благодаря разделению представления изображения (класс Bitmap) и хранилища данных (класс BitmapData), архитектура растровых изображений языка ActionScript позволяет нескольким различным объектам Bitmap одновременно отображать один и тот же объект BitmapData, при этом каждый объект Bitmap может иметь собственные визуальные характеристики (то есть различный масштаб, угол поворота, обрезку, фильтры, преобразования и прозрачность).
Перед тем как познакомиться с методикой создания нового растрового изображения, бегло рассмотрим способ представления цветов в языке ActionScript.
Значения цвета пикселов
В языке ActionScript значения цвета пикселов, формирующих растровые изображения, сохраняются в виде 32-битных беззнаковых целых чисел, обеспечивая огром-
ный диапазон из 4 294 967 296 возможных значений цветов. Каждое конкретное значение цвета в объекте BitmapData концептуально состоит из четырех отдельных значений, которые представляют четыре различных компонента цвета — Alpha (Альфа) (то есть прозрачность), Red (Красный), Green (Зеленый) и Blue (Синий). Эти четыре компонента называются цветовыми каналами. Величина каждого канала в любом цвете варьируется от 0 до 255. Соответственно в двоичном виде каждый канал занимает 8 из 32 бит значения цвета, как показано далее:
? Alpha — биты 24-31 (самый старший байт);
? Red-биты 16-23;
? Green — биты 8-15;
? Blue — биты 0-7.
Руководство по actionscript. часть 5, стр. 024
Чем выше значение канала Red, Green или Blue, тем больший вклад вносит каждый цвет в результирующий цвет. Если значения всех трех каналов RGB равны, будет получен оттенок серого цвета; если значения всех каналов равны 0, будет получен черный цвет; если значения всех каналов равны 255, будет получен белый цвет. Данный 32-битный формат цвета позволяет задать 16 777 216 возможных цветов, при этом каждый цвет может иметь отдельный уровень канала Alpha, находящийся в диапазоне от 0 (прозрачный) до 255 (непрозрачный).
Например, чистый красный цвет описывается следующими значениями каналов:
Alpha: 255, Red: 255, Green: 0, Blue: О
Эти значения соответствуют следующим установкам битов в 32-битном беззнаковом целочисленном значении цвета (пробелы определяют границы четырех байтов):
11111111 11111111 00000000 00000000
В десятичном виде предыдущее целочисленное значение будет выглядеть следующим образом:
4294901760
Безусловно, когда значение цвета представлено в виде одного десятичного числа, уровни различных каналов в этом значении цвета неочевидны. В связи с этим значения цвета пикселов для удобочитаемости обычно записываются в шестна-дцатеричном виде: OxAARRGGBB, где АА, RR, GG и ВВ — это двухразрядные шестна-дцатеричные числа, представляющие каналы Alpha, Red, Green и Blue. Например, предыдущее значение для чисто красного цвета (А:255, R:255, G:0, В:0) в шестна-дцатеричном виде записывается следующим образом:
0xFFFF0000 // Гораздо проще читать!
Для сравнения на рис. 26.2 представлено изображение, заимствованное из рис. 26.1, но на этот раз значения цвета трех выбранных пикселов разбиты на соответствующие цветовые каналы, записанные в шестнадцатеричном виде.
*^ 1 Пример перевода чисел в шесгнадцатеричную систему счисления можно найти по адресу
4
http://www. moock. org/asdg/technotes/basePrimer.
Руководство по actionscript. часть 5, стр. 025
X Y ALPHA RED BLUE GREEN
14 2 FF FF FF FF
X Y ALPHA RED BLUE GREEN
11 8 FF FF 00 00
X Y ALPHA RED BLUE GREEN
12 14 FF 77 66 66
Исходное изображение
Увеличенное изображение для показа пикселов
Координаты и значения цвета выбранных пикселов
Рис. 26.2. Растровое изображение с шестнадцатеричными значениями цвета
Чтобы получить значение отдельного канала из 32-битного значения цвета, мы можем использовать совместно оператор сдвига вправо и оператор побитового И, как показано в следующем коде:
var colorValue:uint = 0xFFFFCC99; // Выбранный цвет
var alpha:uint = (colorValue » 24) & OxFF; // Выделяем канал Alpha
var rechuint = (colorValue » 16) & OxFF; // Выделяем канал Red
var green:uint = (colorValue » 8) & OxFF; // Выделяем канал Green
var blue:uint = colorValue & OxFF; // Выделяем канал Blue
trace(alpha, red, green, blue); // Отображает: 255 255 204 153
Пример использования побитовых операций можно найти в технических записках по адресу http://www. moock. org/asdg/technotes/bitwise.
Руководство по actionscript. часть 5, стр. 026
Хотя непосредственно изменить значение отдельного канала в существующем 32-битном значении цвета невозможно, мы можем достичь этого эффекта, используя комбинацию бинарных операций. Сначала мы очищаем байт нужного канала в существующем значении цвета; затем мы объединяем получившееся число с новым значением цветового канала. Эта методика продемонстрирована в следующем коде. При его выполнении создается число, которое является результатом вставки шестнадцатеричного значения АА в существующее значение цвета:
var colorValue:uint = 0xFFFFCC99; // Выбранный цвет
// Очищаем байт канала Red в исходном значении цвета и присваиваем результат // обратно переменной colorValue colorValue &= OxFFOOFFFF;
// Объединяем значение переменной colorValue с новым значением канала Red colorValue |= (0хАА«16);
trace(colorValue. toString(16)); // Выводит: ffaacc99 Внимательно посмотрите на последнюю строку кода: trace(colorValue. toString(16)); // Выводит: ffaacc99
Этот код генерирует строку в шестнадцатеричном формате для числового значения цвета, вызывая над этим значением метод toString( ) и передавая в качестве
параметра radix значение 16. Строка в шестнадцатеричном формате проще для чтения, чем ее числовой десятичный эквивалент. Тем не менее в качестве средства обеспечения удобочитаемости значения цвета метод toString( ) неидеален — он опускает ведущие нули. Например, для числа
var n:uint = 0х0000СС99;
выражение п. toString (16) вернет значение сс9 9, опустив четыре ведущих нуля. Чтобы улучшить удобочитаемость значений цветов на этапе отладки, мы можем написать собственный код, наподобие представленного в листинге 26.1. В этом листинге представлен класс Pixel, предназначенный для работы со значениями цветов. Класс Pixel помещает бинарные операции в удобные методы, например setRed ( ) и set Alpha ( ). Методы этого класса могут получать и устанавливать уровни отдельных цветовых каналов в значении цвета и генерировать строки, описывающие значения цвета с использованием различных удобочитаемых форматов. Описание класса Pixel доступно в Интернете по адресу http://www. moock. org/eas3/examples.
Листинг 26.1. Класс Pixel
package { public class Pixel { private var value:uint; // Значение цвета пиксела
public function Pixel (nl:uint, n2:int=0, n3:int=0, n4:int=0) { if (arguments. length == 1) {
value = nl; } else {
value = nl«24 | n2«16 | n3«8 | n4;
}
}
public function setAlpha (n:int):void { if (n < о 11 n > 255) { throw new RangeError(«Supplied value must be in the range 0-255.»);
}
value &= (OxOOFFFFFF); value |= (n«24);
}
public function setRed (n;int):void { if (n < 0 11 n > 255) { throw new RangeError(«Supplied value must be in the range 0-255.»);
}
value &= (OxFFOOFFFF); value |= (n«16);
}
public function setGreen (n:int):void { if (n < 0 11 n > 255) { throw new RangeError(«Supplied value must be in the range 0-255.»);
value &= (OxFFFFOOFF); value |= (n«8);
}
public function setBlue (n:int):void { if (n < 0 11 n > 255) { throw new RangeErrorC Supplied value must be in the range 0-255.»);
}
value &= (OxFFFFFFOO); value |= (n);
}
public function getAlpha ( ):int { return (value » 24) & OxFF;
}
public function getRed ( ):int { return (value » 16) & OxFF;
}
public function getGreen ( ):int { return (value » 8) & OxFF;
}
public function getBlue ( );int { return value & OxFF;
}
public function toString ( ):String { return toStringARGB( );
}
public function toStringARGB (radix:int = 16):String { var s:String =
«A:» + ((value » 24)&0xFF).toString(radix).toUpperCase( ) + » R:» + ((value » 16)&0xFF).toString(radix).toUpperCase( ) + » G:» + ((value » 8)&0xFF).toString(radix).toUpperCase( ) + » B:» + (value&OxFF).toString(radix).toUpperCase( ); return s;
}
public function toStringAlpha (radix:int = 16):String { return ((value » 24)&0xFF).toString(radix).toUpperCase( );
}
public function toStringRed (radix:int = 16):String { return ((value » 16)&0xFF).toString(radix).toUpperCase( );
}
public function toStringGreen (radix:int = 16):String { return ((value » 8)&0xFF).toString(radix).toUpperCase( );
public function toStnngBlue (radix:int = 16):String return (value&OxFF) .toStnng(radix) .toUpperCase( );
}
}
// Примеры использования:
var p:Pixel = new Pixel(0xFFFFCC99);
p. setRed(OxAA):
trace(p); // Выводит:
trace(p. getRed( )); // Выводит:
trace(p. toStringRed( )); // Выводит:
// Выбранный цвет
A:FF R:AA G:CC В:99
170
AA
var p2:Pixel = new Pixel(0×33,0×66,0×99,OxCC); trace(p2.toStringARGB(10)): // Выводит: A:51 R:102 G:153 B:204
Создание нового растрового изображения
Для создания и отображения совершенно нового растрового изображения нужно выполнить такую последовательность действий.
Руководство по actionscript. часть 5, стр. 027
1. Создать объект BitmapData.
2. Установить желаемые цвета пикселов в созданном объекте BitmapData.
3. Связать объект BitmapData с объектом Bitmap.
4. Добавить объект Bitmap в список отображения.
Попробуем применить эти шаги на практике!
Наша цель — отобразить квадрат синего цвета размером 10×10 пикселов по центру фонового квадрата зеленого цвета размером 20 х 20 пикселов. Сначала мы создадим объект BitmapData, используя следующий обобщенный код:
new BitmapData(ширина, высота, прозрачность, цветЗаливки)
Параметры ширина и высота обозначают размеры изображения в пикселах — максимальное значение, которое могут принимать данные параметры, равняется 2880. После создания объекта BitmapData изменить размеры изображения невозможно. Параметр прозрачность определяет, должно ли изображение поддерживать прозрачность отдельных пикселов (то есть может ли уровень канала Alpha значения цвета любого пиксела быть меньше 255). Если необходимости в поддержке прозрачности изображения нет, то параметру прозрачность должно быть установлено значение false, поскольку среда Flash отображает непрозрачные изображения быстрее, чем прозрачные. Наконец, параметр цветЗаливки задает значение цвета, которое изначально присваивается всем пикселам изображения.
Изображение, которое мы хотим создать, представляет собой квадрат размером 20 х 20 пикселов, для него не требуется прозрачности, и оно имеет фон зеленого цвета. Таким образом, чтобы создать наш объект BitmapData, мы используем следующий код:
// OxFFOOFFOO означает Alpha: 255, Red: 0. Green: 255. Blue: 0 var imgData:BitmapData = new BitmapData(20, 20, false, OxFFOOFFOO):
Теперь нам необходимо установить синий цвет для пикселов квадратной области размером 10 х 10 пикселов. Класс BitmapData предоставляет несколько инструментов для установки цвета пикселов: setPixel( ), setPixel32( ), setPixels ( ), fillRect ( ) и floodFill ( ). Для наших целей отлично подходит метод fillRect ( ) — он присваивает пикселам заданной прямоугольной области указанный цвет. Задаваемый нами объект Rectangle имеет ширину и высоту, равную 10 пикселам, а его левый верхний угол находится в точке с координатами (5; 5). В результате все пикселы растрового изображения, формирующие прямоугольную область от точки (5; 5) до точки (14; 14) включительно, будут окрашены в синий цвет.