Умные колеса.

Сейчас я работаю над одним весьма интересным проектом — это будет всего лишь интерактивная  флеш-шапка, но она будет полна анимации с алогичным волшебством: кони-рыбы, люди-фрукты и так далее ))

В процессе работы, я уверен, будет накапливатся масса интересных и полезных мелочей, коими я конечно же поспешу поделиться. Сейчас таких мелочей есть две: программный растеризатор сложного вектора. Вектора будет много, и он как пить дать убъет процессор; пришлось выдумывать хитрые вещи. Но об этом позже, сначала я должен убедиться в эффективности выбранного решения ))

Сегодня же я расскажу о колесах. Будет скрипт )) Несложный, но он даст нам чудное колесо, и оно будет вращаться в точности в соответсвии с тем, как далеко продвигается то, к чему это колесо крепится ))) Итак, под кат, там есть небольшой мультик ))

 

Оставим пока лошадей ) (Я намерен, кстати выложить видео запись процесса работы над этой анимацией - так сказать серия Animator at work)
Понаблюдайте за каретой. Колеса, как видите вращаются весьма правильно )) Они следуют всем законам земным и божеским. Вы думаете, я сидел с линейкой и мерял кадр за кадром - каково смещение? Нет. Я вспомнил, что в школе я неплохо разбирался в геометрии ))
Итак, каждое колесо запаковано в мувиКлип, сама карета с ее вложенной анимацией также упакавана в мувиклип.
Каждый клип колеса имеет точку регистрации ровно в его центре, чтобы колесо вращалось вокруг своей оси.
Из геометрии мы знаем формулу длины окружности L = 2PI*R, где R - радиус.
В правильном колесе радиус - это половина ширины клипа.
Рассуждаем логически: когда наше колесо повернется на 360 градусов, оно должно сместиться на расстояние L. Супер! Значит, если колесо повернется на один градус, расстояние будет равно L/360! Запомним это число,  и повесим на колесо событие onEnterFrame в котором смотрим — на сколько сместилась карета (моушвтины тоже считаются!), и считаем угол поворота - дистанцию делим на L/360. Вуаля.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
init(wheel1); // обучаем первое колесо
init(wheel2); // обучаем второе колесо
 
function init(mc:MovieClip):Void
{
	mc.radius = mc._width/2; // собрали радиус
	mc.baseX = mc._parent._x; // запомнили начальную позицию кареты
	// l = 2PI*R - ах, геометрия...
 
	mc.degreeLength  = (2*3.1415926*mc.radius)/360; // смещение при повороте на один градус
	mc.onEnterFrame = function():Void
	{
		var distance:Number = this.baseX - this._parent._x; // на сколько сместилась карета?
		this._rotation = -distance/this.degreeLength; // поворачиваем колесо
	}
}

3 комментария апреля 24, 2009

ScrollRect. Дубль 2.

Как показывает практика, многие избегают использования scrollRect (я писал об этой чудесной возможности в одной из статей) по той простой причине, что не понимают, как работать с координатами. Действительно, после использования маски с клипом, где каждый участник процесса имеет свои понятные иксы и игреки, переход на scrollRect бывает труден.

Сегодня я еще раз попробую обратить вас в свою веру )).


Основная, бесспорная причина, по которой стоит использовать scrollRect вместо прямоугольных масок - производительность.
10 масок убьют CPU намного быстрее, чем 10 scrollRect-ов. Даже в хелпе сказано, что при использовании scrollRect используется попиксельное копирование участка клипа, а не полная его перерисовка.
Вторая причина - (вытекает из первой) можно маскировать НЕ внедренные шрифты, которые, как мы знаем, пропадают при маскировании обычным способом.

Также для меня лично плюсом является то, что мне не надо плодить новые клипы, только для того чтобы замаскировать контент.

Теперь о том, как это работает.

В процессе участвует MovieClip и объект Rectangle.
Когда к клипу применяется scrollRect - то на экран выводится только тот участок клипа, который КАК бы лежит под заданным прямоугольником. Координаты прямоугольника при этом задаются в системе координат маскируемого клипа - то есть от его точки регистрации. Хотим увидеть квадрат 20х20 левого верхнего угла клипа - задаем
mc.scrollRect = new Rectangle(0,0,20,20);

