Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Мастерство Flash. Профессиональные техники программирования Нити во Флеше. Класс и описание.


Информационный Канал Subscribe.Ru


Здравствуйте, читающие меня флешеры и флешерки ;-), поздравляю всех вас с Новым, 2004 Годом.

Несказанно рад тому, что моя рассылка растет, как на дрожжах и поэтому вот вам еще один, предпраздничный выпуск.

Сегодня я расскажу вам про нити в Флеше. Скажете, в Флеше нет нитей и вы не знаете, что это такое? Верно, их не было, но теперь будут.

На эту идею меня надолкнул Джон Потапенко. Но его конвеер выполняет несколько другие функции, поэтому я написал свой класс.

Итак, что же этот класс делает. Для начала кратко расскажу о нитях в обычных языках программирования.

Нити - это участки кода, которые выполняются независимо от основной программы и параллельно ей. У нитей есть одно приятное свойство – семафоры. Семафоры позволяют приостанавливать и вновь запускать работу нитей. К чему это приложимо? Например, если вам надо сделать меню, каждый пункт которого выезжает только после того, как показался предыдущий. Для этого к каждому пункту меню добавляем нить с семафором, который запускает ее по по окончанию работы предыдущей нити.

Мой класс нити работает немного иным способом, а именно: создается менеджер нити, который обрабатывает команды нити одну за другой. Командами могут быть вызов функции, установка или ожидание семафора, переход на другой кадр и т.д.

Обратимся же к свойствам и функциям класса Thread:

Свойства:

Название тип Описание
autoStart boolean Нить начинает отрабатываться сразу же, как только в нее добавляются команды.

Методы и функции:

Название Параметры Описание
init owner Метод вызывается при инициализации нити, как объекта. Параметр owner указывает на контекст нити (мувиклип, в котором нить будет выполняться). Контекстом по умолчанию считается _root
addCondition target, condition, address1, address2 Условный переход по условию condition в контексте target. Если контекст не задан, используется контекст нити. Если condition==true, происходит переход на адрес address1, в противном случае на address2. Если адрес является строковым значением, происходит смещение на указанное количество действий, например "-2" или "5", если же адрес является числом, происходит переход на указаннный номер действия.
addFunctionCall interval, target, function, arguments Вызов функции function в контексте target с параметрами arguments через interval миллисекунд. Если опустить interval, функция выполнится через одну миллисекунду. Если опустить параметр target, функция выполнится в контексте нити
addGoto address Перемещение внутреннего указателя нити на указанное действие. Если параметр address является строковым, происходит смещение на указанное количество действий, например "-2" или "5", если же address является числовым, происходит переход на указаннный номер действия.
addSetSignal signal Вызвать сигнал signal
addStop --- Остановка работы нити
addWait value Подождать value кадров, если value - текстовый параметр, и value миллисекунд в обратном случае
addWaitFrame target, value Подождать, пока мувиклип target не доиграет до кадра value. Если target отсутствует, нить ждет пока ее контекст не дойдет до указанного кадра
addWaitSignal thread, signal Подождать, пока нить thread не вызовет сигнал signal
run --- Принудительный запуск нити
stop --- Принудительный останов нити

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

mythread=new Thread(myclip); mythread.addWaitSignal(otherThread,'done'); mythread.addFunctionCall(100,myfunction,argument); mythread.addStop();

А вот и сам код класса нити.

#initclip
//
// Thread engine. Freeware. (c) 2003 Ilya Shlyakhovoy, ilya_cat@mail.ru
// TMU Consulting http://www.tmu.ru
//

_global.threadStop=0
 _global.threadWait=1
 _global.threadWaitFrame=2
 _global.threadWaitSignal=3
 _global.threadFunction=4
 _global.threadGoto=5
 _global.threadSetSignal=6
 _global.threadCondition=7
 

Thread=function(owner) {
 this.init(owner)
}

Thread.prototype.init=function(owner) {
 if (owner!=undefined) {
 this._parent=owner
 } else {
 this._parent=_root;
 }
 this.$PC=0;
 this.$queue=[];
 this.$signals=[];
 this.$signal=undefined;
 this.$delay=1
 this.$waiting=false;
 this.$classname='thread'
 this.addProperty('autoStart',this.getAutoStart,this.setAutoStart)
 this.autoStart=true;
 ASSetPropFlags(this,null,131) //??
}

Thread.prototype.getAutoStart=function() {
 if (typeof(this.onEnterFrame)=='function' or this.$waiting) return false;
 return this.$as;
}

Thread.prototype.setAutoStart=function(as) {
 this.$as=as;
}

Thread.prototype.checkRun=function() {
 if (this.$interval==undefined and this.autoStart) this.run();
}

Thread.prototype.run=function() {
 if (this.$interval==undefined) {
 this.$delay=1
 clearInterval(this.$interval);
 this.$interval=setInterval(this.process,this.$delay,this)
 }
}

Thread.prototype.stop=function() {
 clearInterval(this.$interval);
 this.$interval=undefined
}

Thread.prototype.$procfunction_0=function(current) {
 clearInterval(this.$interval);
 this.$interval=undefined
 this.$delay=1
 this.$PC++
}

