2011.03.28 15:50

[GFx] 스케일폼(Scaleform) 컨테이너 방식

컨테이너 방식이란 Scaleform 에서 .swf파일들을 어떻게 로드하냐에 따른 한가지 방법을 말한다.
로드방법에는 크게 2가지가 있다.

1. 클라이언트에서 개별적으로 .swf파일을 로드하여 관리하는법.
2. 클라이언트에서 하나의 .swf 파일을 로드하고 ActionScript에서 하위 .swf파일을 로드하는 법.

두가지는 별 차이가 없을것 같지만 엄청나게 큰 차이점을 가지고 있다.

첫번째 차이점은 포커스 관리이다.
많은 사람들이 개별 로드 방식을 포기한 이유중 하나는 포커스 처리때문이다.
개별로드를 하게된다면 하나의 무비별로 별도의 Stage로 처리가 되어 다수의 포커스가 생기게 된다.
이는 심각한 문제를 발생시킬 수 있다.
모든 포커스를 가질 수 있는 개체에 개별적으로 포커스가 들어가는 불상사가 발생할 수도 있다.
또한 여러개의 글자 입력창이 중복 된다면 모든 TextInput에 글자가 동시에 쳐지는 기 현상을 볼 수도 있다.
따라서 개별 로드를 한다면 클라이언트에서 모든 무비에 따라 포커스 처리를 해 줘야 한다.
물론 컨테이너 방식을 쓴다 하더라도 포커스 처리는 해 주어야 한다.
물론 그 비중은 현격히 줄어 들긴 하지만 CLIK컴퍼넌트 TextInput이 포커스 처리부분에 좀 에러점을 가지고 있어서 TextInput에서 빠질때에 따른 포커스 처리 정도만 해주면 된다.

두번째는 로드의 주체이다.
개별 로드 방식은 클라이언트가 개별적으로 로드하게 된다.
따라서 클라이언트 주체로 돌아갈 수 있다.
모든것을 클라이언트 시점에서 로드하고 제어할 수 있게 된다.
클라이언트의 개발력이 강한 회사라면 이 점이 크게 강점으로 작용 된다.
또한 클라이언트에서 직접 메소드 호출과 변수 설정이 들어가게 되므로 비교적(?) 빠른 속도를 낼 수 있는 여지가 있다.
무조건 빠르다는 것이 아니라 제작 방식에 따라서 클라이언트에서 대부분의 연산(Display에 관한것 마저)을 하게 된다면 더 빠른 속도를 낼 수 있게 된다.
반대로 따진다면 컨테이너 방식에서는 액션 스크립터의 능력을 요구하게 된다.
대부분의 UI처리 방식이 클라이언트에서 정보가 오면 Scaleform이 이를 처리하는 방식이라서 오픈된 API를 클라이언트에 제공해야 한다.
따라서 액션스크립터는 클라이언트가 제어할 수 있는 API를 제작해야 하는 부담감이 있다.

세번째는 depth 관리이다.
ActionScript 2.0은 절대적은 depth수치를 가지고 있기 때문에 관리하기가 경우에 따라 굉장히 불편할 수도 있다.
컨테이너 방식은 일단 하나의 .swf파일로 시작하기 때문에 순전히 depth관리는 액션스크립터의 몫이다.
개별로드의 경우 사실상 depth관리가 용이하지 못할 수있는데 클라이언트 차원에서 depth를 조절해야 하기 때문이다.
이것이 큰 문제가 될 수 있는 것이 .swf파일간에는 절대로 섞일 수 없다.
어느하나가 위면 위, 아래면 아래가 되기 때문에 섞일수 없는 구조이다.
컨테이너 방식도 마찬가지다.
두가지 방식 모두 레이어가 섞이는 표현을 하기 위해서는 몇가지 꼼수를 써야 하는데 그나마 컨테이너 방식이 용이하다.
나역시 액션스크립터이지만 대부분의 액션스크립터 역시 컨테이너 방식을 택할 것이라 생각한다.

전반적인 관리, 효용성을 따진다면 컨테이너 방식이 현재까지는 적당한 방식이라 생각한다.
하지만 인력의 분포, 이미 진행된 상황, 여건등을 따진다면 어쩔수 없는 선택을 해야만 하는 경우가 분명 있을 것이다.
현재까지 많은 사람들이 선택한 방법은 컨테이너 방식이다.
우리 프로젝트 역시 이러한 방식을 사용 했으며 약간 변형하여 다수의 컨테이너를 기능별로 분리하여 사용하려고 시도하고 있다.
Scaleform의 분야가 아직까지 성숙된 분야가 아니기 때문에 다른 방식이 나온다면 교체되겠지만 현재까지는 가장 안정된 방법이 아닌가 생각한다.

Trackback 0 Comment 0
2011.03.24 10:42

[AIR] 최근에 만들고 있던것

최근 이래저래 해서 바쁜 일도 있었고 개인적으로도 바빠서 블로그에 한동안 신경을 못쓰고 있었습니다.

개인적으로 필요하다고 생각하는 툴을 만들고 있었던 것도 있지요.


