블로그 이미지
플래시로 밥먹고 살고 있습니다... 하지만 여긴 플래시 전문 블로그가 아닌 그냥 개인 블로그랍니다
미나토

Recent Comment

calendar

      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      
  • 56,002total
  • 9today
  • 173yesterday
2012/02/06 16:20 Scaleform



0. 아~ 쿨타임 어려워요


스케일폼 코리아 카페에 들어갔더니, 쿨타임 그리는 것에 대한 질문이 올라왔더군요...

거기에 몇몇 분들의 덧글들이 답변으로 달려있긴 한데...

여기에 대해서 한번 정리해 볼 필요가 있어보여서, 포스팅을 해봅니다...



1. 쿨타임이란?


일반적으로 게임에서 쿨타임이라 하면, 반투명한 사각박스 형태의 그래픽이 시계방향으로 돌면서 없어지는 애니메이션을 말합니다.

물론 애니메이션(혹은 이펙트)에는 수십/수억가지가 존재할 테지만, 그런 것들은 이 포스팅의 목적인 "런타임에 그려보자" 와 무관해지니 논외로 치겠습니다...


뭐, 당연히 삼각함수 알아야 합니다. 그런데 일반적으로 플래시에서 사용하는 cos 과 sin 함수 외에 tan 함수를 써야합니다... 그러니 조금은 각오(?)를 해두시고 시작해보겠습니다.




2. scaleform4 에서의 Graphics


scaleform4 (현재 시점 버전 4.0.15) 에서는 Graphics 의 지원이 좀 제한적입니다.
제한 사항은 다음과 같습니다.

1. Bitmap 그리기 불가
2. Flash Player 9까지의 api만 지원
3. SpreadMethod 의 제한적 지원 (현재로서는 PAD만 지원하는 것으로 확인됨)


drawGraphicsData 메소드를 지원하지 않는다는 얘기입니다. 사실 이 메소드는 사용하는 분들이 별로 없어서 크게 필요할까 싶기도 하지만 그래도 간단히 설명하자면...

graphics.lineTo(0, 0); 
graphics.lineTo(50, 50);  
graphics.lineTo(100, 100);


이런 세개의 명령문이 있다고 치죠. 이것이 렌더링 될 때는 총 3번의 렌더링이 일어나게 됩니다.


var comands:Vector.<int> =  new <int>[2, 2, 2];
var data:Vector.<Number> =  new <Number>[0,0, 50,50, 100,100];
graphics.drawPath( comands,  data);


Flash Player 10 에서 지원하는 api를 활용하면 위와 같이 표현할 수 있습니다. 이렇게 해놓으면 drawPath 의 한순간만 렌더링이 일어나게 됩니다. 아무래도 빨라지겠죠??? (그 외에도 장점이 많지만 오늘 주제와 무관하니 패스~)

뭐, scaleform4에서 지원되지도 않는 녀석을 두고 말이 길어졌네요. (하지만 마지막 결론 단원에서 써먹을 겁니다. 복선이라고 해두죠.)




3. 닥치고 draw


사설이 길었네요. 코드 해설서가 아니니, 풀코드를 공개하지는 않겠습니다. (구글서치를 잘 해보시면 어딘가 제 코드가 숨어있을 지도...)

가장 중요한 이론만 살펴보죠... 구현해야할 메소드 인터페이스는 다음과 같다고 하겠습니다.

drawCoolTime($graphics:Graphics, $width:Number, $height:Number, $rate:Number):void;


시작위치($x:Number, $y:Number)는 이론에 굳이 필요치 않으니 생략하였습니다. $width, $height 는 당연히 사각영역의 크기이고, $rate는 현재 시간의 비율값입니다. 0~1 까지를 인자로 받습니다.
왜 각도나 시간을 받지 않느냐 하시면... 제 취향입니다. 궁금하시면 이 글을 참고해 주세요.


그 다음에는 넓이와 높이의 절반을 구해야 합니다. 이유는 다음의 그림을 보시면 됩니다.



