동강의AS3.0 강좌2008.12.11 01:43

지난 번 강좌에 이어서 해 보겠습니다. 다들 iMac navigation 이라면 아시지요? 맥을 쓰는 사람들은 항상 모니터 아랫쪽에 위치 시켜 두고 쓰는 편리 한(?) 네비게이션 입니다. 이미 많은 분들이 구현을 해 놓으셨고 윤용호 님이 쓰신 플래시 네비게이션 패턴 18 에서도 다루고 있습니다.  

1단계에서 만들 네비게이션은 아래와 같습니다.


stage 에 자신의 icon 을 디자인 하고, 그 icon 을 무비 클립으로 등록합니다.


저는 5개의 icon 을 만들었고, icon0 ~ icon4 로 이름을 붙였습니다. 이 5개의 무비 클립을 배열에 저장하고 그 배열의 순서로 icon 들을 조정할 것 입니다.  Document class 를 만들고 위의 icon 들을 저장할 배열을 만듭니다.   

 
  1. public function Main() {
  2.                        
  3.                         bit_arr = new Array();
  4.                         bit_arr = [icon0,icon1,icon2,icon3,icon4];
  5.                         
  6.                                
  7.                         for (var i:int=0; i< bit_arr.length; i++) {
  8.                                
  9.                                
  10.                                 bit_arr[i].trgScale = 1.0;
  11.                                 bit_arr[i].num = i;
  12.                                 bit_arr[i].addEventListener(MouseEvent.MOUSE_OVER, iconOverhandler);
  13.                                 bit_arr[i].addEventListener(MouseEvent.MOUSE_OUT, iconOuthandler);
  14.                                
  15.                                
  16.                                
  17.  
  18.                                 addChild(bit_arr[i]);
  19.                                
  20.                                
  21.                         }
  22.                        
  23.                         this.addEventListener(Event.ENTER_FRAME, onEnterframehandler);         
  24.                         mid =  Math.floor(bit_arr.length/2);
  25.                         overIcon = mid;
  26.                         overbool = false;
  27.                         center = bit_arr[mid].x;
  28.                 }

  for 문을 돌려서 만들었던 icon 들의 위치를 정해 주고, addEventListener 를 해 줍니다. 여기에서 각 icon 들 마다 num 과 trgScale 을 지정하였는데, num 은 icon 이 몇번째에 위치해 있나를 알려 주는 변수 이고, trgScale 은 icon 들의 크기를 조정할때 원래 크기로 돌아 가기 위한 기준을 저장하는 변수 입니다. enterframe 으로 돌리기 위한 이벤트로 등록을 하고, icon 들 사이에서 가운데에 존재 하는 icon 을 알기 위한 overIcon 을 지정해 줍니다. 그리고 그 x 위치를 저장해 줍니다. 위의 결과물에서도 알수 있듯이, icon 의 크기와 위치가 변하고, icon 에서 RollOut 되면 다시 원래의 자리로 돌아와야 합니다.  mid 값과 overIcon, center 값을 몰랐을 경우, 신경쓰지 않았을 경우에는 다음과 같은 일이 발생합니다. 무비 클립은 dynamic class 이기 때문에 직접적인 변수 생성이 가능합니다.
참고 : http://cafe.naver.com/flashactionscript/11367


마우스 롤 오버 & 아웃

 
  1. private function iconOverhandler(event : MouseEvent) : void {
  2.                         overbool = true;
  3.                         overIcon = event.target.num;
  4.                        
  5.  }

 

 

  1. private function iconOuthandler(event : MouseEvent) : void {
  2.                        
  3.                         iconReset();
  4.                                
  5.                         overbool = false;
  6.                        
  7. }

 마우스를 icon 에 오버 하면 enterframe 에서 if 문 처리를 판단하는 overbool 변수를 true 로 해 줍니다. 초기값은 false 로 되어있었지요. 그리고 어떤 icon이 오버 되었다는것을 알려 주는 overIcon 에 event.target.num 으로 숫자를 전달해 줍니다.  

지금 부터 산수 입니다;;;;;;;

 
  1. private function onEnterframehandler(event : Event) : void {
  2.                        
  3.                                        
  4.                         for (i=overIcon+1; i < bit_arr.length; i++) {
  5.                                 bit_arr[i].x = bit_arr[i-1].x + bit_arr[i-1].width/2 + bit_arr[i].width/2;
  6.                         }
  7.                         for (i=overIcon-1; i > -1; i--) {
  8.                                                                
  9.                                 bit_arr[i].x = bit_arr[i+1].x - bit_arr[i+1].width/2 - bit_arr[i].width/2;
  10.                         }
  11.                 }   

 

 

 

위에서

  1.   overbool = true;
  2.   overIcon = event.target.num;