아직 완성본은 아니지만 파일전송을 한방에 해주는 프로그램을 만들고 있었습니다.

작업을 하다보면 결과물 파일을 사용처로 복사해야 하는 일이 빈번하게 발생 하는데 매번 일일이 선택하기도 귀찮고 해서 만들게 되었습니다.

AIR2를 사용하였고 특별한 이유는 없지만 native로 뽑아서 exe설치로 뽑아버렸습니다.

트레이 아이콘을 사용하여 불필요한 경우에는 윈도우를 아예 안보이게 해놨습니다.





일단 아이콘은 이렇습니다.

여기저기 떠돌던 아이콘 하나 집어다가 사용하네요..




실행을 하게 되면 위와같이 트레이로 아이콘이 가버립니다.

SystemTrayIcon를 사용한다면 모든 OS에서 하위 트레이 아이콘으로 빼버릴수 있는 것으로 알 수 있습니다.(Mac, linux 포함)

별도의 창은 뜨지 않습니다.




트레이 아이콘에 오른쪽 마우스를 누르게 되면 메뉴가 뜨게 되는데 Preset과 Export, Exit메뉴가 있습니다.

이는 NativeMenu와 NativeMenuItem을 사용하였습니다.

Export에 화살표가 있는 것은 NativeMenuItem 에 subMenu라는 NativeMenu가 또 있는데 이를 생성해 주면 하위로 메뉴를 또 가질 수 있게됩니다.

Preset은 PresetWindow를 띄워서 세팅을 편집할 수 있고 Export는 세팅된 프리셋을 실행하게 되는 것이고, Exit는 종료입니다.




일단 세팅된 프리셋이 없으니 PresetWindow를 띄워 보도록 합니다.

하단부에 프리셋 추가 버튼을 눌러 프리셋을 추가 합니다.




이제 EditWindow가 뜨게 되는데 이는 프리셋을 편집할 수 있습니다.




이름을 정해주게 되는데 이름은 고유한 값이 됩니다.

이름이 겹치게 되면 저장되지 않습니다.

복사될 대상 폴더를 정해주고 복사할 파일 및 폴더를 추가해 줍니다.

체크박스 있는 목록이 폴더 인데 체크가 되어 있다면 하위파일/폴더 까지 모두 복사해 줍니다.

이제 확인을 누르면 프리셋 저장이 끝나게 됩니다.

파일을 선택하는 과정에서는 File 객체를 사용하였으며, FileListEvent.SELECT_MULTIPLE 이벤트와 browseForOpenMultiple()메소드를 사용하면 파일의 복수 선택또한 감지할 수 있습니다.

browseForDirectory()메소드는 폴더 선택 전용 다이얼로그를 띄워주어 목적에 따라서 다양하게 사용할 수 있습니다.





다시 트레이메뉴에서 오른쪽을 누르게 된다면 아까 저장했던 이름이 Export 메뉴에서 뜨게 됩니다.

이제 Export Test라는 메뉴를 누르게 되면 저장했던 파일 및 폴더를 목표 디렉토리로 복사하게 됩니다.





여기서 파일 복사는 FileStream을 사용하려 했으나 생각저럼 잘 진행이 되지 않았고 무엇보다 자세한 전송 현황이 불필요할 것 같아서 사용하지 않았습니다.

File 객체의 copyToAsync 를 사용하여 전체적으로 파일이 몇개나 복사 되었는지 나타내게 됩니다.

copyTo 메소드는 complete 이벤트를 출력하지 않기 때문에 원활한 진행과정 출력에 문제가 있다고 판단하여 비동기적으로 파일을 복사하는 copyToAsync를 사용하여 비동기로 다른프로그램 진행에 방해가 없도록 하며 complete이벤트를 받아 진행 과정을 표시하였습니다.

위의 PresetWidnow와 윈도우 타입이 다른데 이는 NativeWindow를 생성 할 NativeWindowInitOptions 객체에서 type 을 NativeWindowType.UTILITY로 주었기 때문입니다.
기본값은 NORMAL 입니다.




모든 파일복사가 완료 된다면 위와 같이 완료되었다는 메세지가 뜨게 됩니다.

확인을 누르면 정보창이 닫히게 됩니다.




이제 목표로한 디렉토리를 보게 된다면 파일이 복사되었다는 것을 알 수 있습니다.

파일명들은 임의로 가려놨습니다.


전체적으로 아직 세세하게 추가되어야 할 것들이 많다고 생각합니다.

AIR의 자체 업데이트 기능도 추가 해야 할 것 같고 세부적으로 수정되어야 할 버그들도 있는것 같습니다.


'actionscript 3.0' 카테고리의 다른 글

[AIR] 최근에 만들고 있던것  (1) 2011.03.24
[AS3] ConvolutionFilter  (0) 2011.03.02
[AS3] ColorMatrixFilter - 2  (0) 2011.02.08
[AS3] ColorMatrixFilter - 1  (0) 2011.02.08
[AS3] BlendMode  (0) 2011.01.28
[AS3] drawTriangles + bitmap fill  (0) 2011.01.24
Trackback 0 Comment 1
2011.03.14 11:26