쿨타임이란게 결국 위와 같은 그림을 그려내는 과정입니다. 사각형을 그려내는건 일도 아니죠... 문제는 저 삼각형이 빠지는 영역의 드로잉입니다.
좌측 그림의 빠진 삼각형의 밑변(그림으로는 윗변이라고 해야겠군요)의 넓이를 알아야 하고, 우측 그림에서는 채워진 삼각형의 높이를 알아내야 합니다.


결국 사각영역 내에서 각도에 따른 x, y 값을 알아내는게 핵심입니다.

-90 에서부터 시계바늘이 돌다가(이렇게 표현해두죠) 사각형의 우측 상단의 꼭지점을 넘지 않은 지점이라면 좌측 그림에 해당하는 것이고, 꼭지점을 넘었다면 우측 그림에 해당하는 것이죠.

그럼 꼭지점을 넘은 여부는 그 시계바늘의 길이가 일정하다고 했을 때, 끝이 넓이의 절반을 넘느냐 안넘느냐입니다. 그림을 잘 보시면 알겠지만, 절대 45도가 아닙니다.

시계바늘의 길이가 바로 반지름입니다. 반지름은 다음과 같이 알아내면 됩니다.

hw = $width * 0.5;
hh = $height * 0.5; 

radius = Math.sqrt(hw * hw + hh * hh);
radius = new Point(hw, hh).length;


굳이 직각삼각형의 빗변 길이의 공식은 말씀드리지 않아도 되겠지요???  


우측의 경우부터 보죠....

삼각형의 높이를 모릅니다만, 우리는 넓이를 알고 있습니다. 넓이의 절반이죠... 그리고 각도도 알고 있습니다.
각도와 넓이를 알고 있다? 바로 tan 입니다. tan(Θ) * hw 하면 높이를 알아낼 수 있습니다.


좌측을 볼까요?

우측과는 반대로 넓이를 모릅니다만, 높이를 알고 있습니다. 이번에는 tan 의 역수입니다. 1 / ( tan(Θ) * hh ) 하면 넓이를 알아낼 수 있습니다.


와~ 다 그렸다!!!~~~

여러분은 이제 기쁘게 이 as 파일을 가지고선 팀장님에게 자랑하러 가시면 됩니다.

"제가 해냈습니다. 팀장님!!!"

하지만 만약 제가 팀장이라면 이렇게 말할 겁니다.

"그냥 타임라인에 그려"



4. 브루스 윌리스가 귀신


아... 이건 완전 씩스쎈스 이후로 충격적인 반전입니다. 도대체 어쩌라는거냐...

위와 같은 방법을 이용해서 드로우 함수를 실행시키면 말이죠... 프레임 당 엄청난 실수 연산을 반복해야 합니다. 그것도 하나의 슬롯에서만 도는게 아니라 여러 군데서 동시에 제각각 돌고 있겠죠...

게다가 2번에서 언급했 듯이 scaleform4 에서는 렌더링을 최적화 시킬 10용 api도 지원하지 않습니다. (copyFrom 만 지원해도 좀 꽁수가 있는데 말이죠...)
실수연산 부하 + 렌더링 부하.... 가 매 프레임당 무수하게 일어날 겁니다.

하지만 프레임에다가 미리 그려놓고선 프레임 이동으로 쿨타임을 그린다면, 메모리는 좀 늘지 몰라도...

1. 실수연산을 하지 않는다
2. 한번에 렌더링을 해낸다. (이걸 설명하려고 scaleform4 에서 지원하지도 않는 2번을 저렇게 써댔습니다...)

이런 이득이 생깁니다...



5. 그러나 모두 사랑합시다.


무조건 런타임 드로우를 쓰지 말라는 얘기는 아닙니다. 개발 상황에 따라 런타임 드로잉이 꼭 필요할 수도 있겠죠... 당연한 얘기잖아요

그럴 때는 다음과 같은 방법을 고려하시기 바랍니다.

1. 짝수 렌더링과 같이 렌더링 주기를 조절하여 그리는 방법을 사용하시기 바랍니다.
2. visible = false 로 해두었다가 드로잉이 완료되면 true로 바꾼다.
3. etc... (지금으로선 다른 방법은 떠오르질 않네요...)

