Евгений Потапенко признался, что уже месяца два как выложил ActionScript3-версию своего класса Conveyor, ставшим для многих незаменимым помощником во флэш-программировании.
По ссылке - отличнейшая статья и исходники.
Сообщает Ив:
Сделал менеджер карт (с примером). Это такой клас, который позволяет легко и быстро прикрутить необходимый (зум, драг) функционал к карте или к любому изображению. Никаких комментов там нет, сорри, но мне было-бы интересно услышать основные вопросы, которые возникают в процессе прикрутки.
Никаких комментов там нет, сорри, но мне было-бы интересно услышать основные вопросы, которые возникают в процессе прикрутки.
Ответы можно писать сразу Иву в руФлэш (или сюда).
Joa Ebert написал библиотеку для работы с изображениями. Чтобы понять всю ее мега мощь листаем документацию. Примеры автора: пример 1 и пример 2
Документация особо прикольная таем, что содержит картинки-иллюстрации по применению конкретных классов.
Библиотека распростряняется по лицензии Creative Commons License.
А вот еще одна жирная вещь от него же: интерактивный гончарный круг (3D-шникам известен как модификатор Lathe). И один из исходящих линков с его сайта: oos.moxiecode.com.
Автор новости -- Илья Панин.
Когда мы попытаемся произвести такую простую операцию, как добавление экземпляра класса Sprite во Флекс-приложение, -- нечто вроде myCanvas.addChild(new Sprite()); -- флекс ругнется и скажет нам, что добавлять можно только классы, реализующие интерфейс IUIComponent.
Sprite
myCanvas.addChild(new Sprite());
IUIComponent
Это потому, что все визуальные компоненты фрэймворка Fleх этот интерфейс реализуют и работают только с аналогичными реализаторами. Такая вот замкнутая система. Как же нам втиснуться со своим скромным спрайтом в эту громаду событийно-заскинованного великолепия? Ведь Sprite как класс не реализует интерфейс IUIComponent.
Значит, нам нужен тот, кто его реализует. Здесь открывается множество путей, один из которых -- создать класс, расширяющий класс Sprite и реализующий этот самый интерфейс IUIComponent -- этот путь называется Путь Великого Наследования, он долгий и утомительный, и мы туда сейчас не пойдем. Нам ведь совсем не хочется реализовывать все 86 методов интерфейса IUIComponent (я мог ошибиться, проверьте) в этот поздний час.
Ведь есть другой путь -- композиция. Это для нашего случая. Мы используем класс, который уже реализует интерфейс IUIComponent. Я выбрал класс, который называется -- о чудо -- UIComponent! Замечательно в нем то, что его метод addChild принимает в качестве аргумента столь нужный нам спрайт.
UIComponent
addChild
Значит мы теперь можем решить проблему женитьбы спрайта с компонентами Flex 2 Framework. Мы скормим свой спрайт экземпляру класса UIComponent c помощью его метода addChild, и сможем пользовться нашим спрайтом, завернутым в эту оболочку.
Я накропал простой класс UISprite, в котором это реализовано (будет обновляться, если в комментариях мне не покажут, что этот путь тупиковый и нужно было чаще ходить на форумы флэшера, чтобы не изобретать велописед):
UISprite
package { import mx.core.UIComponent; import flash.display.Sprite; /** * UISprite class is a wrapper class * for adding Sprites to Flex display list as childs. * * @author Rostislav Siryk * */ public class UISprite extends UIComponent { /** * Sprite to add to display list */ public var mySprite: Sprite; public function UISprite() { // Empty constructor } /** * Adds non-flex display object as child to this UIComponent instance * * @param assetToSet Object to add as child */ public function setAsset(assetToSet: Object): void { mySprite = (new assetToSet()); this.addChild(mySprite); } /** * Optionally sets teh hane of this UIComponent * * @param assetName New name of UIComponent */ public function setName(assetName: String): void { name = assetName; } /** * Overrides UIComponent class width getter * @return Width of the UIComponent as width of this mySprite child * */ override public function get width():Number { return mySprite.width; } /** * Overrides UIComponent class width setter * @param width New width of the UIComponent as width of this mySprite child * */ override public function set width(width:Number):void { mySprite.width = width; } /** * Overrides UIComponent class height getter * @return Height of the UIComponent as height of this mySprite child * */ override public function get height(): Number { return mySprite.height; } /** * Overrides UIComponent class height setter * @param height New height of the UIComponent as height of this mySprite child * */ override public function set height(height: Number):void { mySprite.height = height; } } }
/** * Overrides UIComponent class width getter * @return Width of the UIComponent as width of this mySprite child * */ override public function get width():Number { return mySprite.width; } /** * Overrides UIComponent class width setter * @param width New width of the UIComponent as width of this mySprite child * */ override public function set width(width:Number):void { mySprite.width = width; }
/** * Overrides UIComponent class height getter * @return Height of the UIComponent as height of this mySprite child * */ override public function get height(): Number { return mySprite.height; }
/** * Overrides UIComponent class height setter * @param height New height of the UIComponent as height of this mySprite child * */ override public function set height(height: Number):void { mySprite.height = height; } } }
Пример использования:
var myUISprite = new UISprite(); myUISprite.setSprite(someSprite); myCanvas.addChild(myUISprite);
(можно было обойтись и одной строкой кода, передавая параметр someSprite через конструктор, но я решил поддерживать подход с пустым конструктором, используемый во Flex Framework)
someSprite
Понятно, что это подходит не только для спрайтов, но также и для мувиклипов, и еще для одних замечательных сущностей, о не слишком широко афишируемой жизни которых я попытаюсь рассказать в следующий раз...
Как известно, класс Delegate позволяет выполнять любую функцию в любой заданной области видимости. Таким образом можно передавать события от любого объекта к любому другому объекту. Но иногда возникает необходимость передать не только событие, но и некоторые аргументы вместе с ним. Стандартный класс Delegate этого не предусматривает, поэтому я написал для собственных нужд класс-расширение DelegateExt, позволяющий передавать параметры вызываемой функции. Если кому-то он пригодится, буду рад. Класс пока испытан только на одном рабочем проекте, так что в случае возникновения ошибок-неполадок -- пишите сюда.
/** * @author Rostislav Siryk (rost - at - flash-ripper.com) */ class com.flashripper.utils.DelegateExt{ function DelegateExt(){ } static function create(obj:Object, func:Function, params:Object):Function { var fExt = function(){ arguments.push(arguments.callee.args); return func.apply(arguments.callee.target, arguments); }; fExt.args = params; fExt.target = obj; fExt.func = func; return fExt; } }
Кстати, в языке ActionScript 3 ни класс Delegate, ни DelegateExt не пригодится, так как в AS3 есть встроенное делегирование событий -- вот вам еще один плюс AS3.
Дизайнеры всего мира были значительно обрадованы новым и очень полезным свойством мувиклипов, Scale9Grid. Те, кто уже знает, что это такое, могут пропустить этот абзац и читать дальше начиная с заголовка "Решение задачи". Тем кто не знает: свойство Scale9Grid позволяет "разбить" мувиклип четырьмя направляющими на 9 условных зон:
1 | 2 | 3 ----------------- 4 | 5 | 6 ----------------- 7 | 8 | 9
Такое разбиение приводит к тому, что способ масштабирования мувиклипа изменяется: теперь этот мувиклип, вместо того, чтобы масштабироваться как обычно, позволяет растягиваться только определенным зонам (2 и 8 -- только по горизонтали, 4 и 6 -- только по вертикали, 5 -- во всех двух направлениях, а углам -- 1, 3, 7 и 9 зонам -- растягиваться вообще запрещено внутренним прокурором флэш-проигрывателя). Таким образом можно добиваться сохранения скруглений углов, масштаба теней, свечений и т.п. декоративных эффектов при масштабироании мувиклипа. Вот -- хороший и красочный туториал о том, как использовать свойство Scale9Grid -- исходник прилагается!.
Но во всем этом 9-зонном великолепии есть грустный факт для дизайнеров: Scale9Grid не работает в режиме LivePreview в среде разработки -- здесь по прежнему отображается уродливо деформированное нечто. Это снижает полезность данной фичи в разы -- чтобы увидеть готовый дизайн, нужно компилировать весь проект. А мы хотим видеть результат сразу же!
com.flashripper.utils.Scale9Grid
Класс com.flashripper.utils.Scale9Grid можно использовать для любых мувиклипов с заданным свойством "Scale9Grid" сколько угодно раз.
В языке ActionScript 3.0 классы представляются внутри проигрывателя как объекты класса, определяющие не только свойства и методы класса, но также и прототип и так называемые "признаки" (traits) класса, являющиеся внутренними сущностями, недоступными для прямого использования. Как вы наверняка помните из ActionScript 1-2, прототип является объектом, содержащим свойства и методы непосредственного надкласса данного класса. А поскольку прототип содержит информацию только о непосредственном надклассе, то интерпретатор ActionScript в более ранних версиях ActionScript для поиска унаследованных свойств последовательно осматривал объекты-прототипы данного класса и всех его надклассов вплоть до Object.prototype включительно. Этот способ поиска унаследованных свойств был назван цепочкой прототипов (или цепочкой наследования). В ActionScript 3.0 прототипы по-прежнему используются для реализации иерархии наследования, но для поиска идентификатора цепочка прототипов больше не используется. Все унаследованные свойства и методы экземпляра теперь хранятся в новом объекте признаков ("traits"), который избавляет от необходимости обхода цепочки прототипов для поиска свойств и методов по имени и существенно повышает производительность кода.
Предыдущие версии ActionScript предоставляли прямой доступ к объектам-прототипам в цепочке прототипов, но этого больше нет ActionScript 3.0. Теперь, когда язык предоставляет более зрелую реализацию основанного на классах программного интерфейса, "хаки" с использованием цепочки прототипов больше не допускаются. И даже более того -- оптимизация внутреннего механизма наследования, например введение объектов-признаков, обеспечивющих намного большую производительность Flash Player, сделала прямой доступ к цепочке прототипов в высшей степени непрактичным.
// via "Programming ActionScript 3.0" Alpha 1 manual
Класс SmartRestrict предназначен для обслуживания тех случаев, когда необходимо заставить пользователя ввести в определенное текстовое поле определенную строку и для контроля этого процесса. Подобные задачи возникают, например, в интерактивных презентациях и обучающих приложениях. Преставьте, что вам нужно научить пользователя вводить правильный логин и пароль при входе в систему:
import com.flashripper.utils.SmartRestrict; function onTextResult(res){ trace("Success:" + res); } // создаем экземпляр класса SmartRestrict, // в качестве параметров указывая текстовое поле, // строку, которую необходимо заставить ввести пользователя, // функцию-обработчик результата // и максимально допустимое кол-во неудачных попыток, // после совершения которых приложение само // заполнит текcтовое поле нужным значением sr=new SmartRestrict(txtLogin, "login", onTextResult,5);
function onTextResult(res){ trace("Success:" + res); }
// создаем экземпляр класса SmartRestrict, // в качестве параметров указывая текстовое поле, // строку, которую необходимо заставить ввести пользователя, // функцию-обработчик результата // и максимально допустимое кол-во неудачных попыток, // после совершения которых приложение само // заполнит текcтовое поле нужным значением
sr=new SmartRestrict(txtLogin, "login", onTextResult,5);
Исходный код класса:
// SmartRestrict class v 0.5.0.1 by Rostislav Siryk // Usage: new SmartRestrict(txtFieldToRestrict:TextField, strToBeEntered:String, fncOnResult:Function, numErrorsMaxCount:Number) import mx.utils.Delegate; class com.flashripper.utils.SmartRestrict { static private var dc=Delegate.create; private var txtField:TextField; private var strToEnter:String=String("Unknown"); private var strInProgress:String=String(""); private var numCharIndex:Number=Number(0); private var numAttempts:Number=Number(0); private var numAttemptsMax:Number=Number(24); private var fncOnResponse:Function; public function SmartRestrict(txtFieldToRestrict:TextField, strToBeEntered:String, fncOnResult:Function, numErrorsMaxCount:Number) { strToEnter=strToBeEntered; txtField=txtFieldToRestrict; fncOnResponse=fncOnResult; if(numErrorsMaxCount) numAttemptsMax=numErrorsMaxCount; //txtField.restrict=strToEnter; txtField.onChanged=dc(this,onRestricted); Selection.setFocus(txtField); } private function onRestricted() { var numCharEntered=Key.getAscii(); var numCharNeeded=strToEnter.charCodeAt(numCharIndex); trace(numCharEntered + "-" + numCharNeeded + "/"+numAttempts); if(numCharEntered==numCharNeeded) { strInProgress+=strToEnter.charAt(numCharIndex); numCharIndex++; }else{ numAttempts++; } txtField.text=strInProgress; if(numAttempts>numAttemptsMax || strToEnter==strInProgress) { doFinalize(); } } private function doFinalize() { txtField.text=strToEnter; txtField.onChanged=null; txtField.type="dynamic"; fncOnResponse(strToEnter==strInProgress); delete this; } }
import mx.utils.Delegate;
class com.flashripper.utils.SmartRestrict {
static private var dc=Delegate.create; private var txtField:TextField; private var strToEnter:String=String("Unknown"); private var strInProgress:String=String(""); private var numCharIndex:Number=Number(0); private var numAttempts:Number=Number(0); private var numAttemptsMax:Number=Number(24); private var fncOnResponse:Function; public function SmartRestrict(txtFieldToRestrict:TextField, strToBeEntered:String, fncOnResult:Function, numErrorsMaxCount:Number) { strToEnter=strToBeEntered; txtField=txtFieldToRestrict; fncOnResponse=fncOnResult; if(numErrorsMaxCount) numAttemptsMax=numErrorsMaxCount; //txtField.restrict=strToEnter; txtField.onChanged=dc(this,onRestricted); Selection.setFocus(txtField); } private function onRestricted() { var numCharEntered=Key.getAscii(); var numCharNeeded=strToEnter.charCodeAt(numCharIndex); trace(numCharEntered + "-" + numCharNeeded + "/"+numAttempts); if(numCharEntered==numCharNeeded) { strInProgress+=strToEnter.charAt(numCharIndex); numCharIndex++; }else{ numAttempts++; } txtField.text=strInProgress; if(numAttempts>numAttemptsMax || strToEnter==strInProgress) { doFinalize(); } } private function doFinalize() { txtField.text=strToEnter; txtField.onChanged=null; txtField.type="dynamic"; fncOnResponse(strToEnter==strInProgress); delete this; } }
Bob Donderwinkel создал класс SuperFades -- Actionscript 2 класс, позволяющий производить различные цветовые трансформации над любым мувиклипом.
Скачать Superfades v1.6 | смотреть демонстрацию. // Via Denis Sheremetov
Цитата:
"Свершилось!!!!! Я бился над этим больше чем пол года. Еще сырая версия, но работает вполне корректно. Скоро приведу в порядок и... эх.... заживем!
Главное, и единственное пока, что делает Path, -- это перевод расчета позиции объекта с кривой в прямую. Т.е. рассчитываем только один параметр: позиция объекта на длине пути. Затем с помощью getPointByPosition получаем координаты x, y. Таким образом задача сводится к вычислению только одного параметра: позиция объекта на длине пути. Чудить на базе этого можно уже сколько угодно. Например и скорость задавать с помощью Path и брать, например _y в качестве скорости."
Path
getPointByPosition
x
y
_y
Конец цитаты. Исходный код:
// author: Ivan Dembicki Path = function () { this.path_points=arguments.toString(), this.path_length=0; var x_array = [], y_array = [], k = 0, i, len = arguments.length, x0 = arguments[0] || 0, y0 = arguments[1] || 0, x1, y1, x2, y2, ln, o, a1, a2, a3, a4, a, b, c, d, e, a2t, sa; var s = Math.sqrt, l = Math.log, p = Math.pow; for (i=2; i<len; i += 4) { x1=arguments[i] || 0, y1=arguments[i+1] || 0, x2=arguments[i+2] || 0, y2=arguments[i+3] || 0, ln=this["ln"+k++]=[{_y:y0, _x:x0}, {_y:y1, _x:x1}, {_y:y2, _x:x2}]; // ASSetPropFlags(this, "ln"+(k-1), 7, 1) o=ln[3]={}, a1=o.a1=x0-2*x1+x2, a2=o.a2=y0-2*y1+y2, a3=o.a3=x0-x1, a4=o.a4=y0-y1, a=o.a=4*(a1*a1+a2*a2), b=o.b=-8*(a1*a3+a2*a4), c=o.c=4*(a3*a3+a4*a4), e=o.e=Math.sqrt(c), d=s(c+b+a), sa=s(a), a2t=a*2, ln[4]=(2*sa*(d*(b+a2t)-e*b)+(b*b-4*a*c)*(l(2*e+b/sa)-l(2*d+(b+a2t)/sa)))/(8*p(a, (3/2))); this.path_length += ln[4]; x0=x2, y0=y2; } this.segments = k--; // comment it! _root.lineStyle(0, 0, 30), _root.moveTo(this.ln0[0]._x, this.ln0[0]._y), _root.curveTo(this.ln0[1]._x, this.ln0[1]._y, this.ln0[2]._x, this.ln0[2]._y), _root.curveTo(this.ln1[1]._x, this.ln1[1]._y, this.ln1[2]._x, this.ln1[2]._y); _root.curveTo(this.ln2[1]._x, this.ln2[1]._y, this.ln2[2]._x, this.ln2[2]._y); // end comment it }; tmp = Path.prototype={}; tmp.getPointByPosition = function(poz) { if (poz<0 || poz>this.path_length) { return {_x:this.ln0[0]._x, _y:this.ln0[0]._y}; } if (this.segments<1) { return false; } var i = 0, ln, len = 0, ff = 0; for (i; i<=this.segments; i++) { ln=this["ln"+i], len += ln[4]; if (len>poz) { ff = (poz-(len-ln[4]))/ln[4]; break; } } var s = Math.sqrt, l = Math.log, p = Math.pow, abs = Math.abs; var fn = function (ff) { var o = ln[3], a1 = o.a1, a2 = o.a2, a3 = o.a3, a4 = o.a4, a = o.a, b = o.b, c = o.c, e = o.e, i = 1, st = 1, f_l = ln[4], t_l = ff*f_l, max_i = 100, d, sa, a2i; while (max_i--) { d=s(c+i*(b+a*i)), sa=s(a), a2i=a*2*i, f_l=(2*sa*(d*(b+a2i)-e*b)+(b*b-4*a*c)*(l(2*e+b/sa)-l(2*d+(b+a2i)/sa)))/(8*p(a, (3/2))); if (abs(f_l-t_l)<.000001) { return i; } st /= 2, i += f_l<t_l ? st : f_l>t_l ? -st : 0; } return i; }; var f = fn(ff), p0 = ln[0], p1 = ln[1], p2 = ln[2], e = 1-f, ee = e*e, ff = f*f, b = 2*f*e; return {_x:p2._x*ff+p1._x*b+p0._x*ee, _y:p2._y*ff+p1._y*b+p0._y*ee}; }; delete tmp;
Как это использовать:
/// TEST _root.createEmptyMovieClip("mc", 0); _root.mc.lineStyle(5, 0xFF0000, 100); _root.mc.lineTo(.2, 0); _root.mc.tween_path = new Path(0, 0, 100, 0, 100, 100, 100, 200, 450, 380, 0, 300, 0, 0); _root.mc.speed = _root.mc.path_position=0; _root.mc.onEnterFrame = function() { if (this.path_position>this.tween_path.path_length) { this.path_position = 0; } this.path_position += this.speed += .01; var poz = this.tween_path.getPointByPosition(this.path_position); this._x=poz._x, this._y=poz._y; };
Скачать класс Path: http://www.sharedfonts.com/Path.as.
Совсем древнее: 17-20.09.2002, 23-30.09.2002, 01-04.10.2002, 07-11.10.2002, 14-19.10.2002, 20-26.10.2002, 27.10-02.11.2002, 04-08.11.2002, 11-16.11.2002, 18-23.11.2002 25-30.11.2002, 02-07.12.2002, 09-14.12.2002 Сайт заработал 17.09.2002