Заметьте, если вы начинаете сдвигать координату прямоугольника - координаты клипа остаются неизменными, хотя визуально кажется, будто он движется под маской. Еще раз напомню - происходит попиксельное копирование участка клипа.


Пример 1. Левый клип замаскирован scrollRect-ом. Перемещая рамку над правым - меняем x и y scrollRect-а.

 


Пример 2. Прокрутка большого клипа в окне заданного размера.
Координаты Rectangle изменяются в зависимости от координат мыши.

 


Пример 3. Комбинация перемещения клипа + перемещение scrollRect дает забавный эффект.
Попробуйте перевесить картину )

 


Пример 4. Покрутите ручки сами.Некоторые свойства Rectangle:

 

x, y - координата левого верхнего угла прямоугольника;
width, heigth - ширина, высота прямоугольника;
left - координата левой стороны. Изменяя это свойство мы меняем сразу и width, и x;
right -координата правой стороны. Изменяя это свойство мы изменяем также и width;
top - координата верхней стороны. Изменяя это свойство мы меняем сразу и height, и y;
bottom -координата нижней стороны. Изменяя это свойство мы изменяем также и height;Покрутив ручки MovieClip вы увидите разницу между перемещением клипа и перемещением прямоугольника scrollRect.
Интересный факт. Изменяя width прямоугольника мы меняем _width клипа (это логично). Но если мы при scrollRect начнем изменять непосредственно _width (_height) клипа - то клип начнет искажаться, тогда как scrollRect останется при своем _width.
Крутите ручки - экспериментируйте.

4 комментария апреля 24, 2008

Разбираемся с SWFAddress

В сети море полезных фреймворков, классов и решений различных задач.
Однако очень многие из них имеют существенный недостаток - УЖАСНАЯ, если вообще присутствующая документация.

Недавно я прикоснулся к магии SWFAddress, библиотеке AS+JS, решающей проблему deep linking для FLASH и AJAX.
Для таких как я (гуманитариев и не-программистов) предлагаю свой опыт по освоению СВФАдреса.
Нет. Документацию на русский язык я переводить не буду. Не вижу в этом смысла. Документация более чем минималистическая. С тем же успехом ее можно было бы вообще не писать. В прочем + от нее все же есть - сводная таблица всех доступных в классе методов.

Первое что следует сделать - это скачать библиотеку. Настоятельно рекомендую качать 7-мегабайтовый архив с примерами и документацией. Потому что, как выяснилось в процессе, если бы я ограничился скачиванием только классов — меня бы постигла неудача, и я бы так и не понял в чем дело. А непоняток-ошибок на пути встретилось некоторое количество )

Первая ошибка. Исторически сложилось так, что я работал над сайтом, к которому намеревался прикрутить SWFAddress на завершающем этапе. Собираетесь использовать дип линкинг - сразу работайте с SWFAddress. Дело в том, что любое изменение адресной строки браузера (А это именно то, зачем нам вообще нужен дип линкинг) вызывает событие SWFAddress.onChange. То есть фактически и переключение разделов из флеш сайта (конечно если оно должно вести к изменению в адресной строке) , и переключение разделов извне (навигация по кнопкам ВПЕРЕД НАЗАД ,навигация по якорям на хтмл-странице и т.д.) вызывает это событие. В сущности на нем как раз и будет строиться обработка события переключения между разделами.
Ошибка вторая. Я доверился заявлению Flash CS3 Support. Фактически же, если публиковать ролик на странице с помощью AC_RunActiveContent.js, которое генерируется Flash IDE - дип линкинг не работает. Изменения в адресной строке - да, но ролик не реагирует на навигацию из браузера. Я дошел до этого знания случайно. Потеряв веру в свой мозг, я просто взял рабочий пример, и заменил в нем флешку на свою - и все заработало. Путем исключений я нашел камень преткновения. Каким то образом AC_RunActiveContent.js из примера отличается от того, что генерируется FLASH CS3 IDE. Так что пользуйтесь скриптом из примеров. Что касается работы с SWFObject и UFO - не проверял. У вас есть отличная возможность сделать это за меня, а потом отписаться здесь, если пожелаете.