적절한 상황에 맞게 적절한 방법을 사용하시는 것이 일을 잘하는 방법이겠죠...



p.s. 그냥 일정한 반지름으로 쭉 돌리고 마스크를 사각형으로 씌우는 방법이 있을 겁니다.
이러면 시각적으로는 원한대로 그려지겠지만, 실제로는 크기가 변경될겁니다.(원만큼의...)
이럴때, 혹시 scale9grid 를 사용했다면, 디스플레이 객체가 마구 변신하는 모습을 보시게 될겁니다...


크리에이티브 커먼즈 라이선스
Creative Commons License
posted by 미나토
2012/01/26 12:48 JavaScript


앞선 포스팅에서 실행 메모리 영역에 대해서 말했습니다... 다른 말로 클로저 영역이라고 합니다.

js

a = function (b){
    var c = 2;

    var d = function (e){
        var f; 
        alert(c);
    }
    d();
}
a();



as2

a = function (b){
    var c = 2;

    var d = function (e){
        var f; 
        trace(c);
    }
    d();
}
a();



이런 함수를 만들면 둘 다 2 가 출력됩니다. alert 함수가 trace 함수로 바꼈을 뿐, 보시다시피 코드는 똑같습니다.

어떻게 2가 출력되었는지 살펴볼까요??

얼핏보면 a 란 함수를 실행하면 a 함수 내부에 선언된 d 함수가 실행됩니다.

d 함수 내부에는 c를 출력하여야 하는데, d 함수 내부에는 어디에도 c라는 변수가 없습니다... 인자에도 없고 함수 내부에 지역변수로 선언되어 있지도 않습니다.
그러면 d 함수가 실행되고 있는 영역인 a 함수를 찾아올라갑니다. 그 안에는 c와 d가 변수로 들어있고, b가 인자로 들어있지요... c를 찾았네요??? c란 변수가 참조하고 있는 2 값을 출력합니다...


d 함수를 실행하는 순간 vm에서는 앞서 말했듯 실행메모리 영역을 만들어냅니다.
e 가 들어오는 arguments 객체가 있고, var 로 선언된 f 가 있습니다. (사실 생략된 this도 설명해야 하는데, 이건 나중에...)
이런 메모리 테이블 공간이 만들어지는겁니다.

마찬가지로 a 함수에도 b로 들어온 arguments 객체가 있고, c, d 로 선언된 지역변수 메모리 테이블이 있겠죠...


어쨌든 d의 메모리 테이블이 만들어지고 나면 이제 한줄씩 한줄씩 작성되어져 있는 구문을 실행하는 겁니다
alert / trace 로 c를 출력해야 하는데 해당 메모리 테이블 공간에 c 가 없습니다...
그러면 이때 해당하는 변수가 정의되지 않았음을 나타내는 undefined 를 출력하는 것이 아니라 함수 d가 실행된 메모리 영역인 a 의 메모리 테이블을 검색합니다

c를 찾았네요? c가 가르키는 값은 2를 출력합니다...

이런 연쇄적으로 연결되는 메모리 영역을 클로저라고 합니다...




그런데 여기서도 없다면?...





참조해볼 사이트

http://js.bsidesoft.com/ 
http://www.diebuster.com/flash/82 
http://blog.naver.com/kjhbond/50129536282


 
참조해볼 서적

javascript.jpg 
http://insightbook.springnote.com/pages/1109998 


js_patterns_cover_small.jpg 
http://insightbook.springnote.com/pages/8500578   
크리에이티브 커먼즈 라이선스
Creative Commons License
posted by 미나토
2012/01/26 12:26 JavaScript


1. js vs as2


앞선 포스팅에서 말했듯 저는 js를 사용해본 적이 거의 없기 때문에 잘 몰랐지만, as2는 사실 js를 그대로 본따 만든 언어입니다...

js의 window 가 바로 as2의 _global 이고, DOM 이 바로 MovieClip, TextField 입니다...