[GFx] 스케일폼(ScaleForm) 클라이언트와의 통신법

ScaleForm은 게임 UI 미들웨어로서 임무를 하기 위해서 클라이언트 프로그램과 통신을 해야만 한다.
당연한 소리겠지만 Client -> Scaleform 도 있고 Scaleform -> Client 도 있다.

Scaleform -> Client 를 살펴 보자면 크게 2가지 방법이 있다.
문자열 전달 방식과 DirectAccess 방식이 있다.
문자열 전달 방식은 다시 2개로 나뉘게 되는데 액션 스크립터라면 흔히 알고 있을 fscommand 와 ExternalInterface 이다.
fscommand 는 예전부터 사용해 오던 방식인데 Scaleform 사에서는 별로 추천하지 않는다.
fscommand 는 오직 2개의 String 형태의 파라미터만 보낼 수 있는데 그중 1개는 명령어 이다.
따라서 fscommand 는 단 1개의 String 형태의 파라미터만 보낼 수 있는 것이 된다.
이에 반해 ExternalInterface.call 의 경우 모든 자료형이 다 보내지게 된다.
Class instance역시 보내지게 되어 나중에 설명할 DirectAccess에 사용하기도 한다.
또한 파라미터 수량역시 탄력적으로 사용할 수 있어서 훨씬 유용하다.
하지만 ExternalInterface 역시 String 기반의 명령어 처리이다.
가장 큰 문제점은 엑세스 딜레이가 일어날 수도 있다는 점이다.
ScaleForm 에서와 C++ 클라이언트에서 처리속도는 클라이언트가 빠르게 된다.
그렇기 때문에 ScaleForm에서 ExternalInterface.call 로 이벤트를 날려도 클라이언트에서 받아서 처리할때 딜레이가 생길 여지가 많게 된다.
하지만 우려할 만한 수준은 아니고 좀더 빠른 속도를 원한다면 DirectAccess를 사용하게 된다.

일단 ExternalInterface를 사용한 문자열 전달 방식은 예전 웹 혹은 기타 상황에서 사용하는 방법과 같다.
ExternalInterface.call() 로 외부메소드를 호출하고 ExternalInterface.allCallback()으로 외부에서 들어오는 입력을 받게 된다.
call(), addCallback()은 클래스 위치에 상관없이 어디서나 호출이 가능하며 수신이 가능하다.
하지만 이것은 장점인 동시에 단점이 되는데 이유는 어디서 무엇을 호출하고 어디서 받는지 정확히 모르기 때문이다.
그래서 call()의 경우 아무데서나 호출하더라도 addCallback()의 경우 한 곳에서 받아서 처리하는 방식으로 일단은 사용하고 있다.
물론 싱글톤 형태로 call()을 관리하는 클래스를 만들어 모든 call()을 거쳐가게 하는 것도 좋은 방법이다.

DirectAccess의 개념은 ScaleForm 에서 객체의 포인터를 클라이언트로 넘겨주어 클라이언트는 해당 포인터에 직접적으로 ActionScript의 메소드를 호출 혹은 변수를 수정하는 방법이다.
ScaleForm사에서 적극적으로 추천하는 방법으로 엑세스 속도가 상당히 빠르다고 한다.
하지만 이 방법을 쓰려면 클라이언트에서 플래시 객체의 포인터를 가지고 있어야 하기 때문에 ExternalInterface.call의 파라미터로 객체 포인터를 넘기게 된다.
간단한 사용의 예는 다음과 같다.

var mc:MovieClip = this.attachMovie("MC", "mc", this.getNextHighestDepth());
ExternalInterface.call("MC_Pointer", mc);

정말 간단한 방법으로 넘기게 된다.
어태치한 무비클립인 MC 를 클라이언트로 넘기게 되면 클라이언트에서 해당 "MC_Point"라는 명령을 받아서 같이 온 포인터를 DirectAccess로 사용할 수 있게 되는 것이다.
이때부터 mc 내부의 메소드 혹은 변수들을 사용할 수 있게 된다.
public  과 private에 대한 관계는 아직 명확히 확인하지 않은 상태이다.
- 이전에 Java와의 리모팅 통신하던 시절에는 private 속성까지 다 접근했었던 기억이 있는데 여기서는 안되는듯 하다.
C++ 에서는 명령을 요청하는 방법은 똑같다.
invoke라는 것인데 대상이 어디냐에 따라서 String 방식이 되거나 DirectAccess방식이 되거나 구분된다.
.swf파일을 로드한 기본 객체인 GFxMovieView에 invoke를 하게 된다면 String 방식이 된다.
하지만 포인터로 넘긴 객체인 GFxValue는 .swf파일을 로드한 객체와 다른 타입의 객체인데 이 객체에 invoke를 하게 되면 DirectAccess가 된다.
그렇기 때문에 객체 포인터를 넘길 필요가 있다.

Trackback 0 Comment 0