Теперь о некоторых тонкостях и внутренностях. В архиве есть коды для всех трех версий AS. Мои опыты ставились на AS2.0

1. Класс написан как TopLevel-класс, или для тех кто не понимает этого словосочетания, - он не создает экземпляров. Пример такого класса -Math, все функции в нем вызываются подобным образом: Math.sin(), Math.round() и т.д. То же справедливо и для SWFAddress.

2. Адресная строка.
Для решения задачи дип линкинга, к существующему URL добавляется якорь # за которым следует строка, которую разработчик волен генерить сам, по своим правилам, и сам же по своим правилам ее и разбирает. Есть два режима. setStrict(true) - в конце адреса жестко добавляется слеш (/) и setStrict(false) - никаких слешей без ведома разрабочика.

3. Основные полезные методы.
В классе присутствует набор методов для разбора строки. Весьма удобно.
К примеру в адресной строке имеем

http://flashsite.com/#news?page=&img=2

SWFAddress.getValue():String - вернет значение строки аккурат после # со всеми Вашими изысками (парами имя=значение)

news?page=1&img=2

SWFAddress.getPath():String - вернет значение строки аккурат после # без дополнительных параметров
news

SWFAddress.getQueryString():Array - вернет строку с дополнительными параметрами

page=1&img=2

SWFAddress.getParameterNames():Array - вернет массив с именами дополнительных переменных
page,img

SWFAddress.getParameter(value:String):String - вернет значение дополнительного параметра указанного в value
getParameter(”page”) // 1;
getParameter(”img”) // 2;

Для того чтобы изменить адресную строку из FLASH существует метод setValue(value:String) - помните, что вызов этого метода автоматически приведет к вызову события onChange, так что фактически переключение между разделами сводится к замене значения адресной строки и последующей обработке события.

Остальные методы описывать не стану, они весьма просты и даже данных документации хватит для их освоения.

4. События.
Я уже говорил о событии onChange. Должен отметить, что событие это вызывается сразу же, при первом же упоминании класса, равно как и событие onInit. Большого смысла в событии onInit я не уловил. В самом начале оно вызывается и тут же за ним вызывается onChange. Возможно есть смысл для более четкой структуризации, и отделении инит-процедур от собственно обработки переключений между разделами.

Более подробно поговрим о событии onChange, хотя в случае с onInit все работает абсолютно так же, за исключением значения cвойств SWFAddressEvent: path=null; value=null; type=init;

События доступны в двух ипостасях:

SWFAddress.onChange = function():Void
{
    trace("SWFAddress.onChange");
}

В данном случае мы просто определяем статичную функцию onChange.

Второй вариант - подписать любой свой объект на событие. Во многом это удобнее, чем описывать вложенные функции с обработчиком события.
К примеру мне удобно подписать экземпляр класса, который напрямую работает с SWFAddress. Для этого я сначала создаю функцию обработчик:

public function onChange():Void \
{
   trace("Class's onChange");
}

И далее подписывась на событие с помощью метода класса SWFAddress - addEventListener(type:String,listener:Function);
Поскольку в этом учавствует стандартный mx.utils.EventDispatcher, нужно подписаться так, чтобы наша функция onChange знала кто в доме хозяин - то есть надо жестко определить this. Делается это при помощи mx.utils.Delegate.create().
Итак подписка на событие для нашего экземпляра будет выглядеть так

SWFAddress.addEventListener("change",Delegate.create(this,onChange));

Теперь мы можем из тела функции onChange обращаться ко всем свойствам и методам нашего экземпляра. Ура.
Продвинемся дальше. В том случае, если мы подписываемся на событие, в качестве параметра в наш обработчик приходит экземпляр SWFAddressEvent, который несет в себе ценную информацию :)
Модифицируем наш обработчик.

public function onChange(evt:SWFAddressEvent):Void
{
  //вернет путь после # из адресной строки БЕЗ параметров
  trace("path:"+evt.path);
  //вернет  путь после # из адресной строки С параметрами
  trace("value:"+evt.value);
}