as2에서, new Array 는 가능하되... MovieClip은 new MovieClip 대신 attachMovie 를 써야하는 이유가 여기에 있는 겁니다. DOM 객체를 가져와서 사용할 뿐인거죠... 만들어서 쓰는 것이 아니고요

그러다 보니 as2도 js의 이원화된 메모리 관리를 그대로 따라갑니다...



2. 메모리 이원화

그럼 메모리 이원화에 대해 말해야겠군요...

js는 메모리 관리 영역이 두군데로 나뉩니다. 오브젝트(Object Class 를 말하는게 아닙니다) 영역과 실행 메모리 영역입니다...


프로그래밍을 해서 컴퓨터에서 실행을 하려면, 우리가 작성한 코드는 당연히 컴퓨터의 메모리 어딘가로 올라가야 합니다... 그래야 CPU에서 그걸 가지고 연산을 하겠죠...

우리가 작성한 코드... 그것을 하나의 오브젝트로 보고 js vm 에서 거대한 해시맵에 담아줍니다. 여기까지는 c 와 비슷하다면 비슷할겁니다.(전 c를 한번도 안해봤기 땜시 잘 모르겠지만...)
이것을 오브젝트 메모리 영역이라고 하겠습니다.


그럼 실행 메모리 영역은 무엇이냐...

코드란 것은 결국 동작시키기 위해 작성하는 것... 동작하지도 않을 코드는 존재하지 않겠죠...
앞에서 작성한 코드가 실행될 때... 즉, 함수가 실행될 때 메모리를 js vm에서 메모리를 새롭게 분배해 줍니다...
예를 들어, 함수 내에 var a = 1 라고 지역변수(일단은 이렇게 부르겠습니다)를 선언하면 1 이라는 Number 메모리를 새로 잡아주고 a 라는 변수에 참조시켜주는거죠


여기서 js가 c 같은 언어에 비해 느린 이유가 만들어집니다... c 는 동작시에 사용하게 될 메모리를 미리 개발자가 잡아놔야 합니다. 그러면 컴파일러에 의해 컴파일이 되면서 메모리를 정리(?)해주게 되고, 해당 포인터를 바로 사용하면 됩니다.

하지만 js는 컴파일이 없으니 실행되는 동안  vm이 알아서 그런 일을 다 해줘야 합니다...

게다가 알아서 생성해줬으니 알아서 지워도 줘야겠죠... 안그러면 메모리가 폭발할 테니까요... 바로 gc가 돌아야 합니다...



3. 요약

첫번째니 가볍게 정리를 하겠습니다.

1. as2  js
2. js는 메모리를 두가지로 관리한다. 오브젝트 영역과 실행 메모리 영역




참조해볼 사이트

http://js.bsidesoft.com/ 
http://blog.naver.com/kjhbond/50129536282


 
참조해볼 서적

javascript.jpg 
http://insightbook.springnote.com/pages/1109998 


js_patterns_cover_small.jpg 
http://insightbook.springnote.com/pages/8500578 
크리에이티브 커먼즈 라이선스
Creative Commons License
posted by 미나토
2012/01/26 11:15 JavaScript


아, 이게 말이죠... 사실은 전혀 만들 생각이 없었어요...


글을 쓰는 2012년 1월을 기준으로 약 2년째 웹을 떠나있는 저로서는 사실 실무에서 js를 쓸 일이 전혀 없습니다.... (1년간 인터랙티브 미디어, 나머지는 스케일폼)
앞으로도 당분간은 쓸 예정이 없고요...


그 전에도 js는 ctrl +c, ctrl + v 로 쓰는 정도였을 뿐입니다... 단지 플래시앱의 테스트를 위해서였죠... 언어라는 생각도 하질 않았어요...


그러나 지금 js는 세상을 뒤엎고 있습니다... 구글이나 페북에서는 아이비리그 나온 친구들이 js를 다룹니다... 플래시는 그에 비해 저물어가니 유행을 타서 저도 포스팅을 시작.....한건 절대 아니고요...


