| flash 를 사용하면서 가장 많이 사용하는 부분은 아마도 트윈 부분일 것이다. 오브젝트의 속성값을 변경하면서 수많은 느낌의 모션을 만들수 있었다. 기존에 포함되어 있는 Tween 클래스는 많은 사용자들이 이런 다양한 트윈을 손쉽게 구현할 수 있게 해준다. 하지만, 생각보다 많은 기능들이 포함되어있어서 덩치도 클뿐더러 구현하는 코드 자체도 길어지게 되었다. 또한 AS3.0에서는 garbage collection 의 동작으로 인해 참조값이 없는 객체에 대해서는 collector 에 의해 메모리 수집의 대상이 되기 때문에 트윈클래스의 인스턴스를 지역변수로 참조하여 사용하게 되면 뜻하지 않게 트윈이 완료되기 이전에 객체가 사라지는 문제가 발생할 수도 있다.. 따라서 이런 문제를 해결하기 위해 지역변수보다 좀더 높은 클래스 단계의 scope 의 참조를 사용하게 되는데 이럴경우 불필요하게 많은 참조 변수들을 클래스가 가지게되여 메모리를 소비하게 된다.
그리고 가장 빈번히 사용하게 되는 트윈의 경우 일일이 이벤트 핸들러 함수를 구현하기가 여간 번거로운게 아니다. 코드자체의 길이도 길어질 뿐만 아니라 가독성 측면에서도 떨어지는게 사실이다.
이런 문제를 조금이나마 해결하고자 이전 버전의 Tween 클래스를 기반으로 AS3.0 으로 컨버팅하였다.
기본적은 틀은 이전에 AS2.0 으로 구현한 로직과 큰 차이는 없다. 참조값을 유지하기 위해 전역속성으로 트윈을 적용하였고 객체를 생성하지 않아도 되기 때문에 한결 코드도 간결해졌다.
***** update(2007.10.30) ******
pause 와 resume 기능을 추가 원하는 오브젝트의 트윈에 적용가능함
pause(), pauseAll() 나 resume(), resumeAll() 를 사용하여 전체또는 부분적인 트윈을 제어할 수 있다.
<TweenEngine class>
package com.dstrict.ub.utils.transitions{
import flash.display.DisplayObject; import flash.events.*; import flash.utils.Dictionary; /** DisplayObject tween class 트윈을 적용할 속성의 갯수에 관계없이 일괄적으로 적용가능 마지막 parameter 로 정해진 형식의 이벤트 오브젝트 적용시 이벤트 시작과 끝을 tracking 할 수 있음. @example code <code> function onTweenStart(param):void{ trace("onTweenStart---->"+param); } function onTweenFinish(param):void{ trace("onTweenFinish---->"+param); } TweenEngine.start(circle,{x:400},Regular.easeOut,30,{onStart:onTweenStart, onStartParams:["circle"],onFinish:onTweenFinish,onFinishParams:["circle"]}); </code> */ public class TweenEngine { private static var _referContainer : Dictionary=new Dictionary(true); /** @param targetObj : DisplayObject , tween 적용할 오브젝트 @param tweenProperty : Object , 속성오브젝트 ex. {x:100,y:100,alpha:1} @param easing : Function , 이징함수 @param duration : int , 지속프레임 @param rest : Obejct , [optional] event object ex. {onStart:onTweenStart,onStartParams:[],onFinish:onTweenFinish,onFinishParams:[]} */ public static function start(targetObj:*,tweenProperty:Object,easing:Function,duration:int,...rest):void{ var time:int=1; var beginning:Array=new Array(); var change:Array=new Array(); var isCreated : Boolean=false; var displayObj : DisplayObject; TweenEngine.stop(targetObj);
if(!(targetObj is DisplayObject)){ displayObj = new Shape(); isCreated=true; }else{ displayObj = targetObj; }
for(var i:* in tweenProperty){ beginning.push(targetObj[i]); change.push(tweenProperty[i]-targetObj[i]); } if(rest.length && rest[0].onStart){ var eventStartObject:Object=new Object(); eventStartObject.onStart=rest[0].onStart; eventStartObject.onStartParams=rest[0].onStartParams; //onStart event eventStartObject.onStart.apply(eventStartObject,eventStartObject.onStartParams); } //Nested function var update:Function=function(){ var objIdx:int=0; for(var i:* in tweenProperty){ targetObj[i]=easing(time,beginning[objIdx],change[objIdx],duration); objIdx++; } time++; if(time>duration){ delete _referContainer[displayObj]; displayObj.removeEventListener(Event.ENTER_FRAME,update); if(isCreated) displayObj=null;
if(rest.length && rest[0].onFinish){ var eventFinishObject:Object=new Object(); eventFinishObject.onFinish=rest[0].onFinish; eventFinishObject.onFinishParams=rest[0].onFinishParams; //onFinish event eventFinishObject.onFinish.apply(eventFinishObject,eventFinishObject.onFinishParams); } } } _referContainer[displayObj] = update; displayObj.addEventListener(Event.ENTER_FRAME,update); }
//Update 2007.10.30 /** * Pause a tweening for a given object. */ public static function pause(targetObj : *) : void { if(targetObj.hasEventListener(Event.ENTER_FRAME)) { targetObj.removeEventListener(Event.ENTER_FRAME, _referContainer[targetObj]); } } /** * Pause all tweenings on the engine. */ public static function pauseAll() : void { for(var item:* in _referContainer) { if(item.hasEventListener(Event.ENTER_FRAME)) { item.removeEventListener(Event.ENTER_FRAME, _referContainer[item]); } } } /** * Resume a tweening from a given object. */ public static function resume(targetObj : *) : void { if(_referContainer[targetObj] != null) { targetObj.addEventListener(Event.ENTER_FRAME, _referContainer[targetObj]); } } /** * Resume all tweenings on the engine. */ public static function resumeAll() : void { for(var item:* in _referContainer) { if(_referContainer[item] != null) { item.addEventListener(Event.ENTER_FRAME, _referContainer[item]); } } } /** * Stop a tweening for a given object */ public static function stop(targetObj : *) : void { if(targetObj.hasEventListener(Event.ENTER_FRAME)) { targetObj.removeEventListener(Event.ENTER_FRAME, _referContainer[targetObj]); delete _referContainer[targetObj]; } } /** * Remove all tweenings from the engine. */ public static function stopAll() : void { for(var item:* in _referContainer) { if(item.hasEventListener(Event.ENTER_FRAME)) { item.removeEventListener(Event.ENTER_FRAME, _referContainer[item]); delete _referContainer[item]; } } }
} }
<example code> import com.dstrict.ub.utils.transitions.*; import fl.motion.easing.*;
TweenEngine.start(circle,{x:400,y:300},Cubic.easeInOut,20,{onStart:onTweenStart,onStartParams:["circle start"], onFinish:onTweenFinish,onFinishParams:["circle finish"]});
//----> 마지막 오브젝트 값은 이벤트 핸들러를 참조하는 값으로 옵션사항이다. 단, 사용시 이벤트 오브젝에서 함수이름을 onStart , onFinish 로 이벤트 파라미터를 onStartParams,onFinishParams 로 키값을 사용해야만 한다.
function onTweenStart(param):void{ trace("onTweenStart---->"+param); } function onTweenFinish(param):void{ trace("onTweenFinish---->"+param); }
//stop tween stage.addEventListener(MouseEvent.CLICK,onStop); function onStop(evt:MouseEvent){ TweenEngine.stop(circle); }
download sample files...
|