한 이유가 여기서 나오게 됩니다. RollOver 하는 icon 이 바뀔때 마다 계속 Enterframe 을 돌려 주고 계속 위치를 변경해 줍니다.

 
  1. private function onEnterframehandler(event : Event) : void {
  2.                        
  3.                         for (var i:int=0; i<bit_arr.length; i++) {
  4.                                
  5.                                 if (overbool)
  6.                                 {
  7.                                         var distance:int = Math.abs(bit_arr[i].x- mouseX)/2;
  8.                                         bit_arr[i].trgScale = (200-distance)/100;
  9.                                         if (bit_arr[i].trgScale < 1.0)
  10.                                         {
  11.                                                 bit_arr[i].trgScale = 1.0;
  12.                                         }
  13.                                 }
  14.                                
  15.                                 bit_arr[i].scaleX = bit_arr[i].scaleY += (bit_arr[i].trgScale-bit_arr[i].scaleX)*0.4;                          
  16.                         }                              
  17.                         for (i=overIcon+1; i < bit_arr.length; i++) {
  18.                                 bit_arr[i].x = bit_arr[i-1].x + bit_arr[i-1].width/2 + bit_arr[i].width/2;
  19.                         }
  20.                         for (i=overIcon-1; i > -1; i--) {
  21.                                                                
  22.                                 bit_arr[i].x = bit_arr[i+1].x - bit_arr[i+1].width/2 - bit_arr[i].width/2;
  23.                         }
  24.                 }       
  25.  

 