Thread.prototype.$procfunction_1=function(current) {
 if (typeof(current.value)=='string') {
 clearInterval(this.$interval);
 this.$interval=undefined
 this.$queue[this.$PC].passed=0
 this.onEnterFrame=function() {
 if (++this.$queue[this.$PC].passed>=Number(this.$queue[this.$PC].value)) {
 delete this.onEnterFrame;
 this.$PC++
 this.$delay=1
 this.$interval=setInterval(this.process,this.$delay,this)
 }
 }
 } else {
 if (current.value!=this.$delay) {
 clearInterval(this.$interval);
 this.$interval=setInterval(this.process,current.value,this)
 }
 this.$PC++
 }
}

Thread.prototype.$procfunction_2=function(current) {
 clearInterval(this.$interval);
 this.$interval=undefined
 this.onEnterFrame=function() {
 if (this.$queue[this.$PC].where._currentframe==Number(this.$queue[this.$PC].value)) {
 delete this.onEnterFrame;
 this.$PC++
 this.$delay=1
 this.$interval=setInterval(this.process,this.$delay,this)
 }
 };
}

Thread.prototype.$procfunction_3=function(current) {
 clearInterval(this.$interval);
 this.$interval=undefined
 this.$wait=true;
 this.$PC++;
 this.$signal=current.signal;
 current.thread.getSignal(this);
}

Thread.prototype.$procfunction_4=function(current) {
 var wh=current.where,fn=current.func;
 if (typeof(current.where)=='string') wh=eval(current.where)
 if (typeof(current.func)=='string') fn=eval(current.func)
 fn.apply(wh,current.args)
 var dtt=Number(current.delay) || 1;
 this.$PC++
 if (dtt!=this.$delay) {
 this.$delay=dtt
 clearInterval(this.$interval);
 this.$interval=setInterval(this.process,this.$delay,this)
 }
}

Thread.prototype.$procfunction_5=function(current) {
 if (typeof(current.value)=='string') {
 this.$PC+=Number(current.value)
 } else {
 this.$PC=current.value
 }
 clearInterval(this.$interval);
 this.$delay=1
 this.$interval=setInterval(this.process,this.$delay,this)
}

Thread.prototype.$procfunction_6=function(current) {
 for (var a in this.$signals) if (this.$signals[a].checkSignal(current.signal)) {
 delete this.$signals[a]
 this.$signals.splice(a,1)
 }
 this.$PC++
 clearInterval(this.$interval);
 this.$delay=1
 this.$interval=setInterval(this.process,this.$delay,this)
}

Thread.prototype.$procfunction_7=function(current) {
 if (current.where[current.condition]) {
 current.value=current.address1
 } else {
 current.value=current.address2
 };
 if (typeof(current.value)=='string') {
 this.$PC+=Number(current.value)
 } else {
 this.$PC=current.value
 }
 clearInterval(this.$interval);
 this.$delay=1
 this.$interval=setInterval(this.process,this.$delay,this)
}

Thread.prototype.process=function(ths) {
 this=ths;
 if (this.$PC>=this.$queue.length) {
 clearInterval(this.$interval);
 this.$interval=undefined
 return
 }
 var current=this.$queue[this.$PC];
 this['$procfunction_'+current.action](current)
}

Thread.prototype.getSignal=function(thrd){
 this.$signals.push(thrd)
}

Thread.prototype.checkSignal=function(sign){
 if (this.$signal==sign and this.$signal!=undefined) {
 this.$signal=undefined
 this.$interval=setInterval(this.process,1,this)
 this.$wait=false;
 return true
 }
 return false;
 }
 
 Thread.prototype.addStop=function(value) {
 this.$queue.push({action:0})
 this.checkRun()
}

 Thread.prototype.addWait=function(val) {
 this.$queue.push({action:1,value:val})
 this.checkRun()
}

 Thread.prototype.addWaitFrame=function(whr,val) {
 if (typeof(whr)=='number') {
 this.$queue.push({action:2,where:this._parent,value:whr})
 } else if (typeof(whr)=='string') {
 this.$queue.push({action:2,where:this._parent,value:Number(whr)})
 } else {
 this.$queue.push({action:2,where:whr,value:Number(val)})
 }
 this.checkRun()
}

 Thread.prototype.addWaitSignal=function(thrd,sign) {
 if (thrd.$classname=='thread') {
 this.$queue.push({action:3,thread:thrd,signal:sign})
 }
 this.checkRun()
}

 Thread.prototype.addFunctionCall=function() {
 if (arguments.length==0) return
 var dt=1,ac=0,whr
 if (typeof(arguments[ac])=='number') {
 dt=arguments[ac]
 ac++
 }
 if (typeof(arguments[ac])!='function') {
 whr=arguments[ac]
 ac++
 } else {
 whr=this._parent
 }
 this.$queue.push({action:4,where:whr,func:arguments[ac],delay:dt,args:arguments.slice(ac+1)})
 this.checkRun()
}

 Thread.prototype.addGoto=function(addr) {
 this.$queue.push({action:5,value:addr})
 this.checkRun()
}

 Thread.prototype.addCondition=function(whr,cond,addr1,addr2) {
 if (arguments.length==0) return
 var ac=0;myw
 if (typeof(arguments[0])!='movieclip') {
 myw=this._parent
 } else {
 ac++
 myw=whr;
 }
 this.$queue.push({action:7,where:myw,condition:arguments[ac],address1:arguments[ac+1],address2:arguments[ac+2]})
 this.checkRun()
 }
 
 Thread.prototype.addSetSignal=function(sign) {
 this.$queue.push({action:6,signal:sign})
 this.checkRun()
 }
 
#endinitclip

Ну что ж, еще раз поздравляю всех вас с Новым Годом и прошу - пишите на ilya_cat@mail.ru, задавайте вопросы

http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное