scaleform.minarto.com

런타임 쿨타임 드로잉 & scaleform4 의 Graphics 본문

Utils & Liblary

런타임 쿨타임 드로잉 & scaleform4 의 Graphics

미나토 2012. 2. 6. 16:20



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. 동시에 같은 모양을 여러군데 그리는 거라면, 드로잉 인스턴스를 하나로 사용하여 실수연산이라도 한번만 하게 만든다.
4. etc... (지금으로선 다른 방법은 떠오르질 않네요...)

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



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