Также событие несет информацию о своем типе (type=”change” или “init”), target (это всегда отсылка на SWFAddress) а также массив parameters (”ассоциативный”) с параметрами из queryString. Если в адресной строке есть news?param=value, то значение param можно получить так : SWFAddressEvent.parameters.param

Какие замечены баги.

1. Самый неприятный. В опере любое переключение между страницами ИЗ браузера (навигация вперед назад, якоря) вызывает полную перезагрузку страницы. Не очень то красиво, особенно если это флеш сайт с какими то особенными переходами между страницами. К счастью внутренние флешовые переходы проходят как обычно.

2.Если вручную вставить адрес в браузерной строке в FireFox - адресная строка перестает изменяться, когда переключаешься между разделами. Вроде как адреса заносятся в history, навигация вперед.назад работает, но это не отображается в адресной строке. В принципе - я лично замечал вообще странное поведение адресной строки в Фоксе, и без дип линкинга, например иногда в ней просто невозможно перенабрать адрес.

Работоспособность проверена на:

  • Mozzilla FireFox 2.0.0.12
  • Opera 9.10
  • IE 6.0
  • Safari (win) 3.0.3

В завершении могу только дать ссылку на первый свой опыт с SWFAddress, где вы можете потестировать работоспособность библиотеки в разных браузерах. Будет полезно, если здесь вы запостите свои баг репорты, ну или зададите вопросы о том, что осталось непонятным. Цель этого топика - сделать эту бесспорно полезную опцию более доступной всем категориям разработчиков )) Поэтому -включайтесь )

http://kvadra.net/samples/goodpeople/_flash/#chillout/two?pgid=2t&imgid=36

23 комментария февраля 26, 2008

_quality = LOW. Производительность против дизайна.

Самое мое любимое качество - LOW. Очень быстро, но смертельно для вектора.

В некоторых случаях, можно с легкостью пользоваться этим чудным режимом, оставляя за собой право на гладкие линии))
Рецепт прост. Если мы имеем дело со статичным вектором, то мы можем сделать с него слепок в битмапДату при режиме _quality=”HIGH”, а затем переключиться на LOW и вывести уже не вектор, а битмапДату. Просто до безобразия.

Более того, замечено, что текст с типом рендеринга ADVANCED - не подвластен козням качества LOW.
ПРи должной сноровке, несложно написать класс, который переводил бы нужный вектор в битмап дату. МОжно даже продумать подобные фокус с анимированными векторами (массив фрейм_в_битмап) Конечно в данном случае больше нагрузки идет на ОЗУ, но в основом именно нагрузка на CPU дает притормаживание.

Пример:

Код фокуса:

import flash.display.BitmapData;
_quality="BEST";
var bmp:BitmapData = new BitmapData(oval._width,oval._height,true,0);
bmp.draw(oval);
_quality = "LOW";
this.createEmptyMovieClip("mc",1);
mc._x = oval._width*2;
mc._y = oval._y;
mc.attachBitmap(bmp,1);

Ссылка по теме: http://www.bytearray.org/?p=117

2 комментария февраля 6, 2008

BitmapData + mask = мертвый браузер.

Очередной баг браузерного плагина и как с ним бороться )
Некоторые нехитрые действия для создания битмап-картинки, маскированной фигурным контуром вырубили напрочь браузер.

Коротко об алгоритме:

1.В библиотеке есть клип для маски (дабы прямоугольный кусок растра оформить в “фигурный” контур).
2. Там же, в библотеке, несколько растров с linkageID.
3. Создается временный клип, аттачится маска, временный клип маскируется.
4. Создается временная битмапДата, аттачится во временный клип (Под маско получается картинка “в рамке”)
5. Создаем еще одну битмап дату, делаем слепок с маскированного клипа.
6. Заносим полученную битмапу в массив, для дальнейшего использования.
7. Убираем временные клипы, диспоузим временный битмап.

При этих нехитрых действиях, дебаг, стендалон - работаю как и предполагается.
Браузер (любой) вылетает, сообщив о б ошибке.

Опытным путем, установил, что проблема в маске. И это же навело меня на решение.
Перед тем , как задать маску, нужно и маскируемому, и маскиующему клипам задать свойство cacheAsBitmap = true. И хотя особоенно логичного объяснения я этому не вижу - плагин принимает такой вариант.

Комментариев нет февраля 5, 2008

Новое в классе FileReference

Недавно в блоге GarbageCollector появилась статья о новых событиях класса NetStream.

Я в свою очередь ) недавно обнаружил некоторые нововведения и в классе FileReference, впервые появившемся в Macromedia Flash 8.


Когда я впервые стал смотреть на возможности этого класса, меня разочаровало то, что на сервер вместе с загружаемым файлом можно отправить данные только GET-методом. (Классический урл-запрос с парами переменная=значение). Также нельзя было получить от сервера никаких данных, по завершении загрузки.

Недавно вновь обратился к этому классу, но уже в Adobe Flash CS3 - и, о чудо! Новые свойства и события, как раз на эту тему.

Новое свойство postData:String. - Как видно из названия (опыты подтверждают) - POST параметры, которые отправляются на сервер вместе с загружаемым файлом.
Польза? Как минимум отправка сложной формы, включающей некий файл (картинку, звук, архив) на сервер. Данные формируются строкой из все тех же пар переменная=значение.

Новое событие:

1
onUploadCompleteData  =  function (fileRef:FileReference, data:String) {};

Как видно из конструкции - по завершению аплоада, если сервер отдает какие то данные в ответ, то мы можем их получить в переменной data:String. Очень удобно хотя бы для того, чтобы сообщить пользователю, что его драгоценные данные отправлены и приняты.

Вот такие бонусы. Добавлю только, что все это работает в плеере 9.0.r28 и выше.

2 комментария января 29, 2008

Первая помощь флешовому HTML Render-у

Форматирование текста с помощью HTML во флеш,что ни говори - гораздо удобнее, чем форматирование с TextFormat, практически в любой ситуации.

Если Вас сильно огорчает сильно урезанный набор тегов, который HTML парсер флеша понимает - читайте дальше.

Итак, что мы имеем в распоряжении:
P, B, I, U, A, BR, LI, I, IMG, SPAN, TEXTFORMAT, FONT.

Как видим - ни хедеров, ни STRONG, который рекомендуется вместо B. Заставить флеш-хтмл-парсер понимать h1, h2…. strong, em не прибегая к хакам - елементарно.
У нас же есть законный TextField.StyleSheet. А с помощью css можно форматировать любой XML документ. Грамотный HTML - это тот же XML, поэтому нам достаточно описать в каком виде мы хотим видеть наши заголовки, описать strong, em - и все что нам нужно в таблице стилей.

Маленькая странность - любой неподдерживаемый тег, описанный в таблице стилей - разрывает строку. В случае заголовоков это даже полезно, а вот strong, разрывающий пасть строке - это экзотика К счастью флеш поддерживает свойство display. Так что display: inline - поставит все на свои места.

Дружите с цсс+хтмл. Великий поклон разработчикам за то, что они избавили меня лично от необходимости повсеместно пользоваться текстФорматом. Даже за такой куцый парсер хтмл.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// стиль
var style_string:String = "h1 {font-size: 20; font-weight: bold} ";
style_string += "strong {font-weight: bold; display: inline;}";
var style_css:TextField.StyleSheet = new TextField.StyleSheet();
style_css.parseCSS(style_string);
// текст
var html_text:String = "
</code>
<h1>Нeader</h1>
";
html_text +="<strong> Very strong line </strong>";
html_text +="usual text";
 
// текстовое поле
var tf:TextField = this.createTextField("tf",0,10,10,400,200);
tf.multiline = true;
tf.wordWrap = true;
tf.border = true;
tf.html = true;
tf.condenseWhite = true;
tf.styleSheet = style_css;
tf.htmlText = html_text;

Ну, а если требуется что-то более продвинутое - посмотрите на компонент HTMLRenderer Андрея Горбатова: http://gorbatov.blogspot.com/…/htmlrenderer

Один комментарий января 28, 2008

ScrollRect vs setMask

На заметку.

Если нужно применить к клипу прямоугольную маску, вместо MovieClip.setMask(mc:MovieClip) лучше воспользоваться свойством scrollRect (доступно от 8-й версии и выше).

Плюс в производительности на лицо. Более того - под такой “маской” не пропадают системные и не-внедренные шрифты.

