flash/As3.0 | 2007/08/09 21:27

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...



 
 
태그 : , ,
이 글의 관련글(트랙백) 주소 :: http://kimkijeung.com/trackback/101
BlogIcon 김진혁 2007/08/24 13:44 ReplyDelete
어쩐지 .. 트윈 하는데 가끔씩 사라지거나 목표지점에 도달하지않고 트윈이 끝나버리는 현상이 발생하더라구요~ 으아 감사합니다~
caurina Tween도 해봐야겠당
BlogIcon 기정e 2007/08/24 16:59 Delete
garbage collection 때문에 뜻하지 않게 여러가지 문제가 발생하더라구요
그리고 단순히 한두개의 객체를 트윈한경우는 발생하지 않고 os 에서 할당한 임의의 메모리값에 도달할 경우 메모리 수거가 일어나기 때문에 트윈같은 경우는 여러가지를 고려해야 할듯 싶네요~~
^_^ 2007/09/16 15:24 ReplyDelete
음... 이거 트위닝 도중에 멈출려면 어찌해야할까요....
removeEventListener를 호출하려고 해도
update가 지역변수로 되어있어서.....
인수로 넣을수도 없고용..ㅠ.ㅠ
BlogIcon 기정e 2007/09/16 20:43 Delete
위 클래스는 기존에 제공되고 있는 Tween 클래스를 간단하게 대체하고자 제작한 것입니다. 따라서 Tween 에서 제공하는 많은 이벤트들은 제공하지 않고 있습니다. 말씀하신 stop 기능은 비교적 간단한 기능이라 제가 추가하여 업로드하였습니다. stop을 구현하기 위해서는 트윈클래스에 연결되어있는 이벤트 리스너를 삭제하면 되는데 이를 위해서는 지역변수 update 함수참조값이 필요하게 됩니다.
이를 위해 Dictionary 를 사용하여 사전에 _referContainer 전역변수객체에 update 함수의 참조값을 저장하였기 때문에 _referContainer[targetObj] 의 값의 이벤트 리스너를 삭제하시면 됩니다. 구체적인 내용은 샘플파일을 참고하세요.
혹시, resume 같은 기능을 구현하시려면 트윈에 필요한 모든정보를 저장하는 것이 필요합니다. 따라서 위와는 조금 다른 방식으로의 접근이 필요합니다. 그럼 도움이 되셨길~~^^
^_^ 2007/09/20 19:13 ReplyDelete
혹시나 해서 와봤는데...
친절히 수정까지 해주셨네요..
위 코드를 써서 그냥 재미난 것을 혼자 만들고 있었거든요..
저는 start가 리턴값으로 update()의 참조를 돌려주는 방식으로
바꿔서 하고 있었어요 ㅎㅎ
그래서 그걸 임시 변수에 저장해놨다가
멈추고 싶을 때 removeListener에 넣는 식으로..^^ 임시방편..
많은 공부가 되네요.. 감사합니다.

Name 
Password 
Homepage 
  secret
Comment 
  글쓰기


[PREV] [1] ... [7][8][9][10][11][12][13][14][15] ... [105] [NEXT]

 
전체 (105)
flash (74)
math&physics (4)
programming (11)
Flex2 (1)
Mac (2)
photo (0)
project (6)
주저리주저리 (3)
유용한 자료들 (1)
diary (0)
Book (1)
web (2)
«   2009/01   »
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31