Числовые методы в одно касание
Как видим, перед нами дифференциальное уравнение второго порядка. Для этого случая есть старые и миллион раз проверенные числовые методы интегрирования. На самом деле там все проще, чем кажется: вычисления производятся методом "а почему бы и нет" — то есть берется начальная точка и как бы немного аппроксимируется первыми членами разложения Эйлера к следующей в предположении, что это не черт знает где, а где-то рядом. Ну, то есть y[i+1]=y[i]+dy.
Например, большой популярностью у студентов и преподавателей пользуется метод Рунге-Кутты четвертого порядка точности. Не буду вдаваться в подробности — сами посмотрите в тексте программы. Главное, что каждая следующая точка будет вычисляться как функция предыдущей. А поскольку уравнение у нас второго порядка, начальная точка будет задаваться двумя координатами: (x, y), где y — суть функциональная производная от x, но в данном случае мы будет смотреть на нее как на независимую переменную.
Сразу скажу, что мы не будем "бороться" с переменным шагом интегрирования — это, конечно, выгодно с точки зрения вычислений, но усложнит демонстрацию того, что мы тут будем демонстрировать: применение Flash в качестве вычислительной среды.
Диагноз: Ш 7-Б
А теперь, если посмотреть на вещи прагматично, глазами конкретных людей из ЦРУ, ГРУ и других беспредельных заведений. Это мы для примера взяли какие-то странные аттракторы — а ведь эти-то ребята могут поручить Flash-скриптам все что угодно, от расчета биологического оружия, декодирования шифров, дешифрации изображений со спутников до вычитки электронной почты и… да мало ли хороших дел можно придумать.
И если раньше для этого нужно было покупать новый мэйнфрейм за несколько миллионов, то теперь достаточно перетереть с yahoo.com и разместить там свой Flash-банерок. Видели там такие большие Flash’ки? Это с виду там реклама кредитных карточек, а на самом деле — кто знает?
А ведь можно сделать "вычислитель" и вовсе маленьким и невидимым…
С другой стороны, можно, как в , наоборот — разрекламировать, раструбить, чтобы любой пользователь мог поставить вашу флэшку домашней страничкой и таким образом стал помогать вам бороться со СПИДом, искать пришельцев и раскодировать коды террористов. Это уже вопрос наглости, под каким предлогом вы будете тырить у людей их процессорное время.
Кстати, ходит такая полусказка, что, мол, Саддам Хусейн в ответ на эмбарго на ввоз компов в Ирак скупал приставки Nintendo 64, ставил на них Linux, объединял в кластеры и решал стратегические задачки типа просчета траекторий ракет. Не уверен, что именно так оно и было — но идея, без сомнения, интересная. В любом случае, скрытые возможности есть, и рано или поздно они будут использованы.
Использованы иллюстрации с сайта .
document.write('');
Новости мира IT:
02.08 - 02.08 - 02.08 - 02.08 - 02.08 - 01.08 - 01.08 - 01.08 - 01.08 - 01.08 - 01.08 - 01.08 - 01.08 - 01.08 - 01.08 - 31.07 - 31.07 - 31.07 - 31.07 - 31.07 -
Архив новостей
(66)
2 Август, 17:53
(19)
2 Август, 17:51
(34)
2 Август, 15:40
(42)
2 Август, 15:35
(1)
2 Август, 14:54
(3)
2 Август, 14:34
(3)
2 Август, 14:15
(2)
2 Август, 13:34
(7)
2 Август, 13:04
(3)
2 Август, 12:28
BrainBoard.ru
Море работы для программистов, сисадминов, вебмастеров.
Иди и выбирай!
google.load('search', '1', {language : 'ru'}); google.setOnLoadCallback(function() { var customSearchControl = new google.search.CustomSearchControl('018117224161927867877:xbac02ystjy'); customSearchControl.setResultSetSize(google.search.Search.FILTERED_CSE_RESULTSET); customSearchControl.draw('cse'); }, true);
IT-консалтинг | Software Engineering | Программирование | СУБД | Безопасность | Internet | Сети | Операционные системы | Hardware |
PR-акции, размещение рекламы — , тел. +7 495 6608306, ICQ 232284597 | Пресс-релизы — |
This Web server launched on February 24, 1997 Copyright © 1997-2000 CIT, © 2001-2009 |
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. |
Источники воды. Если на Agriko-Akva.ru. Для бытового использования. |
Flash ActionScript и странные аттракторы
Арсений Чеботарев,
Я уже как-то рассказывал и показывал, как работает сервер приложений Cold Fusion от Macromedia. Но вот, опять встречаю человека, а он мне и говорит: "А-а-а, флэшки? Это которые картиночки про Масяньку?". Елы-палы, объясняю для детей природы…
Вот уж люди: любят носиться со своими предрассудками — и что обидно, еще и живут при этом долго. Ну какая же там за бесценок продавшаяся Масянька, если "флэш анимейшин" — это на сегодня самый простой и очень мощный способ кросс-платформенного самовыражения.
Конечно, происхождение флэшки — самое что ни на есть простецкое, первые версии вообще не далеко ушли от анимированных GIF’ов, но главное, как поняли макромедийцы,— это попасть на комп пользователя и подсадить народ на продукт, чтобы люди апгрейдились и апгрейдились. Сам апгрейд через плуг — это пожизненный памятник Flash’евским создателям.
Вот так вот под шумок у нас на компьютерах и поселилась самая что ни на есть операционная среда Flash и виртуальная Flash-машина.
Изначально Flash работал только под MS Windows и Mac OS. Благодаря фирме Sun Flash был портирован под X-Windows, то есть на Solaris, IRIX, BSD, Linux. Количество установленных Flash-плееров приблизительно равно количеству установленных браузеров, которые, в свою очередь, в любом случае сопутствуют графическим оболочкам, таким как KDE. Короче, на сегодня вероятность встретить на персональном компьютере Flash-плеер составляет около 86%, и то последние 14% относятся к "только что установленным", на которые плагин просто не успел попасть.
Конечно же, первую роль играет красивая анимация — но, заметьте, сетевая анимация. То есть поддерживается доступ к сетевым ресурсам для загрузки данных и изображений. Конечно, все это ограничено довольно специфичными рамками, но главное — есть доступ к серверам приложений. А значит, все, что нельзя сделать, локально можно делегировать серверу. И в этом заключается прикол, так и должны работать сетевые приложения.
Важен и фактор компактности самого плеера, который на сегодня не превышает 400 Кб для большинства платформ. Такой плеер легко встроить в любой смартфон или хэндхэлд. Сравните с виртуальной машиной Java даже в минимальной версии. Конечно же, на стороне Java — мощность и богатство платформы, но у этой мощности имеются не только стороники, но и противники. Есть же люди, платящие суммы как за супермощные джипы, так и за маломощные и экологичные автомобильчики — и последних все больше. Так и в программировании: для изучения всех иерархий классов и разработки новых иерархий в Java может понадобиться много месяцев. А задача за это время может быть решена на Flash — и при том, заметьте, серверная часть будет портабельной и инвариантной, так что тут даже больше гибкости и правильности. О том, что фронт-энд будет красивее на Flash, можно и не говорить — конечно, если под рукой есть про-дизайнер с руками в нужном месте.
Ладно, хватит чесать блох — переходим к практике дзен. Практику нам раздали такую: создать портабельное, интерактивное, распределенное приложение. Причем никаких масянек, никаких летающих пингвинов — что-то из мира науки, что-то из математики. Что-то, что бы могло показать, что Flash может использоваться в качестве калькулятора.
Немного оптимизации: истребляем в себе все человеческое
Еще чуть-чуть теории — а потом сплошная практика. Поговорим о человеческом факторе в науке.
Если порыться в любой научной отрасли, даже в сравнительно чистой математике или физике, можно найти не только штаны Пифагора, но и старые носки Эйлера. Например, та же десятеричная система появилась благодаря привычке считать на пальцах. Ну разве не абсурдная причина? Та же секунда времени — усредненная частота сердечного ритма. Ну разве не странная единица? Более поздние "находки", типа 360 градусов окружности — это уже дань более ученым расчетам. Не смогли поделить угол на три части, вот и придумали: сделаем в полном развороте 3х4х5х6=360 частей, будет делиться по определению на что угодно.
С другой стороны есть реально интересные числа: то же. Например, стоит договориться с тараканами, что такое окружность, ее центр и радиус, а также выяснить, что такое ряды, так сразу любой таракан сможет доказать вам, что длина окружности, выраженная через ее же радиус, равна Пи.
Короче, старая хитрость: хочешь понять систему — говори на ее языке, а не на своем. Это знают математики и программисты, взять ту же задачу вавилонских башен и ее рекурсивное решение. Оказалось, что есть простое решение, нужно только выбрать точку зрения.
А мы тут при чем? Вот при чем. Как правило, при задании dt в числовых методах используются "отбалденные" значения типа 0,1. Это число просто удобно в десятичной системе счисления — больше в нем ничего хорошего. Даже если применяются методы динамического шага, то в лучшем случае мы перейдем к 0,2 или 0,01. Хрен редьки не слаще.
На самом-то деле наша система обладает своим собственным сердцем: R*cos(wt). Вот это и есть естественный для нашей системы хронометр, часы — или называйте как хотите. Один полный оборот этих часов — это и будет наша единица времени, назовем ее революцией, то есть оборотом.
По ходу задачи для получения аттракторов мы должны будем фиксировать значения в одной фазе нашего колебатора, например в нулевой. Если мы выберем dt произвольно, то не факт, что в одном обороте будет целое число шагов — даже наверняка не будет. В результате наш рабочий цикл для вычисления тысячи точек будет выглядеть примерно так:
int time=0; dt=0.1; cnt=0;
while(cnt<1000) {
x1=fn(x);
if ((2*Pi*(cnt+1))-(tme*w))>=0 {cnt++; … }
x=x1;
}
Короче, мы должны будем отслеживать, как наша "стрелка часов" приближается к нулевой отметке, и брать, например, первую точку, которая прошла "за полночь". Не точно, не удобно и не спортивно. Гораздо проще и куда интереснее разделить нашу революцию на целое число частей (как это сделано с градусами) и "ходить конем" только в эти точки. Тогда вычисления аттрактора будут точными, кратными целому и постоянному числу "ходов".
На сколько частей делить революцию — априори не понятно, но можно предположить, что для вычислений удобными будут степени двойки. Тогда мы сможем для энного хода получать значение mod(n), что для степеней двойки эффективно реализуется отбрасыванием старших разрядов с помощью битовой операции AND.
Введем такую величину, как революция/2n, или сокращенно revN2. Это величина, представляющая деление одного оборота на 2n. То есть: rev8 — 256-я часть от одного оборота, rev10 — 1024-я и т.д. Такая система измерения удобна для компьютера. Например, можно создать объект rev (8, "сos", R, w), который просчитывает косинус с градацией 256 позиций на один оборот, с радиусом R и частотой w и заносит результаты в таблицу-массив. Частота тут, собственно, нужна, для вычисления временного шага: если rev8=2*Pi/2n, то w*dt_revN=2*Pi/2n, в частности w*dt_rev0=2*Pi/20. Это можно реализовать как метод объекта rev, например GetTimeStep().
Теперь все чудно: для получения тысячи точек аттрактора только и нужно, что устроить цикл:
for (i=0;i++;i<1000) for (j=0;j++;j<256)
А значения косинуса можно получать из массива в заранее просчитанном объекте rev:
rev.GetValue(i)
Не буду рассказывать, насколько выборка из массива быстрее вычисления косинуса. Скажу только, что в ActiveScript обе операции реализованы способом, далеким от идеального. Массивы на самом деле представляют собой ассоциативные списки Java, косинус — тоже, очевидно, не реализуется одной процессорной командой, как могло бы быть в идеале. Но и в этом случае массив дает огромное преимущество, включая экономию на одном дополнительном умножении на радиус на каждом расчете. Ситуация осложняется еще и тем, что для расчета одной точки Cos вызывается четыре раза, то есть для тысячи точек и rev8 количество вычисляемых косинусов достигает 4х256х1000=1e6, то есть одного миллиона! Это не шутка даже для ассемблера.
На этом — конец теории, полный и окончательный.
Об объектной модели ActionScript
Если вы привыкли работать с объектами в C++, то объекты в ActionScript частично окажутся для вас шокирующими. Для начала: вы привыкли к наличию классов и экземпляров? Придется отвыкать. Классы в ActionScript — это тоже экземпляры, только особого типа. Ну, собственно, если вы задумаетесь, как работают статические методы в классах C++, то поймете, что создавать экземпляр не всегда нужно. Если проводить параллель с ActiveX, то объекты-классы (объекты типа "класс") можно назвать фабриками классов.
Эта каша серьезно усложняет понимание, но не использование классов и объектов. Об объектах-классах также можно думать как о шаблонах, а о производных "экземплярах" как о копиях, создаваемых методом Clone(). Поэтому об объектах-классах еще говорят как об объектах верхнего уровня.
На самом деле вы будете часто пользоваться такими объектами верхнего уровня, предопределенными в самом Flash. Некоторые объекты вообще существуют в одном экземпляре, точнее — не являются экземплярами никаких классов, и создание новых копий не предполагается. На таком объекте выполняются только статические методы, хотя понятие статических методов, как таковых, в ActionScript, не существует.
К более привычным относятся два других типа объектов — "сточные" и пользовательские. Первые заранее определены, и вы обычно создаете их экземпляры. Например, вы создаете новый экземпляр snd=new Sound() для воспроизведения вашего саундтрека. Особый тип объектов, MovieClip, создается специальной функцией. Пользовательские классы создаете вы сами. И тут вас поджидает другой микро-шок.
Этот микро-шок — синтаксис декларирования класса. Его (синтаксиса) нет. Для определения класса используется слово function! Это уже жестоко напоминает "ООП" в perl: оказывается, все реализовано через области видимости, то есть класс определяется областью видимости локальных переменных и функций.
Это стало возможным потому, что, в отличие от C++ и в полном соответствии с Паскалем, допускается создание локальных функций внутри функций, так сказать иерархическая, а не одноранговая архитектура.
На еще более глубоком уровне зарыты локальные анонимные функции — то, что мы назвали бы виртуальными методами или указателями на функции. Эти функции доступны не по имени, а через "хэндлеры", в качестве которых выступают переменные, в частности — элементы списка. Именно так, через список дочерних функций, реализованы области видимости. Виртуальность заключается в том, что вы можете найти нужный метод и переопределить его, независимо от того, писали вы его сами или же унаследовали от суперкласса.
Сами функции, как можно уже догадаться, также являются объектами типа Function. Естественно, что функция содержит списки локальных объектов. Кроме этого функции содержат список своих аргументов (свойство arguments), ссылку на вызывающую и вызываемую функции (то есть на саму себя), а также несколько методов, вроде call и apply. Эти методы явно получают в качестве первого параметра ссылку на объект, из которого вызывается метод, и null, если это "свободная" функция.
Жара, однако, крепчает. Оставим на время эту теорию и проиллюстрируем ее практикой. Не простой, конечно, а относящейся к нашей задачке. Создадим класс, который вычисляет тригонометрические (впрочем, как и любые другие) функции, разделяя окружность на 2n частей. Впоследствии для любого положительного N возвращается значение в этой точке. Также можно спросить, какое "время" соответствует этому N. Параметры на входе конструктора: n, fn(){}, A, w. Где n определяет количество точек, функция задает вычисляемую зависимость, A и w — амплитуда и частота соответственно. Go-go.
function rev(n,fun,a,w) {
this.length=1<N;
this.mask=this.length-1;
this.values=new Array(this.length);
this.slice=Math.PI*2/this.length/w;
var i=0;
while (i<THIS.LENGTH) {
this.values[i]=a*fun(i*this.slice*w); i++; }
}
rev.prototype.GetValue=function(i){ return this.values[i&this.mask];}
rev.prototype.GetSlice=function(){ return this.slice;}
rev.prototype.GetLength=function() {return this.length;}
Вы, возможно, захотите спросить, почему я использую while, а не for. А потому что в for у меня проблемы. Может глюк, а может мне просто ума не хватает. В любом случае, в теории есть только три программных конструкции: последовательность, выбор и итерация — так что разницы никакой. Как видите, код компактный, на вид приятный (и при этом — работающий). Есть пару "хакерских" местечек, например вычисление той же битовой маски или "почему сначала делится на w, а потом умножается". Честно говоря, я и сам ничего не понимаю, просто это вот работает — значит угадал что-то.
Использование этого объекта такое (числа — номера кадров):
1 #include "coord.as"
#include "rev.as"
callback=function(arg){return Math.cos(arg);}
rev1=new rev(10,callback,1,1);
rev2=new rev(6,callback,2,2);
2 cnt=0;
while (cnt<REV1.GETLENGTH()*3) {
dt(cnt*rev1.GetSlice(),rev1.GetValue(cnt),0x00f);
Cnt++; }
3 cnt=0;
while (cnt<REV2.GETLENGTH()*3) {
dt(cnt*rev2.GetSlice(),rev2.GetValue(cnt),0x00f);
Cnt++; }
4 Stop();
Как видите, мы создаем два объекта, причем отличаются эти объекты тремя параметрами: порядком революции (количеством точек на оборот), амплитудой и частотой. Кроме того, мы проверяем три оборота, чтобы оценить, что наш объект корректно отсекает лишние биты и не ошибается при доступе к массиву. Графически результат выглядит так:
Наши объекты работают ожидаемым образом
Два глюка, кроме for, были обнаружены при работе с as-файлами. Во-первых, вы обязательно должны завершить последнюю строку переводом курсора — иначе ошибки, ошибки... Такие глупости когда-то встречались в некоторых утилитах UNIX — и, как видно, ходят по миру до сих пор. Второе — в режиме Ctrl+Enter какие-то вещи не меняются при изменении внешних файлов. То есть алгоритм обновления кэша включаемых файлов не работает как следовало было. Если ваши изменения в тексте программы не имеют эффекта, попробуйте проверять по Ctrl+F12 — должно сработать. Кстати, и производительность в браузере раза в два больше. Видимо, отключается какая-то отладка или что-то в том же роде.
Практика: точки, системы координат, синхронизация etc.
Теперь откроем наш Flash и попробуем что-то там рисовать, в том числе аттракторы. Не будем слишком упираться в красоту, хотя, конечно, не без этого. Для начала: что может рисовать Flash? Ответ: ничего, кроме прямых. Вы в шоке? А как же, по-вашему, должна работать векторная графика? Короче, в нашем распоряжении только два метода: moveTo для перемещения в точку растра объекта MovieClip и lineTo для рисования прямой от текущей точки до другой, которая, соответственно,становится текущей. Кто помнит, все это напоминает первобытные функции рисования в Turbo Pascal или убогую "черепашку" с плоттером в клюве.
Даже рисование точки — уже кое-какая проблема, поскольку если нарисовать прямую из точки до самой себя, то ничего не будет нарисовано. Хотите нарисовать точку — нарисуйте маленький квадратик, или линию, или крестик — так будет лучше всем. Главное — вы можете рисовать отрезок дробной длины, так что крестик 0,1 на 0,1 эффективно закончится пикселем на экране.
Два возможных решения не проходят через цензуру. Первое — рисовать маленький квадратик, закрашенный с помощью BeginFill и EndFill в некоторый цвет, но с прозрачной рамкой. Работает, но по производительности — полный сакс.
Второй метод — клонировать объект типа "точка". Это вообще не работает, потому что на одном фильме может лежать только 255 объектов, каждый на своем слое. Так что много точек таким методом вы не нарисуете. Помещение символа в тот же слой будет удалять предыдущий символ. Если вы помните, как программировались старые игровые приставки, то там тоже в одной строке сканирования не могло разместиться более восьми спрайтов.
Кроме рисования точек нам понадобится преобразование координат из предметной области в условные пиксели рабочей поверхности. Это задача для школьников старших классов, так что не стану на ней останавливаться. Замечу только, что не делаю поверхность рисования динамически растягиваемой, размер подложки постоянный — 1200 х 800. Любое масштабирование объекта MovieClip можно и нужно выполнять (и так оно и будет) средствами Flash, причем с такими чудесами техники, как антиалиасинг. Не будем улучшать совершенное.
Вот как выглядит рисование простейшей системы координат
width=1200; height=800;
dx=20; dy=4;
kx=width/dx; ky=height/dy;
originX=width/20; originY=height/2;
cx=originX/kx; cy=originY/ky;
function x(x1) { return originX+x1*kx; }
function y(y1) { return originY-y1*ky; }
function mv(x1,y1) { moveTo(x(x1),y(y1)) }
function li(x1,y1) { lineTo(x(x1),y(y1)) }
function dt(x1,y1,dcl) {
var xx=x(x1); var yy=y(y1);
lineStyle( 1, dcl, 100 );
moveTo(xx,yy);
lineTo(xx+.1,yy+.1);
}
lineStyle( 1, 0x0, 35 );
moveTo(0,0); lineTo(0,height-1);
lineTo(width-1,height-1); lineTo(width-1,0);
lineTo(0,0); moveTo(0,originY); lineTo(width-1,originY);
moveTo(originX,0); lineTo(originX,height-1);
Код находится в отдельном файле coord.as и включается в первый кадр командой #include "coord.as". Имена функций нарочно имеют минимальную длину — моя фантазия подсказывает мне, что при рисовании удобно упаковывать побольше элементов в одну строку.
Теперь, чтобы проверить фишку, попробуем что-нибудь нарисовать. Построим тот же косинус… оба-на! For на 1000 итераций не работает! А все оттого, что мы беремся рисовать много точек в одном кадре — оно-то рисует, но кино не может обработать другие кадры, и все валится с ругательствами. Обходим: помещаем куски кода в разных кадрах:
1 #include "coord.as"
i=-3;
2 dt(i,Math.cos(i),0x0); i+=0.1;
3 if (i<=3) { GotoAndPlay(2); } else { Stop(); }
Чтоб дела шли быстрее, можно fps фильма разогнать до 120-ти. Теперь все работает как часы, точечки рисуются. А вдруг можно еще упаковаться? Без проблем: во втором кадре копируем строку — то есть по входу в кадр рисуются две точки сразу. Можно записать "оптимизатор" во втором кадре таким вот образом:
cnt=0;
while ((i<=3)&&(cnt<=100)) {
dt(i,Math.cos(i),0x0);
i+=0.01;
cnt++;
}
В результате наши расчеты не мешают воспроизведению остальной анимации, если таковая вдруг появится. Самый простой пример такой анимации — поле динамического текста, привязанное к переменной. Этот текст будет обновляться не чаще, чем мы будем переходить от кадра к кадру, так что это нужно периодически делать, если мы хотим отображать "бегущие счетчики", например, отрисованных точек.
Переходим к более сложным вопросам ActiveScript.
Странные картиночки
Мы не будем детально обсуждать реализацию наших числовых методов, там все как в книжках. Важно то, что есть какая-то функция. На входе она воспринимает точку на плоскости, а на выходе дает следующую точку. Делов-то. Полный текст всех наших AS файлов — на КП-диске. В нашем "кине" код тоже не слишком сложен и похож на то, что мы уже видели:
1 #include "coord.as"
#include "rk4.as"
c=1.0; A=1.1; w=2.1; revN=8;
rk = new rk4(c,A,w,revN);
dots=1;
dotcolor=0x003300
2 for (i=0;i<500;i++) {
rk.NextPoint();
if ((rk.GetTI()&255)==0) {
dt(rk.GetX(),rk.GetY(),dotcolor);
dots++;
}
}
3 if (dots>100000) {Stop();} else {GotoAndPlay(2);}
Вот как один из наших странных аттракторов выглядит в результате.
Инь и Янь имеют простую математическую интерпретацию
Как видите, все очень красиво и похоже на ожидаемый результат. По сложившейся традиции все происходит на черном фоне. Аттрактора тут, собственно, два — в разных фазах. Фиолетовый соответствует нулевому смещению фаз косинуса, красный — полуобороту, углу Пи. Благодаря нашему табличному генератору делается все это просто.
Конечно, правильный препод должен сделать замечание, что, мол, на координатные оси не нанесены единицы измерения, кроме того, не указаны параметры. Серьезный программист, посмотрев в код, может дополнить, что координатную сетку тоже можно сделать объектом и параметризировать. К тому же, поскольку вычисления тут превалируют над отрисовкой, то несложно будет рисовать сразу 128 фазовых слоев в 128-ми окнах. Более того, можно эффективно анимировать слои, циклически заменяя символы MovieClip.
Да, все это так — но главное для нас не это. Куда интересней, что ActionScript может считать не хуже того же Бейсика — и при этом эффективно отображать результаты. Что и требовалось доказать. Кстати, вы легко можете кликнуть по клипу и прилизать любой участок — без единой строки кода. А теперь реализуйте это сами, например на C++… Ну, а мы пока будем продвигаться дальше.
А где же тут интерактивность и распределенные вычисления? Простой ответ: в Караганде. Более детально: Flash в современной форме включает все для интерактивности, реализованы основные элементы управления, а каких и нет — те можно добавить. Первое, что приходит в голову: позволить пользователю вводить параметры нашего уравнения и нажимать кнопку Пересчитать. Но это противоречит другой идее — распределенным вычислениям. В конце концов, можно сделать хотя бы кнопку Выход, для нетерпеливых.
Идея распределенного вычисления как раз и состоит в централизованном (или распределенном) управлении вычислительным процессом. Для реализации такого поведения проще всего создать на сервере XML-приложение, которое будет реализовать управление. Пользователю браузера при этом отводится роль лоха-наблюдателя.
В случае с нашим приложением можно предположить, что в качестве параметров будут выступать c, A и w. В качестве результата программа может сбрасывать те же параметры, плюс тип полученного графика: странный — не странный (придется еще реализовать детектор странности). Серверная часть легко сможет заносить эти данные в базу данных — с последующим анализом. Кстати, программа анализа этой БД тоже может быть написана на Flash, почему бы и нет.
С точки зрения программирования ActiveScript тут нет никаких проблем: в язык встроена поддержка XML-сообщений. Также в широком ходу и старая техника — LoadVariables. При этом вместо файла вы указываете имя CGI-скрипта, который и поставляет необходимые пары "имя-значение". Короче, даже выбор есть.
Выглядит это даже проще, чем кажется: например, для загрузки параметров из duffarg.pl можно загрузить переменные. Для этого достаточно строку
c=1.0; A=1.1; w=2.1; revN=8;
заменить на:
_root.LoadVariables(duffarg.pl,"GET");
Если скрипт генерирует параметры в виде XML, загрузить их будет чуток сложнее:
duffXMLParams=new XML();
duffXMLParams.onLoad=function(success) {
if (success) {
… Разбор XML документа
}
}
duffXMLParams.load(duffarg.xml);
Для "отдачи" результатов легко можно использовать метод XML.send() — отсылка работает еще проще, без ожидания результата. Несложно организовать и отсылку переменных, указав в качестве метода доступа "POST" либо же "PUT" — в качестве второго параметра LoadVariables().
Задачка: странные аттракторы (очень краткий курс)
Придумал, а точнее — вспомнил. Есть в мире математики такие популярные вещи, как странные аттракторы. Это когда что-то там движется странно. Как известно, когда решаешь дифуру, то в простом случае получается что-то такое периодическое, или не совсем — ну, короче, что-то не странное. Поведение простого колебатора одно из трех: либо затухает, либо выходит на орбиту (тупо аппроксимирует к ней), либо вообще входит в резонанс (само с собой — одна часть уравнения с другой) и разрывает все к ежам, как говорится — "движущиеся части системы выходят из наблюдаемой области". Во втором случае колебатор называют осциллятором.
Ага, нету такого слова колебатор? Ну о’кей, считайте меня автором — с момента публикации у меня на это слово все права.
А потом обнаруживается, что некоторые системы колбасятся по непонятному закону — то есть не видно, где у него период. Одним из простых странных колебаторов является система, описываемая уравнением Дюффинга:
dx/dt=dfy, dy/dt = x-x3 — c*y + A*cos(w*t)
Как видите (ну, типа видите), тут в наличие источник суеты в виде какого-то внешнего колебатора A*cos(w*t) и "гальмо" (энергетическая утечка, в механике — трение) в виде -c*y и, плюс к этому, еще какая-то гадость, описывающая закон движения точки в пространстве в зависимости от времени. Есть несложная физическая интерпретация — но она нам сейчас без интереса. Хотите — почитайте здесь: .
Да, так вот, при некоторых параметрах получаем достаточно замысловатое движение. Странно ведут себя как координата x, так и скорость y. Вот как выглядит, например, жужжание хаотического шмеля.
Координата и скорость точки в хаотическом режиме
Для прикольности можно построить график зависимости x от y — красиво видно, как и куда сходится поведение системы с течением времени.
Скорость как функция координаты
Больше таких картинок вы можете увидеть на сайте, с которого было взято это изображение — линк в конце статьи. Я нарочно взял независимые результаты, чтобы потом сравнить их с собственными, тут никакой ошибки. Интерактивную версию можно посмотреть здесь: .
Есть еще вариант: отмечать на графике только точки в одной фазе колебатора возбуждения. Это именно и есть странный аттрактор. Там такой кисель смешной образуется — называется подковообразное преобразование. По этим картинкам определять странность вообще просто. Посмотреть на странный аттрактор "в натуре" в виде gif-анимации можно по адресу: www.sekine-lab.ei.tuat.ac.jp/~kanamaru/Chaos/e/Animation/duffing.html.
Что нас будет интересовать, это то, при каких параметрах проявляется странное поведение. Само поле параметров является слегка глючным: при одних параметрах проявляется странность аттрактора, при других (даже бесконечно близких) — как и не бывало, налицо отвратительная и нежелательная гармония. Вот и постараемся, по крайней мере графически, отобразить области, где странность проявляется, а также области, где таких странностей нет.
Загрузка текста и переменных во Flash
(C). ,
Как таковой возможности загружать текст во Flash нету, но имеется возможность загружать переменные извне (в том числе и из текстовых файлов). Переменные передаются в стандартном формате GET-запроса:
[переменная]=[значение]&[переменная]=[значение]&...&...
- в таком виде формируются пары переменная-значение, разделённые символом амперсанда ("&"). Flash может также принимать переменные, сформированные серверными сценариями (PHP, ASP, JSP, CGI, Cold Fusion и т.п.). Но об этом пойдёт речь ниже. Сейчас же продемонстрируем загрузку текста (и почему только текста? да любых переменных! :) из обычного (текстового :) файла.
Для начала, сформируем текстовый файл, который нам предстоит загрузить. Он должен состоять из пар переменная=значение, разделенных амперсандом. Амперсанд определяет конец значения переменной, так что перед ним не должно быть пробелов или символов перевода каретки (если, конечно, это не входит в ваши планы). Вот пример содержимого текстового файла, который можно дать Flash на загрузку:
myText=This is the text to be loaded to Flash.&myValue=123.45
Сохраняем этот файл под именем "vars.txt".
Теперь создадим Flash файл, в который будет загружаться этот файл. Нам потребуются текстовые поля с именами myText и myValue и кнопка, которую мы будем использовать, чтобы инициировать загрузку:
Нам нужен только очень простой код для кнопки:
on(release) {
loadVariables("vars.txt", "_root");
}
Как вы догадались, всё выполняет функция loadVariables(). Рассмотрим её подробнее.
loadVariables() служит не только для загрузки переменных из внешних источников, но и для передачи переменных из Flash в серверные скрипты или другие ролики Flash.
Формат фунцкции loadVariables() следующий:
loadVariables("url", level/"target" [, variables]);
url - абсолютная или относительная ссылка на файл, из которого/в который будут посылаться данные.
level - номер уровня, на который будут загружены переменные. Чтобы указать числовое значение, нужно использовать функцию loadVariablesNum(). В этой же функции можно использовать идентификаторы уровней (например, loadVariablesNum("vars.txt", "_level0") для загрузки на 0-й уровень).
target - идентификатор клипа (movie clip), в который загружаются переменные.
Указывается либо идентификатор уровня, либо идентификатор клипа. Нельзя указать оба параметра одновременно.
variables - необязательный параметр, используется при посылке переменных, указывает метод посылки: GET или POST.
В нашем примере, мы загружали переменные из текстового файла vars.txt в основной объект Flash-ролика: _root.
Скачать файлы данного урока: (3 k)
В рассказано как можно передавать данные из Flash в сценарий PHP.
Удачи!
Передача данных из Flash в серверные сценарии
(C). ,
В прошлом уроке мы рассмотрели возможность загрузки данных во Flash. Сейчас мы научимся посылать данные из Flash во внешние сценарии, или в другие ролики Flash.
Как и в , нам потребуется .swf файл, из которого мы будем посылать данные. Пусть он содержит два поля для ввода переменных и пару кнопок, при нажатии на которые будут посылаться данные:
Послать данные можно как с помощью функции loadVariables(), описанной в , так и с помощью знакомой многим getURL(). В нашем примере одна кнопка использует первую функцию, другая - вариант с getURL(). Разница этих методов состоит в том, что loadVariables() вызывает скрипт, без отображения его в окне браузера, а getURL() открывает свою цель в браузере и передаёт ей переменные.
Итак, в ролике присутствуют два текстовых поля для ввода с именами переменных myText и myValue. По умолчанию там записан текст "поле myText" и "поле myValue". Левая кнопка вызывает PHP скрипт "target.php" и передаёт ему значение переменных. Правая - открывает файл "target2.php" и тоже передаёт ему данные из .swf. Код содержащийся в файлах приводится ниже.
Вот код первой кнопки:
on(release) {
loadVariables("target.php", "_root", "POST");
}
Функция уже описывалась в прошлом уроке, интересующися могут .
Код второй кнопки:
on(release) {
getURL("target2.php", "_blank", "POST");
}
Синтаксис getURL() очень похож на синтаксис loadVariables:
getURL(url [, window [, "variables"]]);
url - единственный обязательный параметр, путь до файла, который загружается в браузер.
window - имя окна или фрейма, в которое загружается файл. Значение "_blank" означает, что содержимое открывается в новом окне.
variables - метод передачи переменных: GET или POST.
Код файла "target.php":
<?
$f = fopen("result", "w");
fwrite($f, $myText);
fclose($f);
?>
Код файла "target2.php":
<?
print $myText;
print "<br>";
print $myValue;
?>
Сценарий target. php сохраняет содержимое переменной myText в файле "result", позволяя тем самым проверить работу loadVariables(). Сценарий target2.php просто выводит значиния myText и myValue в окно браузера. Как видите, переменные напрямую передаются в PHP скрипт и имеют там такие же имена, как и во Flash.
Точно так же можно получать доступ к переменным из любого серверного приложения, имеющего интерфейс CGI. Например, в Perl можно использовать конструкцию param("myText"). В ASP доступ к переменным можно получить через Request.QueryString("myText").
Использованные в уроке файлы можно забрать здесь: (3 k)
Удачи!
Динамическая загрузка внешних .mp3 файлов
Во Flash MX появилась возможность загрузки внешних файлов. Для
этого используется функция loadSound(url, stream) объекта Sound.
Первый параметр, url, указывает путь к файлу. Второй, stream,
является логической (булевой) переменной, определяющий потоковый режим загрузки
звукового файла. Если значение stream равно false, то Flash дождётся
полной загрузки файла, прежде чем его воспроизводить. Если же stream
равен true, то файл может воспроизводиться в потоковом режиме не загрузившись
полностью. Данный режим рекомендуется использовать только на быстрых каналах
связи или при использовании на локальной машине, т.к. потоковое воспроизведение
по нашим каналам Интернет часто приводит к прерыванию воспроизведения длинными
паузами :).
snd1 = new Sound();
snd1.loadSound("track03.mp3", true);
snd2 = new Sound();
snd2.loadSound("http://someserver.com/some_file.mp3", false);
Специально для этого урока я сделал маленький проигрыватель,
который использует подгрузку внешних файлов и позволяет менять громкость и баланс
проигрываемой композиции. Он также позволяет отслеживать сколько процентов запрошенной
композиции загружено. Этот пример можно скачать (,
218k), и поэкспериментировать самому.
Внимание! mp3 файлы не включены в архив с примером, поэтому вам
придётся использовать свои, предварительно изменив пути к ним в параметрах компонента
ComboBox.
Надеюсь, данная статья оказалась вам полезной.
Удачи!
(C). // 2002-2003 // all rights reserved
Динамическое изменение параметров звука
Объект Sound позволяет динамически устанавливать уровень громкости
и баланс (панорамирование) звука. Существуют также функции для получения значения
баланса и громкости.
Для установки громкости звука используется функция setVolume(value).
Параметр value может принимать значения от 0 (минимальный уровень) до
100 (максимальный уровень). По умолчанию уровень громкости равен 100.
Для установки баланса используется функция setPan(value).
Здесь параметр value может принимать значения от -100 (весь звук в левом
канале) до 100 (весь звук в правом канале). Значение 0 (оно стоит по умолчанию)
означает, что звук равномерно распределён между обоими каналами.
globalSnd.setVolume(50); // Половинная
громкость
globalSnd.setPan(70); // Сместить звук по большей части в правый канал
Можно использовать функции getVolume() и getPan()
для получения текущего значения громкости и баланса соответственно.
currentVolume = someSnd.getVolume();
currentPan = someSnd.getPan();
Можно одновременно устанавливать все параметры звука при помощи
функции setTransform(), но мы её в данной статье не рассматриваем.
Можно в цикле вызывать функции setVolume() и setPan(),
плавно изменяя значение параметра, и тем самым создавать эффекты затухающего,
возрастающего и/или перемещающегося звука.
Привязка звука к объектам Sound
Объект Sound позволяет вопроизводить звуки, не втавленные непосредственно в ключевой кадр временной шкалы. Но для этого их надо сначала поместить в библиотеку, а затем экспортировать для использования в ActionScript.
Для помещения звука в библиотеку достаточно выбрать "File -> Import to Library...", и в появившемся окне указать имя звукового файла.
Теперь, когда файл уже находится в библиотеке, выделяем его,
кликаем правой кнопкой мыши на названии звука, и в появившемся контекстном меню выбираем "Linkage...". Должно появится подобное окошко:
В поле Identifier мы вводим идентификатор (имя) звукового ресурса. Можно включить галочку "Export in first frame", тогда звук будет загружен уже в первом кадре мульта, однако, такой способ неприменим при хоть сколько-нибудь больших звуках, т.к. до начала загрузки 1-го кадра (даже прелоадера не видно!) мы видим пустое место, появляется ощущение "зависшего клипа". Поэтому рекомендуется выключать эту галочку, а в кадре где нужна загрузка звука, помещать его на временную шкалу с параметрами Sync Stop. Тогда звук не будет загружен до этого кадра и можно спокойно использовать прелоадер.
Далее, чтобы привязать звуковой ресурс к звуковому объекту, нужно
воспользоваться функцией attachSound(idName), в которой параметр idName
указывает идентификатор звукового ресурса:
mySound = new Sound();
mySound.attachSound("tada");
После этого наш звуковой объект готов к манипуляциям.
Программное управление звуком
Рубен Сардарян & Андрей Жебраков,
В этой статье мы познакомим вас с программным управлением звуком при помощи языка AcrionScript. Flash иногда очень неадекватно воспринимает звуки, размещённые прямо во временной шкале, поэтому при создании больших мультов без программного управления не обойтись.
Мы рассмотрим:
создание звуковых объектов (объектов типа Sound);
привязку звуков к таким объектам;
управление воспроизведением звука;
динамическое изменение параметров звучания (громкость и панорамирование);
загрузку в объект Sound внешних .mp3 файлов.
Объект Sound появился в 5-й версии Flash, поэтому все приёмы, рассмотренные в статье, кроме загрузки внешних .mp3 файлов, могут быть использованы и в 5-й версии.
Создание звуковых объектов
Начнём. Вы уже наверное догадались, чтобы производить какие-либо операции со звуком, нужно создать объект типа Sound. Сделать это очень просто. Существует стандартная конструкция
soundObject = new Sound(target);
где soundObject - это имя создаваемого звукового объекта, а target - необязательный параметр, указывающий объект типа MovieClip, или уровень. Если мы хотим, чтобы наш звуковой объект работал только в одном MovieClip-е или на одном уровне, то мы должны его создавать с указанием данного параметра:
movieSound = new Sound("SomeClip");
movieSound = new Sound("_root.teddy.mouth");
levelSound = new Sound("_level1");
Если же планируется использовать объект в любом месте вашей флэшки, то он создаётся без параметров:
globalSound = new Sound();
Воспроизведение и остановка звуков
Основными действиями, выполняемыми со звуковыми объектами являются,
конечно же, воспроизведение и остановка воспроизведения.
Для того, чтобы воспроизвести звук, используется функция start(offset,
loops) объекта Sound. Параметр offset, указывает смещение
в секундах, от начала звукового фрагмента, а loops - количество повторений
проигрываемого фрагмента.
Например, если мы хотим проиграть вторую половину 20-тисекундного
фрагмента 3 раза, мы запишем:
someSoundObject.play(10, 3);
Звук начнёт проигрываться с 10-й секунды.
Оба параметра функции start() являются необязательными.
По умолчанию звук проигрывается с самого начала один раз:
someSoundObject.play();
Можно повторить звуковой фрагмент несколько раз с начала, тогда
мы указываем нулевое смещение:
someSoundObject.play(0, 5);
Чтобы остановить проигрывание, используется функция stop(idName).
Вызванная без параметров, функция останавливает все звуки. Указав параметр idName,
обозначающий идентификатор звука, можно остановить только один специфический
звук:
globalSnd.stop();
someSnd.stop("tada");
Цель данной работы.
Оценить возможности Flash для создании клиентов Web сервисов.
Flash client.
Для оценки возможностей Flash 8 написан простой SOAP (76Кб).
Приложение формирует и передает запросы Web сервису, принимает от него данные и отображает их. С точки зрения пользователя Flash клиент и Web Service обеспечивают функциональность:
Последовательный просмотр всех записей таблицы базы данных; Чтение произвольной записи таблицы базы данных; Обновление произвольной записи; Вставку новой записи.
Исходный тест Flash клиента в виде RAR файла Вы можете взять .
Eсли Web сервис создан и размещен, обращение к нему может исходить от любого SOAP клиента, а не только от описываемого здесь. Более того, тип технологии, применяемой для создания клиента или сервиса, и язык реализации могут быть выбраны произвольно, но выбранная технология должна поддерживать SOAP/WSDL.
Internet как среда разработки.
Web сервис, созданный и размещенный в Internet по некоторому URL определяет:
имена методов доступа к данным; имена и типы входных данных; имена и типы выходных данных; типы сообщений; кодировки; пространства имен
и некоторые другие параметры.
Другими словами, Web сервис формализовано описывает данные и предоставляет открытые методы доступа к ним.
Использование приложения.
Работать с Web клиентом просто:
Листание записей выполняется кнопками "Prior" и "Next". Для чтения произвольной записи установите ее номер в поле "Номер записи" и нажмите кнопку "Select" . Для обновления записи заполните все поля формы нужными данными, включая номер записи и нажмите кнопку "Update". Вставка записи выполняется после ввода данных в поля формы клиента и нажатия кнопки "Insert". Номер записи вводить не обязательно, программа сама найдет последнюю запись в таблице базы данных.
P.S. Используемая здесь версия NUSOAP не работает с Unicode, принятой по умолчанию во Flash, однако, после незначительной доработки эта проблема решается. Для заинтересованных читателей пусть это будет домашним заданием.
Всего хорошего.
Описание реализации.
Никаких особых требований к набору инструментов: PHP, NUSOAP, mySQL нет.
Версия PHP может быть 4.0.6 и выше; mySQL - любая стабильно работающая версия; Пакет NUSOAP достаточно скопировать в рабочую директорию на сервере.
Исходный текст Web сервиса прозрачен и содержит:
Последовательное определение методов сервиса (строки с 7 по 82):
selectSales; updatesales; insertSales Регистрацию обьявленных методов (строки с 83 по 114); Реализацию обьявленных методов в виде одноименных PHP функций (строки с 119 по 200).
Web клиент реализован в среде Macromedia Flash 8 c использованием компонентов:
WebServiceConnector; TextInput; Button
и некоторых других.
Для просмотра Web сервиса в Internel Flash имеет специальное окно, которое может быть открыто, например, так:
Windows --> Other Panels --> Web Services.
В окне Define Web Service следует ввести URI сервиса, для нашего случая это:
Flash обратится по заданному адресу, считает и отобразит информацию о сервисе. Состав предоставляемой Flash информации о сервисе идиентичен тому, что можно увидеть в браузере, обратившись по URL, но Flash отобразит только те данные, которые необходимы для реализации клиента:
имена методов доступа; входные и выходные параметры.
Отмечу так-же, что аналогичную функцию имеет и компонент WebServiceConnector, настройка которого может быть выполнена как визуальными средствами Flash так и из ActionScript 2.0
Web клиент очень прост, он содержит несколько десятков строк текста, существенная часть которого посвящена анализу возмоможных ошибок.
Основой Web клиента служат три компонента WebServiceConnect (по числу методов сервиса). Правда, этот компонент мог бы быть и один, но в этом случае его пришлость бы перенастраивать при смене вызываемого метода, что, наверное, не очень рационально. Большая часть настройки клиента выполняется визуальными средсвами среды Flash, что весьма удобно.
На стороне сервера, средствами языка
На стороне сервера, средствами языка PHP и пакета создан Web сервис реализующий RPC (Remoute Procedure Calls) к СУБД mySQL. Web сервис выполняет на стороне сервера SQL операторы:
Select; Update; Insert,
которые реализованы в виде SOAP/PHP методов:
selectSales ($request); updateSales ($request); insertSales ($request)
где переменная $request содержит параметры запроса, принятые от клиента.
Для демонстрации работы с Web сервисом, предварительно, в базе данных создана небольшая таблица:
CREATE TABLE DBSERVICE ( ID INT NOT NULL PRIMARY KEY, SALES VARCHAR(100), DESCRIPT VARCHAR(150), PRICE INT );
Данный можно увидеть в Internet, используя обычный браузер. Открыв ссылку WSDL, Вы можете посмотреть описание Web сервиса средствами XML. На этой же странице, открыв соответстующие ссылки, можно ознакомиться с описанием RPC методов сервиса.
Исходный тест Web сервиса в виде RAR файла Вы пожете взять отсюда.
Web Service в Macromedia Flash.
Мacromedia Flash 7,8 версий содержат набор классов для создания клиентов Web сервисов:
WebServiceConnector; DataSet; DataGrid; RDBMSResolver; DataHolder
и некоторые другие.
Имеется так-же богатый набор классов для работы с данными, представленными в виде XML файлов, но это тема для отдельной статьи.
Для реализации Web сервиса на стороне сервера может быть использована любая технология поддерживающая SOAP/WSDL, например:
J2EE; .NET; PHP.