Использование предельно просто:

1
2
3
import flash.geom.Rectangle;
var maskRect:Rectangle = new Rectangle(x,y,width,height);
my_mc.scrollRect = maskRect;

С такой “маской” удобно делать также и скроллеры (собственно название выдает).
Достаточно поменять значение x, y для Rectangle, и визуально мы видим смещение контента мувиКлипа.

7 комментариев декабря 9, 2007

Защита от неплательщиков.

На волнах фриланса частенько попадаются жадные купцы.
Денежку пожалеют, и разработчику не заплатят.
Особенно озадачивает разработчика сей факт, когда он, наивный, отдал результат работы в жадные купцовы руки.

Лучшая защита - работать только с теми, кто у вас в local-trust )))

Но вот еще небольшая подмога. Класс Permission.
Для работы с ним, конечно понадобиться свой родной домен, на который вы сможете положить скромный crossdomain.xml. В нем укажите доступ для того домена, на котором будет лежать результат вашей работы. Ну а если не знаете где именно, будет лежать разрешайте доступ всем. Хуже не будет.

Далее. Кладем у себя мальнький текстовый файл, в котором будут записаны две переменных allow=1 и message=ЗАПЛАТИ ДЕНЕГ!!!

Пока allow=1 флешка будет работать как положено.
Но как только вам покажется, что денег больше не видать - меняйте allow=0.
Теперь все будут поверх флешки периодически читать ваш душещипательный message.

Конечно, по завершении работ, в случае благополучной оплаты - лучше убрать эту мышеловку из кода, и отправить финальный , стерильный вариант.

Использование:

Просто заводим новый экземпляр Permission и передаем в конструкторе путь к текстовому файлу.

var my_permission:Permission = new Permission("my_domain.net/my_permission.txt");

Код классa: ru.decafe.utils.Permission

/**
* class ru.decafe.utils.Permission
* @author Mikhail Ivanchuk
* @version 0.1
*/
import ru.decafe.utils.Cache;
 
class ru.decafe.utils.Permission {
	private var  theURL:String = "";
	private var accessor:LoadVars;
	private var blinker:Number;
	private var alert_mc:MovieClip;
	private var message:String = "";
 
	public function Permission(url:String) {
		theURL = url;
		accessor = new LoadVars();
	}
	public function loadAccess():Void {
		var refer:Permission = this;
		var _key:String = theURL.indexOf("?")==-1?"?":"&amp;";
		accessor.load(theURL+Cache.disable(_key+"nocache="));
		accessor.onLoad = function (success:Boolean) {
			var mode:String = "demo";
			if (success &amp;&amp; this.allow == "1") {
				mode = "allow";
			}
			trace("mode: "+mode+"\n"+this.message);
			if (mode=="demo") {
				refer.message = this.message;
				refer.blinker = setInterval(refer,"alert",10000);
			}
		}
	}
	private function alert():Void {
		alert_mc = _level0.createEmptyMovieClip("alrt",_level0.getNextHighestDepth());
		var txt:TextField = alert_mc.createTextField("txt",0,0,0,150,60);
		txt.background = true;
 
		txt.multiline = true;
		txt.wordWrap = true;
		txt.backgroundColor = 0xDEDEDE;
		txt.border = true;
		txt.borderColor = 0;
		txt.html = true;
		txt.condenseWhite = true;
		txt.htmlText = "
 
<span style="font-family: Arial;">"+message+"
 
";
		alert_mc.counter = 100;
		alert_mc.onEnterFrame = function () {
			this.counter--;
			if (this.counter&lt;0) this.removeMovieClip();
		}
	}
}
</span>

+ Cache.as, который необходим для работы класса Permission: ru.decafe.utils.Cache

2 комментария декабря 6, 2007

Кеширование данных, и как с ним бороться.

Мало мальски серьезное приложение обязательно грузит в себя некие внешние данные.
В случае работы на просторах сети эти данные попадают в кеш.
Иногда эта особенность сильно мешает. К примеру мы делаем галерею которая постоянно пополняется. Адреса изображений заносятся в XML файл, который мы и грузим первым делом в нашу галерею. Единожды загрузившись - этот файл надолго попадает в кеш и наша галерея ничего и знать не знает об обновлениях.

