본문 바로가기

동강의AS3.0 강좌

[Base] 5강 - DisplayObejct 와 객체 동적 생성(2)


지난 강에서 DisplayObject 의 개념에 대해 잠깐 언급하였습니다. 그때 클래스 다이어 그램은 기억이 나시는지요? ( 4강참고) 그 다이어 그램과 같이 Flash 에 존재 하는 모든 객체속성( class ) 들은 상속에 상속을 거쳐서 자신의 속성을 만들게 됩니다.  

예를 들어 F1 을 눌러 봅시다.

 

 

MovieClip

패         키지 :loadClassListFrame('class-list.html')" href="file:///C:/Documents%20and%20Settings/All%20Users/Application%20Data/Adobe/Flash%20CS3/en/Configuration/HelpPanel/Help/ActionScriptLangRefV3/flash/display/package-detail.html">flash.display
클래스 public dynamic class MovieClip
상속 MovieClip  Sprite  DisplayObjectContainer  InteractiveObject  DisplayObject  EventDispatcher  Object

모든 클래스의 최상위인 Object 에서 DisplayObject Sprite 를 거쳐서 MovieClip 이 만들어 짐니다. 이게 바로 상속관계지요

그러면 1) 상속되면 머가 좋은거냐??  2) 왜 상속 되는 거냐??  

1) 상속되면 하위 클래스에서 상위 클래스의 속성을 그대로 가져다 쓸수 있기 때문에 속성을 재 정의할 필요가 없습니다.

단적인 예를들면 MovieClip 은 Sprite 를 상속 받는데 이 Sprite 속성은 F1 을 보시면 알겠지만 MovieClip 에서 타임라인이 없는 Class 라고 보시면 됩니다. 따라서 MovieClip 에서 사용가능한 gotoAndPlay, gotoAndStop 속성을 사용할수가 없습니다.  

2) 왜 상속되는거냐? class 에 대해 확실하게 이해 하고 있지는 않지만, 제 의견은 이렇습니다. 있던 속성을 갔다 쓰면 되지 또 만들 필요가 있는가? 라는 생각입니다. 자세한건 객체 지향 프로그램 관련 서적을 참고 하세요.  

위와 같이 우리가 가장 많이 쓰고 있는 MovieClip 은 이렇게 만들어 지는 것입니다. 상속에 개념은 여기 까지 하고 이제 DisplayObject 와 DisplayObejectContainer 개념을 적용해 보겠습니다.

우선 fla action 창에
trace(root, stage); 
를 찍어 봅시다.
// output
[object MainTimeline] [object Stage]

그리고
var mc:MovieClip = new MovieClip();
trace(mc); 
// output
[object MovieClip] 

여기서 말하는 stage 는 위에서 output 으로 나온것과 같이 object Stage 타입의 하나의 객체 입니다.
보이는 화면이라고 해서 객체가 아닌것이 아니라 그 화면 자체도 객체인 것입니다.
단적인 예를 들어 지구 = stage , 사람 = MovieClip 이라 볼수 있습니다.


위와 같은 계층도로 되어 있습니다. 복잡하니깐 여기에선 Stage 와 Main 부분만 보도록 하겠습니다. 

trace(stage.root);
trace(this.parent);
trace(stage.getChildAt(0));

trace(stage.getChildAt(0).root);
trace(stage.getChildAt(0).parent);