마우스의 X 위치 값과 icon 의 x 위치 값을 이용하여 distance 를 구합니다. 마우스가 멀리 있을 수록 distance 는 커지게 되고 icon 에 영향을 주게 되는 trgScale 값이 작아 지게 됩니다.  

  1. if (bit_arr[i].trgScale < 1.0)
  2. {
  3.        bit_arr[i].trgScale = 1.0;
  • }

    if 문을 이용해서 trgScale 이 원래의 scale 크기인 1.0 보다 작아 지는것을 막아 줍니다. if 문을 빼고 돌려 보세요.

    bit_arr[i].scaleX = bit_arr[i].scaleY += (bit_arr[i].trgScale-bit_arr[i].scaleX)*0.4;   

    그런후 가속도 공식을 이용하여, 크기를 변화 시켜 줍니다.
    가속도 공식 :   

    변화시키고 싶은 속성 += (원래 속성값 - 변화후 속성값)*변위(?)( 갑자기 단어가 생각이 안남 )
    ex ) this.x += ( this.x - targetX ) *0.1;   x 의 위치를 targetX 까지 변화 시킴  

    여기까지 오버 하였을때 icon 들을 변화 시켜 보았습니다. 그럼 롤 아웃 하면 ? 위에서 나왔던 iconReset() 함수를 구현해 보면

     
    1. private function iconReset():void
    2.                 {
    3.                         for (var i:int=0; i<bit_arr.length; i++) {      -------------- 1)
    4.                                 bit_arr[i].trgScale = 1.0;
    5.                         }
    6.                         overIcon = mid;                                     -------------- 2)
    7.                        
    8.                        
    9.                         bit_arr[mid].addEventListener(Event.ENTER_FRAME,mcEnterframe);            -------- 3)
    10.                 }
    11.                
    12.                 private function mcEnterframe(event : Event) : void { ----------------- 4)
    13.                         var speed:int = (center-event.target.x)*0.1;
    14.                         event.target.x += speed;
    15.                         if (Math.abs(speed)<0.01) {
    16.                                 bit_arr[mid].removeEventListener(Event.ENTER_FRAME,mcEnterframe);
    17.                         }
    18.                 }

     

    1) 모든 icon 의 scale 을 1.0 로 조절함니다. ( onEnterframe 에서 계속 돌아 가고 있기 때문에 trgScale 만 바꿔주면 됩니다 )

    2) 다시 mid 값을 가운데 위치한 icon 으로 초기화 합니다.

    3) 원래 위치로 돌아 가기 위한 mcEnterframe 를 등록합니다.  

    4) 롤 아웃이 되면 전에 있었던 center 로 가운데 있던 icon 이 이동합니다. 이 icon 만 이동 시켜도 되는 이유는 onEnterframe 에서 계속 아래 for 문이 돌아 가고 있기 때문입니다. 그리고 어느 정도 오차가 생기겠지만 speed 값이 0.01 보다 작아 지면 removeEventListener 를 해 줍니다. ( enterframe 을 계속 돌리는 것은 낭비 0.01 정도 되면 거의 변화가 느껴지지 않습니다 )

    1. private function onEnterframehandler(event : Event) : void {
    2.                        
    3.                                        
    4.                         for (i=overIcon+1; i < bit_arr.length; i++) {
    5.                                 bit_arr[i].x = bit_arr[i-1].x + bit_arr[i-1].width/2 + bit_arr[i].width/2;
    6.                         }
    7.                         for (i=overIcon-1; i > -1; i--) {
    8.                                                                
    9.                                 bit_arr[i].x = bit_arr[i+1].x - bit_arr[i+1].width/2 - bit_arr[i].width/2;
    10.                         }
    11.                 }   

    사용된 전체 코드.

     
    1. package {
    2.         import flash.display.MovieClip;
    3.         import flash.events.Event;
    4.         import flash.events.MouseEvent;
    5.         import flash.utils.Timer;
    6.         import com.pixelfumes.reflect.*;
    7.        
    8.         import icon.Cicon;     
    9.  
    10.         /**
    11.          * @author navi main
    12.          */
    13.         public class Main extends MovieClip {
    14.                
    15.                 private var overbool:Boolean;
    16.                 private var overIcon:int;
    17.                 
    18.                 private var center:int;
    19.                 private var mid:int;
    20.                 private var frametime:Timer;
    21.                 private var bit_arr:Array;
    22.                        
    23.                 public function Main() {
    24.                        
    25.                         bit_arr = new Array();
    26.                         bit_arr = [icon0,icon1,icon2,icon3,icon4];
    27.                       
    28.                                
    29.                         for (var i:int=0; i< bit_arr.length; i++) {
    30.                                
    31.                                
    32.                                 bit_arr[i].trgScale = 1.0;
    33.                                 bit_arr[i].num = i;
    34.                                 bit_arr[i].addEventListener(MouseEvent.MOUSE_OVER, iconOverhandler);
    35.                                 bit_arr[i].addEventListener(MouseEvent.MOUSE_OUT, iconOuthandler);
    36.                                
    37.                                
    38.                                 addChild(bit_arr[i]);
    39.                                
    40.                                
    41.                         }
    42.                        
    43.                         this.addEventListener(Event.ENTER_FRAME, onEnterframehandler);         
    44.                         mid =  Math.floor(bit_arr.length/2);
    45.                         overIcon = mid;
    46.                         overbool = false;
    47.                         center = bit_arr[mid].x;
    48.                 }
    49.        
    50.  
    51.                 private function iconReset():void
    52.                 {
    53.                         for (var i:int=0; i<bit_arr.length; i++) {
    54.                                 bit_arr[i].trgScale = 1.0;
    55.                         }
    56.                         overIcon = mid;
    57.                        
    58.                        
    59.                         bit_arr[mid].addEventListener(Event.ENTER_FRAME,mcEnterframe);
    60.                 }
    61.                
    62.                 private function mcEnterframe(event : Event) : void {
    63.                         var speed:int = (center-event.target.x)*0.1;
    64.                         event.target.x += speed;
    65.                         if (Math.abs(speed)<0.01) {
    66.                                 bit_arr[mid].removeEventListener(Event.ENTER_FRAME,mcEnterframe);
    67.                         }
    68.                 }
    69.  
    70.                 private function iconOuthandler(event : MouseEvent) : void {
    71.                        
    72.                         iconReset();
    73.                                
    74.                         overbool = false;
    75.                        
    76.                 }
    77.  
    78.                 private function iconOverhandler(event : MouseEvent) : void {
    79.                         overbool = true;
    80.                         overIcon = event.target.num;
    81.                        
    82.                 }
    83.                        
    84.                
    85.                 private function onEnterframehandler(event : Event) : void {
    86.                        
    87.                         for (var i:int=0; i<bit_arr.length; i++) {
    88.                                
    89.                                 if (overbool)
    90.                                 {
    91.                                         var distance:int = Math.abs(bit_arr[i].x- mouseX)/2;
    92.                                         bit_arr[i].trgScale = (200-distance)/100;
    93.                                         if (bit_arr[i].trgScale < 1.0)
    94.                                         {
    95.                                                 bit_arr[i].trgScale = 1.0;
    96.                                         }
    97.                                 }
    98.                                
    99.                                 bit_arr[i].scaleX = bit_arr[i].scaleY += (bit_arr[i].trgScale-bit_arr[i].scaleX)*0.4;                          
    100.                         }                              
    101.                         for (i=overIcon+1; i < bit_arr.length; i++) {
    102.                                 bit_arr[i].x = bit_arr[i-1].x + bit_arr[i-1].width/2 + bit_arr[i].width/2;
    103.                         }
    104.                         for (i=overIcon-1; i > -1; i--) {
    105.                                                                
    106.                                 bit_arr[i].x = bit_arr[i+1].x - bit_arr[i+1].width/2 - bit_arr[i].width/2;
    107.                         }
    108.                 }       
    109.         }
    110. }

     

    네비게이션의 경우에는 수학적인 이해가 들어 가는 부분이 많은것 같습니다. 하지만 공식처럼 쓸줄만 알면 되니깐 걱정 하진 마세요. 이번에는 한 Document class 에 다 때려 박았는데, 다음 강 부터 네비게이션을 보완하면서 2단계로 만들어 보겠습니다. 그러기 위해서는 이 하나의 클래스를 잘 이해 하고 계시는게, 2단계를 나가는데 지장이 없을꺼라 생각 됩니다.  

    다음 강에서는 클래스를 분리 하고, 좀더 이것 저것 붙여 보겠습니다. 휙휙 지나간 면이 없지 않아 있네요;; ㅋ 잘못된 점이나, 질문이 있으시면 거침 없는 댓글이나, 답글 부탁 드립니다. !! 수고하셨습니다.

     - 완료 파일 다운 받기-



  • Posted by Flash 동강