Сценарий 2:
Мы пишем клиентскую часть игры для он-лайн казино. Все процессы связанные с логикой игры происходят на жутко засекреченном сервере, наш клиент только отображает красиво все эти процессы. В определенный момент отправляет серверу данные о действиях игрока, в ответ получая XML с состоянием дел: Баланс игрока, комбинацию карт (или символов, если это слот-машина) ну и много всего разного.

Несмотря на то что мы не запрашиваем реально существующий XML, все равно результат заносится в кеш, и по следующему подобному запросу мы получим старые данные. В итоге - игрок выиграл 100000, но не знает, что это случилось.

Самый простой способ это приклеить Math.random() к запросу. Тогда браузер воспримет такой запрос как абсолютно новый и радостно вернет нам нужные данные в самом свежем виде. Но, полагаться на Math.random() всегда я бы не стал.

И я не стал. Как раз когда мне довелось писать кучу игр для казино, возник вопрос о железной защите от кеша. В итоге родился шизофренический метод, который позже я перелопатил в класс с одним единственным статичным методом. Базируется он на самой непостоянной субстанции - времени.

Однако на этом мы успокаиваться не будем. Иногда нам нужно чтобы свежие данные приходили не так часто. Допустим у меня есть сайт-портфолио, состоящий из нескольких html-страниц. На каждой имеется флеш-галерея работ. Если я буду отключать кеш для каждой загрузки - то мой посетитель будет упорно грузить свежие данные при каждом возвращении на страницу. Выход - обновляться скажем только каждый час, или день.

В общем хватит слов. Класс элементарный - и все будет ясно из его кода.

Метод один Cache.disable(key:String, level:Number);
key - это строка, которую нужно приклеить к запросу. Или банальный “?” (”&” если в запросе уже есть пары имя=значение), или что-то сокровенное вроде “?nocache=”.
level - уровень защиты от кеша. Передаем одну из констант:
Cache.MONTH, Cache.DAY, Cache.HOUR, Cache.MINUTE, Cache.FULL

код класса:

/**
* class Cache
* @author Mikhail Ivanchuk
* @version 0.1
*/
class ru.decafe.utils.Cache {
 
	public static var MONTH:Number = 1;
	public static var DAY:Number = 2;
	public static var HOUR:Number = 3;
	public static var MINUTE:Number = 4;
	public static var FULL:Number = 5;
	public static function disable(key:String, level:Number):String {
		if (level == undefined) level = Cache.FULL;
		var browser:Boolean = (_level0._url.substr(0,4) == "http");
		// timestamp
		var timestamp:Date = new Date();
		var timestampY:Number = timestamp.getYear();
		var timestampMN:Number = timestamp.getMonth();
		var timestampD:Number = timestamp.getDate();
		var timestampH:Number = timestamp.getHours();
		var timestampM:Number = timestamp.getMinutes();
		var timestampS:Number = timestamp.getSeconds();
		var timestampMS:Number = timestamp.getMilliseconds();
		var timestampMT:Number = Date.UTC(timestampY,timestampMN,timestampD,timestampH,timestampM,timestampS,timestampMS);
		//date string
		var dateString:String = timestampY.toString(16) +timestampMN.toString(16);
		if (level <= Cache.MONTH) return (browser?(key+dateString):"");
		dateString += timestampD.toString(16);
		if (level <= Cache.DAY) return (browser?(key+dateString):"");
		dateString += timestampH.toString(16);
		if (level <= Cache.HOUR) return (browser?(key+dateString):"");
		dateString += timestampM.toString(16);
		if (level <= Cache.MINUTE) return (browser?(key+dateString):"");
		dateString += timestampS.toString(16)+timestampMS.toString(16)+timestampMT.toString(16);
		// random
		var addition:String = (Math.floor(Math.random()*1024)).toString(16);
		return (browser?(key+dateString+addition):"");
	}
}

Один комментарий декабря 6, 2007


МЕТА

метки

Календарь

Март 2010
Пн Вт Ср Чт Пт Сб Вс
« Фев    
1234567
891011121314
15161718192021
22232425262728
293031  

Архив

Ссылки

Радио