(getChildAt 은 (안) 안에 있는 숫자의 뎁스로 접근하여 그 뎁스에 있는 객체를 반환 합니다. 

// output

[object Stage]
[object Stage]
[object MainTimeline]
[object MainTimeline]
[object Stage] 

parent 는 객체.parent  ==> 객체의 부모에 접근한다는 말 입니다. 여기서 유심이 볼 부분은 빨간색 입니다. stage 에 0 뎁스에 있는 것은 MainTimeline 이다. stage 가 시작 부터 가지고 있는 객체 이지요 ( 그냥 첫 화면에서 보는 타임 라인 이라고 생각하시면 됩니다 ) 이렇게 stage 는 담을 공간을 마련해 주고, 우리는 그 위에 무비클립을 생성하여 사용하는 것이지요. 어려운 개념이니 어렵다고 대충 넘어 가지 마시고 찬찬히 trace 찍어 보시기 바람니다.

 

자 이제 stage 에 마우스 클릭으로 무비 클립을 만들어 circle_mc 를 만들어 봅시다.
action 창에는 ( 앞으로 action 이라고만 쓰겠습니다 )  

removeChild(circle_mc);
trace(circle_mc); 

짠! 어디로 갔을까요??  화면에서는 사라졌지만 아직도 trace 문에서는 찍히고 있는 것을 알수 있습니다. 이 말은 뭘 의미하는 것일까요?

화면에서 사라졌다고 해서 메모리에서도 지워진 건 아님니다.
장난 하냐 ? 그럼 어떻게 지워야 다 지워지는 거냐?   

removeChild(circle_mc);
trace(circle_mc);
circle_mc = null;
trace(circle_mc);  

// output
[object MovieClip]
null  

null 값을 넣어 줘야 지워 지게 됩니다. ( 어렵게 말하면 플레시에는 가비지 콜렉션이라는 쓰레기 값들을 ( 메모리에서 필요하지 않은 부분 ) 을 수집하는 장치가 있습니다. 그 수집 장치의 수집되는 후보가 되는 것이지요 ) 이 개념은 단순 코딩할때는 그냥 지나치는 부분 이지만 Loader class 나 URLLoader

로 파일을 불러 들일 때는 광장히 중요하게 작용하는 부분입니다. 예를 들어 Loader 로 이미지를 주기적으로 10개씩 로드 한다고 생각하면 removeChild 와 null 값으로 이미 지나간 이미지를 지워주지 않는다면 메모리는 점점 쌓이게 되어 컴퓨터 다운!!! 의 결과를 볼수 있으실 것입니다.  

지워주는건 이제 어떻게 하는지 알았고, 같은 무비 클립을 어떻게 동적으로 생성 할거냐? 가 문제 인데 2.0 에서는 duplicateMovieClip 나 attachMovie 을 사용하였지만, 3.0 으로 오면서 모두 사라졌습니다. 대신에 좀더 강력한 세부적으로 작용하는 addChild 나왔습니다.
우선 아까 소스에서

removeChild(circle_mc);
trace(circle_mc);
addChild(circle_mc); 

다시 원이 나타남니다. 그럼  


removeChild(circle_mc);
trace(circle_mc);
circle_mc = null;
addChild(circle_mc);
// output
[object MovieClip]
TypeError: Error #2007: 매개 변수 child은(는) null이 아니어야 합니다.
 at flash.display::DisplayObjectContainer/addChild()
 at Untitled_fla::MainTimeline/frame1()

이미 참조 할수 없게 되어 버렸다는 에러가 나오네요.


addChild removeChild 를 알았다고 해서 동적 생성을 할수 있는건 아님니다. 이제 부터 중요한 라이브러리에 있는 무비클립을 Linkage 하는 절차에 대해 알아 보겠습니다. 우선 아까 것에 이어서 circle_mc 를 stage 에서 지워 버림니다. 그리고 라이브러리에 등록되어 있는 무비클립 위에서 마우스 우클릭을 합니다.

Linkage 에 Export for Actionscript 를 클릭하면 아래와 같이 바뀌게 됩니다. Class 명에는 자신이 지정하고 싶은 이름을 쓰면 됨니다 여기서는 Circle 로 하겠습니다.



이제 준비가 끝났습니다. 이제 addChild 해 볼까요?

var cir:Circle = new Circle();       // 방금전 Circle 이라는 Class 를 생성하였습니다. 이제 그

addChild(cir);                                 클래스를 이용하는 것이지요.  

짠! 붙었습니다. 부모인 stage 에 자식인 cir 을 addChild 했습니다. stage.addChild(cir); 도 같은
의미 입니다. (stage 상에서만 )

변수를 생성하는 방법은

var 이름:클래스명 = new 클래스명();  

본래 검은색으로 써있는 클래스명은 인터페이스 명이라고 해야 되는게 맞지만 그냥 넘어 가겠습니다.( 인터 페이스는 아주 나중에...)  

이제 이걸 이용하여 좀더 재미난걸 만들어 보겠습니다.   

 
  1. import fl.transitions.easing.*;
  2. import fl.transitions.Tween;
  3.  
  4. for(var i:int = 0; i < 50; i++)
  5. {
  6.         var cir:Circle = new Circle();
  7.         cir.x = Math.random() * 550;
  8.         cir.y = Math.random() * 400;
  9.         addChild(cir);
  10. }
  11.  
  12. addEventListener(MouseEvent.MOUSE_OVER, mouseOverhandler);
  13.  
  14. function mouseOverhandler(event:MouseEvent):void
  15. {
  16.         var targetX = Math.random() * 550;
  17.         var targetY = Math.random() * 400;
  18.         new Tween(event.target,"x",Strong.easeOut,event.target.x,targetX, 30,false);
  19.         new Tween(event.target,"y",Strong.easeOut,event.target.y,targetY, 30,false);
  20.        
  21.        
  22. }

만들어 보시면 알겠지만 여기서 Tween 클래스의 치명적인 버그가 존재(?) 한다는 걸 알수 있습니다.
움직이다 멈춰 버리지요..ㅋㅋㅋ 그래서 ENTER_FRAME 을 돌리던가 google Tweener 를 쓰곤 한담니다. 한번 영역 밖으로 나가지 않게 소스를 수정해 보세요.
Math.random() 함수는 뒤에 오는 인자 값으로 랜덤한 값을 반환해 줍니다.
예)
Math.random() * 10; 
0~ 10 까지 숫자중 하나는 반환해 줌.  

이제 클래스 개념이 본격적으로 시작 되었슴니다. 다음 강 부터는 Frame 액션에서 벗어나 class 액션으로의 업그래이드를 해 보겠습니다.  

역시나 잘못된 점이나 질문들을 거침없는 댓글 부탁드리고요.