작년 말부터 히카님의 지도(스터디이지만 지도라는 말이 어울립니다) 하에 S51 이란 js 스터디를 하고 있는데,
as2 == js 이고,  as3 은 js의 ecmascript3 스펙에 class 문법을 붙인  ecmascript4 스펙인 것을 다시 한번 몸소 깨닫고 있습니다...


스터디는 들은 후에 잊혀지는 법... 이걸 어따 써먹긴 해야겠는데...

같이 스케일폼 스터디를 하는 친구들에게 스케일폼4를 대비해 스케일폼에 맞는 as3 스터디를 시작하기로 했거든요... 그 초입단계로서 as2 와 as3를 좀 가르쳐야겠다고 생각을 했고...
그러면서 자연스레 js 문법을 가르치면 되겠다 싶었습니다...(헌데 문제는 더도 배우고 있는 중이라...)


앞선 두가지의 스터디의 일부로서 좀 정리가 필요하겠다 싶어서 카테고리를 하나 더 만듭니다...


아마도 다른 곳같은 실무에서의 js가 아닌, as2, as3 와 연결된 개념으로서의 포스팅이 될거라고 생각합니다.



 
크리에이티브 커먼즈 라이선스
Creative Commons License
posted by 미나토
2012/01/18 11:22 Scaleform


1. 스케일폼은 플래시와 달라요

플래시 웹앱 환경과 scaleform 의 환경은 상당한 차이가 있습니다...

첫째, http 통신을 할 수가 없다
둘째, 기본적인 키보드와 마우스 왼쪽 버튼 이벤트 말고도 여러 인터랙션이 있다.
세째, 가상폴더에서 실행된다...(udk 기준입니다... 다른 엔진도 그런지는...)...그렇기에 절대 경로를 찾기 어렵다.

이외에도 여러가지 제한이 있고, 반대로 추가적인 기능들이 있지만 일단 이렇습니다...


스케일폼에서 제공하는 scaleform.gfx.* 패키지를 보면 많은 클래스들이 있습니다. 이는 스케일폼의 여러 확장기능들을 이용하게 하기 위한 클래스들입니다.

다른 것은 둘째 치고 일단 Extensions.enabled 함수를 확인하셔야 합니다. (멤버변수가 아닌 set/get 함수입니다)
기본값은 false 이지만 이걸 true로 해두면 위에서 언급한 여러 확장기능들을 사용할 수 있게 됩니다. 



아무튼 위에서 말한대로 스케일폼은 여러 세팅할 값들이 일반적인 플래시앱과는 꽤 다르게 해줘야 합니다

그런 세팅을 해야할 곳은 바로 시작점 클래스 입니다...



2. 시작점 클래스


플래시에서는 시작점 클래스란 것이 있습니다

바로 Document Class 인데, vm이 최초에 실행할 class 를 말하는겁니다.
엄밀히 말하자면 해당 class를 인스턴스로 만들어 stage에 addChild 하는 행위를 말합니다... 그렇게 인스턴스화 되는 과정에서 해당하는 class 의 생성자 함수가 실행되는 것이지요...

시작점 클래스에 관한 포스팅이 아니니, 자세한 내용은  http://www.diebuster.com/flash/98 을 읽어보시기 바랍니다...



3. 본격적으로~

function Main(){
    addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}

function onAddedToStage($e:Event):void{
    removeEventListener(Event.ADDED_TO_STAGE,  onAddedToStage);
}




자, 여기서부터입니다. 우리는  onAddedToStage 를 구현해줘야 하죠... 사실 다른 분들은 생성자 함수부터 많은 세팅들을 하는 경우가 있을겁니다.
뭐, 여러가지 이유가 있지만... 일단 제가 저기서부터 세팅을 시작하는 이유가 있습니다...

스케일폼 UI 개발 특성상 여러개의 swf로 나눠지게 됩니다... 최상위 컨테이너인 Main 에서 여러 인벤토리, 캐릭터 정보창, 상점 등등... 여러 swf를 불러서 사용하는 형태가 되는 것이지요.

툴팁의 컨테이너를 따로 만들 수도 있을 거고, 클라이언트와 통신하는 객체를 따로 만들어 불러들일 수도 있을겁니다...


