Как вы наверно знаете, в Actionscript 2.0 стандартные методы динамического рисования применимы только для назначения цвета, толщины линий, рисования линий и кривых (подробнее в посте о динамическом рисовании). Нет даже методов для рисования прямоугольных примитивов, окружностей и эллипсов. Конечно, их можно нарисовать вручную или написать собственные функции, которые будут отрисовывать самые распространённые примитивы. Но зачем делать то, что уже давно сделано до нас. Например, на одном варварском веб-ресурсе выложен класс Graphics, который позволяет расширить возможности динамического рисования в ActionScript 2.0. Рассмотрению данного класса и посвящён этот пост. В качестве среды разработки использоваться будет Macromedia Flash 8.
Первым делом нам нужен сам класс Graphics. Его можно взять с указанного ранее сайта или из исходников, прилагающихся к данному посту.
Класс Graphics с комментариями автора. Код ActionScript 2.0:
class Graphics extends MovieClip {
var mc;
var color:String;
var fill:String;
var thick:Number;
// constructor
public function Graphics(depth:Number) {
_root.createEmptyMovieClip("test1", depth);
mc = _root.test1;
// set defaults
color = "0x000000";
thick = 1;
fill = "0x666666";
}
// setters
function setColor(_color:String) {
color = _color;
}
// set thickness
function setThick(_thick:Number) {
thick = _thick;
}
// set fill
function setFill(_fill:String) {
fill = _fill;
}
//change depth
function changeDepth(_depth:Number) {
mc.swapDepths(_depth);
}
//
//drawing functions
function drawLine(x1:Number, y1:Number, x2:Number, y2:Number) {
mc.lineStyle(thick, color);
mc.moveTo(x1, y1);
mc.lineTo(x2, y2);
}
function drawRect(x1:Number, y1:Number, width:Number, height:Number) {
mc.lineStyle(thick, color);
mc.moveTo(x1, y1);
mc.lineTo(x1+width, y1);
mc.lineTo(x1+width, y1+height);
mc.lineTo(x1, y1+height);
mc.lineTo(x1, y1);
}
// fillRect
function fillRect(x1:Number, y1:Number, width:Number, height:Number) {
mc.lineStyle(thick, color);
mc.moveTo(x1, y1);
mc.beginFill(fill);
mc.lineTo(x1+width, y1);
mc.lineTo(x1+width, y1+height);
mc.lineTo(x1, y1+height);
mc.lineTo(x1, y1);
mc.endFill();
}
// ------ DRAW CURVE ------- //
function drawCurve(startX:Number, startY:Number, curveControlX:Number, curveControlY:Number, endX:Number, endY:Number) {
mc.lineStyle(thick, color);
mc.moveTo(startX, startY);
mc.curveTo(curveControlX, curveControlY, endX, endY);
}
// draw Oval
function drawOval(x:Number, y:Number, width:Number, height:Number) {
mc.lineStyle(thick, color);
mc.moveTo(x, y+height/2);
mc.curveTo(x, y, x+width/2, y);
mc.curveTo(x+width, y, x+width, y+height/2);
mc.curveTo(x+width, y+height, x+width/2, y+height);
mc.curveTo(x, y+height, x, y+height/2);
}
// --------- FILL OVAL ------------ //
function fillOval(x:Number, y:Number, width:Number, height:Number) {
mc.lineStyle(thick, color);
mc.moveTo(x, y+height/2);
mc.beginFill(fill);
mc.curveTo(x, y, x+width/2, y);
mc.curveTo(x+width, y, x+width, y+height/2);
mc.curveTo(x+width, y+height, x+width/2, y+height);
mc.curveTo(x, y+height, x, y+height/2);
mc.endFill();
}
// --------- DRAW CIRCLE----------- //
//if argument styleMaker == 22.5 you get a full circle
// 66 makes a star like figure
// usage : drawCircle(radius,x,y,22.5)
function drawCircle(r:Number, x:Number, y:Number) {
var styleMaker:Number = 22.5;
mc.moveTo(x+r, y);
mc.lineStyle(thick, color);
var style:Number = Math.tan(styleMaker*Math.PI/180);
for (var angle:Number = 45; angle<=360; angle += 45) {
var endX:Number = r*Math.cos(angle*Math.PI/180);
var endY:Number = r*Math.sin(angle*Math.PI/180);
var cX:Number = endX+r*style*Math.cos((angle-90)*Math.PI/180);
var cY:Number = endY+r*style*Math.sin((angle-90)*Math.PI/180);
mc.curveTo(cX+x, cY+y, endX+x, endY+y);
}
}
// --------- DRAW FILLED circle, ----------- //
//if argument styleMaker == 22.5 you get a full circle
// 66 makes a star like figure
// usage : fillCircle(radius,x,y,22.5)
function fillCircle(r:Number, x:Number, y:Number) {
var styleMaker:Number = 22.5;
mc.moveTo(x+r, y);
mc.lineStyle(thick, color);
mc.beginFill(fill);
var style:Number = Math.tan(styleMaker*Math.PI/180);
for (var angle:Number = 45; angle<=360; angle += 45) {
var endX:Number = r*Math.cos(angle*Math.PI/180);
var endY:Number = r*Math.sin(angle*Math.PI/180);
var cX:Number = endX+r*style*Math.cos((angle-90)*Math.PI/180);
var cY:Number = endY+r*style*Math.sin((angle-90)*Math.PI/180);
mc.curveTo(cX+x, cY+y, endX+x, endY+y);
}
mc.endFill();
}
// ----- DRAW helix shape --- //
// if argument styleMaker == 22.5 you get a full circle
// 66 makes a star like figure
// usage : drawCircle(radius,x,y,22.5)
function drawHelix(r:Number, x:Number, y:Number, styleMaker:Number) {
mc.moveTo(x+r, y);
mc.lineStyle(thick, color);
var style:Number = Math.tan(styleMaker*Math.PI/180);
for (var angle:Number = 45; angle<=360; angle += 45) {
var endX:Number = r*Math.cos(angle*Math.PI/180);
var endY:Number = r*Math.sin(angle*Math.PI/180);
var cX:Number = endX+r*style*Math.cos((angle-90)*Math.PI/180);
var cY:Number = endY+r*style*Math.sin((angle-90)*Math.PI/180);
mc.curveTo(cX+x, cY+y, endX+x, endY+y);
}
}
// --------- DRAW FILLED helix SHAPE, ----------- //
//if argument styleMaker == 22.5 you get a full circle
// 66 makes a star like figure
// usage : fillCircle(radius,x,y,22.5)
function fillHelix(r:Number, x:Number, y:Number, styleMaker:Number) {
mc.moveTo(x+r, y);
mc.lineStyle(thick, color);
mc.beginFill(fill);
var style:Number = Math.tan(styleMaker*Math.PI/180);
for (var angle:Number = 45; angle<=360; angle += 45) {
var endX:Number = r*Math.cos(angle*Math.PI/180);
var endY:Number = r*Math.sin(angle*Math.PI/180);
var cX:Number = endX+r*style*Math.cos((angle-90)*Math.PI/180);
var cY:Number = endY+r*style*Math.sin((angle-90)*Math.PI/180);
mc.curveTo(cX+x, cY+y, endX+x, endY+y);
}
mc.endFill();
}
// -------------- DRAW GRADIENT SHAPE -------------- //
// this does the same as above only now with a gradient option
//useage example :
//drawGradientShape(140,200,40,22.5,
//0x0000ff,0x0000ff,100,50,50,50,100,100);
function drawGradientShape(r:Number, x:Number, y:Number, styleMaker:Number, col1:Number, col2:Number, fa1:Number, fa2:Number, matrixX:Number, matrixY:Number, matrixW:Number, matrixH:Number) {
mc.lineStyle(thick, color);
mc.moveTo(x+r, y);
var colors:Array = [col1, col2];
var alphas:Array = [fa1, fa2];
var ratios:Array = [7, 0xFF];
var matrix:Object = {matrixType:"box", x:matrixX, y:matrixY, w:matrixW, h:matrixH, r:(45/180)*Math.PI};
mc.beginGradientFill("linear", colors, alphas, ratios, matrix);
var style:Number = Math.tan(styleMaker*Math.PI/180);
for (var angle:Number = 45; angle<=360; angle += 45) {
var endX:Number = r*Math.cos(angle*Math.PI/180);
var endY:Number = r*Math.sin(angle*Math.PI/180);
var cX:Number = endX+r*style*Math.cos((angle-90)*Math.PI/180);
var cY:Number = endY+r*style*Math.sin((angle-90)*Math.PI/180);
mc.curveTo(cX+x, cY+y, endX+x, endY+y);
}
mc.endFill();
}
//
// ----------- GRADIENT RECTANGLE ----------- //
//gradientRect(0,0,200,200,0x0000ff,0x0000aa,100,100,50,50,100,100)
function gradientRect(x1:Number, y1:Number, width:Number, height:Number, col1:Number, col2:Number, fa1:Number, fa2:Number, matrixX:Number, matrixY:Number, matrixW:Number, matrixH:Number) {
mc.lineStyle(thick, color);
var colors:Array = [col1, col2];
var alphas:Array = [fa1, fa2];
var ratios:Array = [7, 0xFF];
var matrix:Object = {matrixType:"box", x:matrixX, y:matrixY, w:matrixW, h:matrixH, r:(45/180)*Math.PI};
mc.moveTo(x1, y1);
mc.beginGradientFill("linear", colors, alphas, ratios, matrix);
mc.lineTo(x1+width, y1);
mc.lineTo(x1+width, y1+height);
mc.lineTo(x1, y1+height);
mc.lineTo(x1, y1);
mc.endFill();
}
//
// ---- DRAW HEXAGON ---- //
//
public function drawHexagon(hexRadius:Number, startX, startY) {
var sideC:Number = hexRadius;
var sideA:Number = 0.5*sideC;
var sideB:Number = Math.sqrt((hexRadius*hexRadius)-(0.5*hexRadius)*(0.5*hexRadius));
mc.lineStyle(thick, color, 100);
mc.moveTo(startX, startY);
mc.lineTo(startX, sideC+startY);
mc.lineTo(sideB+startX, startY+sideA+sideC);
// bottom point
mc.lineTo(2*sideB+startX, startY+sideC);
mc.lineTo(2*sideB+startX, startY);
mc.lineTo(sideB+startX, startY-sideA);
mc.lineTo(startX, startY);
}
//usage would be drawHexagon(sideLength, startX , start Y)
//
// ---- fill HEXAGON ---- //
//
public function fillHexagon(hexRadius:Number, startX, startY) {
var sideC:Number = hexRadius;
var sideA:Number = 0.5*sideC;
var sideB:Number = Math.sqrt((hexRadius*hexRadius)-(0.5*hexRadius)*(0.5*hexRadius));
mc.lineStyle(thick, color, 100);
mc.beginFill(fill);
mc.moveTo(startX, startY);
mc.lineTo(startX, sideC+startY);
mc.lineTo(sideB+startX, startY+sideA+sideC);
// bottom point
mc.lineTo(2*sideB+startX, startY+sideC);
mc.lineTo(2*sideB+startX, startY);
mc.lineTo(sideB+startX, startY-sideA);
mc.lineTo(startX, startY);
mc.endFill();
}
//usage would be fillHexagon(sideLength, startX , start Y)
}
Можно скопировать приведённый выше код класса и сохранить как Graphics.as.
Теперь нам надо подключить класс Graphics к нашему флеш-проекту. Тут, по крайней мере, два пути.
Путь первый. Простой. Просто размещаем класс Graphics (то есть содержащий его файл Graphics.as) в одной папке с нашим флеш-проектом. Конец.
Путь второй. Более сложный, хотя... Мы должны указать программе, где лежит наш файл Graphics.as. Для этого в Macromedia Flash 8 идём по следующему пути: Edit -> Preferences -> ActionScript -> ActionScript 2.0 Settings... Появляется окно программы:

