AS3.0 로더(Loader)로 불러온 다른 swf 의 클래스 사용하기
by 세계의끝 on 7.05, 2009, under AS3.0 API
이 문제는 AS3.0 의 swf 간 로드 구조를 구성할 때 반드시 한번은 만나게 되는 문제이므로 정리해 둡니다.
Main.swf 에서 Sub.swf 를 Loader 를 이용해 로드한 후에 Main.swf 에서 Sub.swf 의 클래스나 메서드를 사용해야 할 때가 있습니다.
AS2.0 라면 MovieClipLoader 와 loadClip 을 이용하여 로드 완료 이벤트를 확인 한 후 인스턴스네임으로 참조해 들어가면 되지만, AS3.0의 경우에는 그런 방법으로 다른 swf의 클래스를 사용할수 없습니다. 이런 경우 ApplicationDomain 클래스의 getDefinition() 메서드를 이용해 참조해야 합니다.
이 예제에는 3개의 클래스가 사용됩니다. 각 클래스에 대한 설명은 본문과 코드 주석에 포함되어 있습니다.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // SubSystem.as 의 내용. package { import flash.display.Sprite /* * 이 클래스는 별도로 SubSystem.swf로 컴파일 하여 Main.swf 에서 Loader를 통해 로드하는 대상으로 삼음 * 즉, 이 클래스는 SubSystem.swf 의 도큐먼트 클래스 입니다. */ public class SubSystem extends Sprite { public function SubSystem() { trace( "SubSystem !!!" ) } public function createItem( $name:String = "" ):Sprite { var item:Circle = new Circle( $name, 50, 50 ); addChild( item ) return item; } } } |
생성자에서는 제대로 로드가 되었는지 확인하는 용도의 trace 외에는 하는 일이 없고, public 으로 공개된 createItem() 메서드는 Circle 클래스를 new 해주고, 객체를 반환하고 있습니다.
Circle 클래스는 예제용으로 밖에 사용할 일이 없는 궁극의 원그리기 클래스 입니다.
0 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 | // Circle.as 의 내용. package { import flash.display.Sprite public class Circle extends Sprite { private var _name:String; public function Circle( $name:String = null, $x:int = 0, $y:int = 0, $radius:uint = 50, $color:uint = 0x000000, $alpha:Number = 1 ) { draw( $x, $y, $radius, $color, $alpha ) this._name = $name } private function draw( $x:int, $y:int, $radius:uint, $color:uint, $alpha:Number ):Sprite { var item:Sprite = new Sprite(); item.graphics.beginFill( $color, $alpha ); item.graphics.drawCircle( $x, $y, $radius ); addChild( item ) return item } override public function get name():String { return _name; } } } |
SubSystem 클래스에서 Circle 클래스를 따로 import 하지 않았으므로, 이 두개의 클래스는 같은 폴더에 넣어야 동작하겠군요.
다음은 Main 클래스 입니다. 이 파일은 Main.swf 에 사용되는 도큐먼트 클래스 입니다.
0 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 32 33 34 35 36 | //Main.as 의 내용. package { import flash.display.DisplayObject; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.net.URLRequest; public class Main extends Sprite { private var loader:Loader = new Loader(); private var request:URLRequest = new URLRequest( "SubSystem.swf" ); public function Main() { //Loader는 직접 addEventListener 하지 못하고 contentLoaderInfo 를 통하여야 함 loader.contentLoaderInfo.addEventListener( Event.COMPLETE, completeHandler ); loader.load( request ); } private function completeHandler( e:Event ):void { var runtimeClassRef:Class = loader.contentLoaderInfo.applicationDomain.getDefinition( "SubSystem" ) as Class; var displayObj:DisplayObject = new runtimeClassRef(); //addChild 하려면 DisplayObject 로 캐스팅 addChild( displayObj ); var subSystemObj:Object = displayObj as Object; //메서드를 호출하려면 다시 Object 로 캐스팅 var item1:Sprite = subSystemObj.createItem( "item1" ); var item2:Sprite = subSystemObj.createItem( "item2" ); item2.x = 100; //로드한 SubSystem.swf 의 자원은 이제 subSystemObj 로 참조하면 됩니다. trace( "subSystemObj.numChildren : ", subSystemObj.numChildren ); } } } |
getDefinition() 과는 직접 관련은 없지만, 한가지 짚고 넘어가야할 내용이 있습니다. Loader 의 다운로드 진행상황이나 로드 완료 등의 이벤트를 받고 싶을 경우 Loader 에 contentLoaderInfo 를 통해 addEventListener 를 걸어야 합니다.[01] Loader 에 직접 addEventListener 를 걸고 아무리 기다려본들 이벤트는 발생하지 않습니다.[02]
다시 내용으로 돌아와서, Main.as 는 SubSystem.swf 를 Loader 를 통해 로드하고, 로드 완료된 이벤트 확인한 이후, SubSystem 의 내부 메서드를 호출하여 SubSystem 로 하여금 Circle 객체를 new 로 생성하게 하고 있습니다.
만약 SubSystem.swf 를 통해 얻고 싶은 것이 fla의 라이브러리에 Class 네임으로 정의한[03] 무비클립이라면 getDefinition( “ClassName” ) 과 같이 해당 무비클립의 클래스 네임을 넣어주고 addChild 까지만 해주면 됩니다. 메서드 호출 까지도 필요 하지 않은 경우라면 이렇게 훨씬 더 간단하죠.
참고 : Main.swf 가 AS3.0 이고 SubSystem.swf 가 AS2.0 인 경우 ApplicationDomain 은 사용할 수 없습니다.
관련 레퍼런스 링크
ApplicationDomain 클래스 사용
ActionScript 3.0 언어 및 구성 요소 참조 설명서 : ApplicationDomain
* 다른 swf 가 아닌 하나의 swf에서 fla 라이브러리에 정의한 클래스 이름으로 무비클립을 사용하려면 “AS3.0 getDefinitionByName() 메서드를 이용한 라이브러리 자원 이용 – AS2.0 attachMovie 대응” 을 읽어보세요..
- 로더객체.contentLoaderInfo.addEventListener(……) [↑]
- 로더객체.addEventListener(……) <– (잘못된 사용) [↑]
- AS2.0의 Linkage 사용하듯 [↑]
관련된 글
20 Comments for this entry
1 Trackback or Pingback for this entry
-
도큐먼트 클래스 *.as 파일을 연결하지 않은 fla 파일의 도큐먼트 클래스 이름은? | 세계의끝과 플래시 원더랜드
2월 25th, 2010 on pm 1:24[...] 세계의끝 on 2.25, 2010, under AS3.0 작년 7월에 작성한 “AS3.0 로더(Loader)로 불러온 다른 swf 의 클래스 사용하기” 를 보면, ApplicationDomain 클래스의 getDefinition() 메서드를 이용해서 다른 [...]
Blog under the Creative Commons Attribution-NoDerivs 3.0 License
2월 24th, 2010 on pm 12:08
안녕하세요? 배우러 들렀다 질문드립니다. ㅎ
첫째는,
위에 main.as에서 클래스 정의한 부분 …….. getDefinition(‘SubSystem’)
여기에서 “SubSystem” 요게 클래스 이름이잖아요.
그럼 메인타임라인에 그냥 코딩해서 만든 swf는 위 방법으론 클래스화 안되는건가요?
2월 25th, 2010 on pm 1:26
답변글을 작성하다가 내용이 길어져 별도의 포스팅으로 발행하였습니다. ^^
http://ufx.kr/blog/393
2월 24th, 2010 on pm 12:12
둘째는, 좀 관계없는 초급 질문인데
예를 들어 맨위에 작성한 SubSystem 클래스를 도큐먼트 클래스로 하여 swf 만들때
전 여태까지 메인타임 라인에서
클래스 생성후 addChild 해줬었거든요.
flash ide(CS4)에서 이 방법 말고 다른 간단한 방법이 있는지요?
죄송하게도 항상 질문만 남기고 가네요 ㅡㅡ;
수고하세요 ^^ (코드를 쓰니깐 에러가 나네요..)
2월 25th, 2010 on pm 1:29
이 질문은 목적어와 주어가 다수 생략된것 같아, 무슨 의미인지 이해가 잘 가질 않는군요 ^^
2월 25th, 2010 on pm 11:31
아.. 요건 창피해서 다시 말씀 못드리겠네요. 하하
그냥 클래스 이름을 써넣으면 되는거였는데 암튼 혼자 해결했답니다.
5월 15th, 2010 on pm 12:40
수고많으십니다.~ 답변이 있었으면 하는 바램입니다.
상황은 제가만드는 플래시에 ~ loader로 다른 swf를 불러야하는상황입니다.
헌데 이 swf는 소스도 없고, 안에 아무것도 모르는 상황입니다. 클래스라든가뭐그런거등등아무것도….
헌데 textfield 가 있더군요.
그래서~ loader로 불러 이로드에 addEventliastener(마우스.click 을 했더니)
오~ textfield 에 값이 trace로 나오긴하더군요…
혹시 ~이런상황에서 저 textfield 의 값을 제가 빼올수있을까요?
개발자입니다만 플래시를 잘몰라서요.
이벤트발생시키고 관련 함수를 실행시키게 되어있던데
그안에 e.target.text하니까 일단 textfield 의 글을 가져오기는하는데~ 난감합니다.
5월 15th, 2010 on pm 10:49
그러니까 TextField 객체의 인스턴스네임을 알고 싶다는 질문이죠?
만약 swf 파일에 있는 텍스트필드가 스테이지에 텍스트 툴로 그려진 후 인스턴스네임이 지정된 녀석이라면 클릭이벤트의 e.target.name 로 인스턴스네임을 알 수 있습니다.
name 이 인스턴스네임은 아니지만, 플래시의 저작툴로 텍스트필드를 만든 경우에는 Flash IDE가 인스턴스네임을 지정하면서 name 속성에도 같은값을 넣어주기 때문입니다.
그런데 위의 경우가 아니고
위와 같은 형태로 액션스크립트에서 런타임에 만들어진 텍스트필드라면 핸들링을 할 수 있는 인스턴스네임을 알 수 있는 방법이 없습니다.
대부분의 경우 instance1, instance2 … 같은 형태로 자동 지정되기 때문이죠.
다만, 클래스에서 전역변수로 정의되어있다면 디컴파일러로 변수명은 알 수 있습니다만, 다른 swf 파일을 Loader 로 가져온 경우에는 단순히 변수명으로는 객체를 참조를 할 수 없으므로 무용지물이 되겠습니다.
그러나 역시 가장 흔한 경우가 첫 번째 경우이므로 name 이 뭔지 찍어보세요.
10월 12th, 2010 on pm 4:08
안녕하세요~
블로그 잘보고있습니다~
질문이 있는데요~
변수앞에 $표기는 왜 하는건가요?
10월 14th, 2010 on am 3:02
변수가 아니라 함수의 인자에 $ 기호를 사용하고 있습니다.
첫번째로는 네이밍의 중복을 피하기 위함이고,
두번째로는 인자와 전역변수들의 구분을 명확하게 하기 위함이고,
세번째로는 코드힌트를 받을 때 인자만 목록으로 받기 위함입니다.
이 포스트 본문에 있는 코드의 경우 인자에 $x 를 하지 않으면, x 라고 써야 할텐데, 이렇게 되면 DisplayObject 의 x 속성과 네이밍이 중복되서 문제가 생길 수가 있습니다.
이를 피하기 위해서 xPos 같이 인자 네이밍을 하는것 또한 그닥 의미 없는 행위이기도 하고요.
또한 인자 표시를 하지 않을 경우 코드가 아래와 같습니다.
함수 내부에서 this.value 는 전역변수인 value 를 가리키고, 그냥 value 를 사용하면 인자를 가리키죠.
이것을 구분하는게 성가신데다가 디버깅을 어렵게 하는 원인이 되기도 합니다.
그래서 인자는 인자라는 표시를 하는겁니다.
보너스로 함수 내부에서 $를 찍는 순간, 인자만 코드힌트를 볼 수 있죠.
12월 14th, 2010 on pm 4:04
안녕하세요. 2.0만 사용하다가 3.0공부하면서 세계의끝님의 포스트로 많은 도움받고있습니다.
위의 내용을 적용하다가 궁금한점이 있어서 질문드립니다.
로드된 플래시의 여러 함수를 사용하는데는 문제가 없던데… 로드된 플래시(subSystemObj)의 public변수에 값을 넘겨줄때는 약간의 딜레이가 있는듯 한데요.
예를 들어 subSystemObj에 xml경로를 넘겨주고 싶어서 subSystemObj에 public 변수로 xmlPath를 선언해놓고 위에서 처럼 부모 플래시에서 subSystemObj.xmlPath=”경로”;
이런식으로 넘겨주니 바로 받지 못하더군요. 혹시나해서 subSystemObj안에서 setTimeout으로 1/1000초 뒤에 xmlPath값을 읽어보니 그때는 읽히더라구요.ㅜㅜ
이문제를 해결할수 있는 방법이 있을까요?
참고로 이문제는 부모SWF가 외부변수(xml경로)를 받아서 자식SWF에게 넘겨주는 문제에서 부터 시작했습니다.
그럼 행복한 하루되세요^^
12월 14th, 2010 on pm 4:42
예전에 이 포스트를 쓰던 당시 그 부분에 대해 테스트를 해봤었습니다. ^^
저는 당시 메서드는 참조가 가능하지만 변수는 불가능하다 라는 결론을 내렸었는데, 그게 또 그런건 아닌 모양이군요. 어쩐지 참조가 될 법도 한데 안되는게 좀 이상하긴 했습니다.
이런 경우 타이머를 사용하는 것은 여러 모로 좋지 않습니다. 예상치 못한 곳에서 예상치 못한 결과가 나올수도 있고요.
그래서 메서드는 참조가 되는것을 이용해 get/set 메서드로 변수를 간접적으로 참조하는 방법을 사용하시면 되겠습니다.
12월 14th, 2010 on pm 8:09
이제 3.0을 막 접하다보니 get/set 있다는걸 생각 못했네요.
빠르고 명쾌한 답변 정말 감사드립니다^^
12월 22nd, 2010 on am 11:55
안녕하세요, 가르침을 얻고자 글을 올립니다. ㅎ^-^
전 지금 위의 내용을 참조 해서 main.swf 에서 asp 파일과 통신하여 특정플래시를 불러오는
작업을 진행중 입니다만, loader 를 이용해서 불러왔는데 COMPLETE event 까지 넘어가는데 화면상에 보여지지는 않습니다. 이부분에서 막히더군요, displayobject 로 형변환을 해줘야 하는건지…
간단하게 다시 설명하면 main.swf 는 a.asp 파일과 통신만을 하고, a.asp 파일에서 sub1 이라는 값을 return 해 주면 main.swf 에서 sub1.swf 파일을 불러와서 보여줘야 하는 작업 입니다.
아..프로그래머인데 이제 막 액션 스크립트를 접하다 보니 어려운점이 많네요, 도움 부탁드립니다. ^-^
12월 22nd, 2010 on pm 5:45
질문 내용만으로 짐작하건대, 다른 언어 하시던 분이라면 아마도 Loader 클래스의 성격에 대해 약간 다르게 이해하고 계신것 같다는 느낌이 드는군요. 그렇다면 이 포스트 본문과도 전혀 다른 질문 내용이고요.
Loader 클래스는 기본적으로 DisplayObject 클래스를 상속한 클래스이고, 그렇다는건 addChild() 를 해야 화면에 보여지게 됩니다. 단순히 로딩만을 담당하는 클래스가 아니라는거죠.
12월 22nd, 2010 on pm 9:02
답변 감사드립니다. ^-^ addChild(loader.content) 하는걸로 해당 문제는 진행하였으나, 타임라인에 직접 코딩했던걸 class 로 나누려니 이번엔 또 addChild 가 안되네요, main.swf 의 stage 를 main.as 에서 사용할 수 있도록 선언해서 전달한 후 addChild 해야 할거 같은데, 지식이 전무 하다보니, 어렵네요, 혹시 어떤 방식으로 처리를 해야 하는지 도움을 받을 수 있을까요?
12월 23rd, 2010 on am 12:37
addChild()의 특성이나 사용 방법을 이해하셔야 해결되는 문제일텐데,
그 내용을 제가 전부 설명해 드리는건 지면상 불가능하겠죠.
아래 레퍼런스를 정독하시고, 해결책을 찾으시길 바랍니다.
http://help.adobe.com/ko_KR/Flash/CS5/AS3LR/flash/display/DisplayObjectContainer.html?allClasses=1
5월 13th, 2011 on pm 4:38
이상하네…왜 댓글을 적어도 안나오지 -_-;;
5월 14th, 2011 on am 1:46
잘 나오고 있습니다. ~_~
단, 이 블로그에 처음 댓글을 작성한 경우에는 제가 승인을 해드려야만 보이도록 설정해 놓았기 때문에(스팸 때문에)
안보이는것처럼 보일수는 있습니다만, 두번재 이후부터는 문제 없습니다.
9월 26th, 2011 on am 9:32
본문글과 관계가 없을수도 있지만..
조심스럽게 질문드립니다 ^^;;
현재 프리로더역할인 swf로 swf를 하나 불러드리는데
구동이나 다른건 이상이 없는데 불러드린 swf에서 클릭이벤트로
fullscreen을 구현할려니 도저히 되지가 않아서요.
이런저런 방법을 시도해봤으나 결과는 X.
불러드린 swf에서 프리로더의 stage에 접근해야 할것 같긴한데
방법을 몰라서 이건 시도도 못해보고 있습니다.
좋은 의견이나 방법 알려주시면 감사하겠습니다.
9월 27th, 2011 on am 12:14
먼저, html 에 사용된 swf 임베드 코드의 파라미터에 풀 스크린이 허용 되어 있는지 확인해보실 필요가 있고요.(의외로 이런 곳에 원인이 있는 경우가 많습니다.)
stage 를 로더가 로디에게 넘겨주는 방법이야 위의 본문의 내용대로 public 메서드를 이용해 넘겨줄 수 있지만, 이미 로디의 무비클립들이 보이고 클릭되는 시점이라면 도큐먼트 클래스의 stage 든 어떤 객체의 stage 든 이미 존재하는 시점일텐데, stage 가 없어서 풀 스크린이 안먹는다는건 앞 뒤가 맞지 않아 보입니다.
이런 경우는 다른 원인일 가능성이 높아 보이므로,
로디쪽 코드에서 아래와 같이 EVENT.ADDED_TO_STAGE 이벤트를 이용해 디버깅 해보세요.