그럼 제가 인벤토리를 만들고 있는 상황이라면 인벤토리의 Main은 테스트할 때 말고는 실제 구동시에는 Main이 아니라는 뜻입니다... 최상위 컨테이너인 Main에서 부른 형태일테니까요...

자, 그럼 현재의 Main이 진짜 Main인지 아닌지를 판단하는 방법이 필요한데 바로

(stage === this.parent)  로 판단하시면 됩니다...

그럼 다음과 같은 코드가 이어질 겁니다...

if (stage === this.parent) {
    Extensions.enabled = true;
    stage.align = StageAlign.TOP_LEFT;
    stage.scaleMode = StageScaleMode.NO_SCALE; 
}



뭐, 이정도일 겁니다... Extensions.enabled 에 대해서는 처음에 설명했지요???

이 다음 실행될 구문은 바로 

if (stage === this.parent) {
    Extensions.enabled = true;
    stage.align = StageAlign.TOP_LEFT;
    stage.scaleMode = StageScaleMode.NO_SCALE;

    if (Extensions.enabled) {
    }
    else{
    }
}


입니다. 여기서부터가 이제 아스트랄해지는 부분입니다...

바로 앞선 구문에서  Extensions.enabled 에 true 값을 대입연산자인 = 로 줬습니다...
그런데 바로  Extensions.enabled 값이 true 인지를 판단한다라...?

이제  Extensions class를 다시 열어봐야할 시간이 됐습니다.


4.  Extensions class

 // Enable/disable GFx extensions
static public function set enabled(value:Boolean) : void {}
static public function get enabled() : Boolean { return false; }



Extensions class의  enabled 함수가 구현되어 있는 모습입니다... 뭔가 이상하지 않나요??? 보통 set/get 함수를 만들면 다음과 같이 해야 하지 않나요?

static private var _enabled:Boolean = false;

static public function set enabled(value:Boolean) : void {
     _enabled = value;
}
static public function get enabled() : Boolean { return  _enabled ; }



이렇게 말이죠... 그런데 Extensions class 안에는 _enabled 이 없습니다...

이녀석은 바로 scaleform 에 저장되는 값이기 때문입니다.

그렇다면 if (Extensions.enabled) 문의 비밀이 나옵니다.

Extensions.enabled = true;
if (Extensions.enabled) {
    // 이 swf 가 돌아가는 vm은 scaleform 플레이어입니다
}
else{
    // 이 swf 가 돌아가는 vm은 Flash 플레이어입니다
}



이 구문은 현재의 vm을 판단하는 부분입니다... 플래시 플레이어에는 _enabled 값이 저장될 곳이 없으니 언제나 get enabled() 가 false 만을 반환하기 때문이죠...


그런데 여기서 의문이 남습니다... 어차피 scaleform으로 돌릴 것을 만드는데, 왜 flash player 에서 돌리려고 하는건가요???



5. 그러니깐 그게 왜 필요한데... 어따 쓸거냐고...


스케일폼 플레이어는 디버깅에 제한을 받습니다... trace는 찍어주는데 break point 가 안먹어요...(제가 방법을 모르는 것인지는 모르겠습니다만...)

물론 하려고만 하면야 trace만으로도 잘 개발할 수 있습니다만... break point 가 좀 필요할 때가 있는 것도 사실이지요...
바로 디버깅의 편리함을 가져다 주기 위함이예요...

고작 브레이크포인트 디버깅 때문에 코드를 더럽히냐고 하실 수 있지만... 어차피 저 코드는 어떤 상황에서건 최초에 딱 한번만 실행됩니다. 런타임의 실행속도와 무관하지요...

이외에도 뭔가 다른 곳에 필요치 않을까요??? :^)


p.s. 사실 저는 다르게 만들어써요 ㅋㅋㅋ
p.s. 써놓고 보니깐 제목을 vm 판단하기...라고 지을걸 그랬나 싶다는... 이놈의 필력이란...

 
크리에이티브 커먼즈 라이선스
Creative Commons License
posted by 미나토
 <PREV 1 2 3 4 5 ... 54    NEXT>