Здесь и указываем путь к нашему файлу Graphics.as.
Импортируем класс Graphics в наш флеш-проект с помощью инструкции import:
import Graphics;
Теперь, когда класс подключен, мы можем использовать его в своём проекте.
Рассмотрим возможности, предоставляемые классом Graphics.
Создаём пустой MovieClip
Когда мы что-то рисуем во флеш с помощью стандартных методов рисования ActionScript, то первым делом создаём пустой мувиклип (холст), в котором и будем затем рисовать. В классе Graphics этот приём тоже используется:
var graphics:Graphics = new Graphics(0);
В качестве параметра указывается уровень, на который мы хотим поместить наш мувик. В данном примере наш мувиклип будет помещён на нулевой уровень. Но, думаю, проще указать наивысший свободный уровень с помощью специальной функции ActionScript:
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
На данном этапе мы ничего не увидим на сцене нашего флеш-ролика. И это нормально. Мы ведь создали ПУСТОЙ мувиклип, в котором нам ещё только предстоит рисовать.
Назначение цвета контура
По умолчанию используется контур чёрного цвета. Если это вам не подходит, то цвет контура можно изменить с помощью метода setColor():
graphics.setColor("0xff0000");
В данном случае мы задали нашему контуру красный (0xff0000) цвет.
Назначение толщины контура
По умолчанию рисуется контур толщиной 1 px. Если это вас не устраивает, то меняем толщину контура методом setThick():
graphics.setThick(5);
В качестве параметра указываем желаемую толщину контура.
Назначение цвета заливки
Цвет заливки (по умолчанию стоит оттенок серого) назначается методом setFill():
graphics.setFill("0x0000ff");
В данном случае мы установили для заливки синий цвет.
Рисование линии
Линия отрисовывается методом drawLine(), которому в качестве параметров передаются координаты начальной и конечной точек линии. Например, мы можем нарисовать красную линию толщиной 5px из точки (0,0) до точки с координатами (200,200):
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.drawLine(0,0,200,200);
Рисование кривых
Кривые рисуются методом drawCurve(). В качестве параметров этому методу передаются координаты начальной точки, координаты контрольной точки и координаты конечной точки кривой. Далее идёт пример, в котором кривая построена из точки (0,0) в точку (400,0), а контрольная точка имеет координаты (200,200):
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.drawCurve(0, 0, 200, 200, 400, 0);
Подробнее о кривых в ActionScript можно почитать в посте о динамическом рисовании кривых в ActionScript.
Прямоугольный примитив без заливки
Чтобы нарисовать прямоугольный примитив без заливки нам понадобиться метод drawRect(). В качестве параметров надо передать этому методу координаты верхнего левого угла прямоугольника, а также ширину и высоту прямоугольника. Для примера нарисуем прямоугольник с красным контуром толщиной 5 px, координатами верхнего левого угла (100,100), с шириной 300 px и высотой в 100 px:
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.drawRect(100, 100, 300, 100);
Прямоугольный примитив с заливкой
Прямоугольный примитив с заливкой рисуется методом fillRect(), а в качестве параметров ему надо передать координаты верхнего левого угла прямоугольника, ширину и высоту. Так, для примера, нарисуем прямоугольник с красным контуром толщиной 5 px и синей (0x0000ff) заливкой, верхний левый угол которого имеет координаты (100,100), а ширина и высота - 300 и 100 px соответственно:
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.setFill("0x0000ff");
graphics.fillRect(100,100,300,100);
Овал без заливки
Овал без заливки генерируется методом drawOval(). В качестве параметров передаются координаты верхнего левого угла, ширина и высота овала. Например, нарисуем овал красным контуром толщиной 5 px, координатами верхнего левого угла (0,0), шириной - 550 px, а высотой - 400 px:
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.drawOval(0, 0, 550, 400);
Овал с заливкой
Овал с заливкой рисуется методом fillOval(). Параметры рисования такие же, как и у овала без заливки. В качестве примера нарисуем овал с синей (0x0000ff) заливкой:
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.setFill("0x0000ff");
graphics.fillOval(0, 0, 550, 400);
Окружность без заливки
Окружность без заливки рисуется методом drawCircle(), которому в качестве параметров передаётся радиус окружности и координаты центра окружности. Для примера нарисуем окружность с радиусом 100 px и координатами (200,200):
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.drawCircle(100, 200, 200);
Окружность с заливкой
Окружность с заливкой генерируется методом fillCircle(), которому в качестве параметров передаётся радиус окружности и координаты центра окружности. Рисуем окружность с синей заливкой, радиусом 100 px и координатами центра (200,200):
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.setFill("0x0000ff");
graphics.fillCircle(100,200,200);
Helix без заливки
Рисуется методом drawHelix(), который в качестве параметров принимает радиус и координаты центра фигуры. С помощью же последнего параметра можно "закруглять" получившуюся фигуру. Пример кода:
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.drawHelix(100, 200, 200, 1);
Приведённый выше код нарисует восьмиугольный примитив.
Helix с заливкой
Отрисовывается методом fillHelix(). Параметры аналогичны с методом drawHelix(). Пример кода:
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.setFill("0x0000ff");
graphics.fillHelix(150, 200, 200, 0);
Шестиугольник без заливки
Рисуется методом drawHexagon(). Первый параметр отвечает за размеры шестиугольника, а два последних - за положение шестиугольника по осям x и y. Пример:
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.drawHexagon(100, 200, 200);
Шестиугольник с заливкой
Создаётся методом fillHexagon(). Имеет те же параметры, что и drawHexagon(). Пример кода:
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.setFill("0x0000ff");
graphics.fillHexagon(100, 200, 200);
Градиентная заливка
Класс Graphics имеет методы для градиентной заливки геометрических примитивов:
- drawGradientShape()
Первые четыре параметры у данного метода рисуют непосредственно саму фигуру и полностью совпадают с параметрами метода drawHelix(). А вот оставшиеся параметры используются именно для настройки градиента: цвета градиента и их прозрачность, положение относительно осей координат, ширина и высота градиента. Пример градиентной заливки этим методом:
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.drawGradientShape(180,200,200,22.5,0xff0000,0x000000,100,100,0,0,400,400);
Результат будет следующим:

Как видите, с помощью этого метода мы создали окружность и залили её линейным градиентом.
- gradientRect()
Если предыдущий метод позволял заливать линейным градиентом окружности, то данный предназначен для градиентной заливки прямоугольников. Первые четыре параметра данного метода описывают сам прямоугольник (положение по осям x и y, высота и ширина). Остальные параметры описывают градиентную заливку: цвета градиента и их прозрачность, положение градиента в системе координат, ширина и высота градиента. Пример:
import Graphics;
var graphics:Graphics = new Graphics(this.getNextHighestDepth());
graphics.setColor("0xff0000");
graphics.setThick(5);
graphics.gradientRect(50,50,300,300,0xff0000,0x000000,100,100,50,50,300,300);
Результат:

Исходники под Macromedia Flash 8 и сам класс Graphics можно скачать здесь.
Вот так вот.