영문 기사 - Adobe Vs. Unity: The Future Of 3D Web Games

(왠만하면 꼭 한번 읽어보세요 ㅋ)

이 기사는 Unity의 관점에서 쓰여진 글인것 같습니다.

글을 읽어보면 주구장창 Unity CEO 이야기만 인용되고 약간 편중된 기사라고 보이는데요

제가 전해드리고 싶은건

댓글중에 공유할만한 내용이 있어서입니다.

Chris Kaitila의 댓글 원문보기

글의 내용은 이렇습니다.

Chris Kaitila -

유니티는 언리얼 엔진같은 "게임엔진"인 반면에 몰힐은 로우 레벨 API입니다. 두 개는 완전히 다른 종류며 아마 경쟁자체도 무의미할 수 있습니다. 유저들이 아무리 왈가왈부해도 결론은 나지 않을 겁니다. 왜냐면 두 제품은 완전히 다른 유저층을 겨냥하고 있기 때문입니다.

몰힐은 vertext와 fragment shader로 이뤄진 완전 Low-level 엔진입니다. 때문에 CPU를 거의 사용하지 않는 엄청난 퍼포먼스를 보여줍니다. 반면에 유니티는 클릭만으로도 게임을 만들 수 있는 High-level의 "게임엔진"입니다. 코드 기반의 하드 개발자에게는 몰힐이 더 낫겠죠.

플래시 몰힐은 다운로드같은건 필요 없이 구동될 겁니다. 안드로이드, 티비, 넷북, 데스크탑, 맥에서 말이죠. 반면 유니티는 소수의 하드 게이머들을 위한 맞춤 기술이 될 겁니다. 여러분의 어머니가 갖고 있는 컴퓨터에 플래시는 설치되어 있어도 유니티는 설치되어 있지 않을 것입니다. 아마 관리자 승인까지 얻어가면서 유니티는 설치되지 않을수도 있지만 플래시는 이미 깔려있다는 얘기죠.

유니티는 완전 하드코어 게임에 적합할 것이고 플래시는 캐쥬얼 게임 시장에 퍼질 것입니다.

마지막으로 몰힐은 공짜(로열티도 구입비도 결과물에 로고도 없습니다)입니다. Flex를 사용하던 Flash Develop을 사용하던 Haxe를 사용해서 컴파일을 하던 Flash CS6를 사지 않아도 공짜입니다.

무료와 백만원단위의 풀버전(또는 시작시 배너가 걸리는 무료버전)을 놓고 봤을 땐 당연히 몰힐이 선호될 것은 분명합니다.

그러나 유니티는 몇가지 유리한 점이 있습니다. 몰힐로 개발하려면 모든 걸 직접 다 만들어야합니다. (물리엔진, 파티클 시스템, 충돌체크등) 반면에 비개발자도 개발할 수 있도록 많은 기능들이 이미 유니티에서는 지원이 됩니다.

몰힐로 개발하기 위해서는 굉장히 많은 것들을 공부해야합니다. 하지만 유니티로 개발하려면 마우스 클릭만 할 줄 알면 됩니다. 몰힐은 설치가 필요없는 무료여서 유니티를 대체제가 될 수도 있습니다.

하지만 확실히 할 것은 이 제품들은 전혀 다른 유저층을 겨냥하고 있기 때문에 전혀 경쟁이 없을 수도 있다는 것입니다. 두 기술이 모두 존재하고 성공하기에는 충분히 큰 시장이라는거죠.

핵심을 정말 잘 잡은 것 같습니다.

유저층이 다르다는 게 전제조건인 것에 매우 동감하고

플래시의 장점 유니티의 장점(안해봤지만 ㅋ)을 잘 정리한 것 같습니다.

하지만 한가지 간과한게 있다면

플래시에도 이미 Box2D나 ND2D처럼 공개된 프레임웍이 많이 나오고 잇고

편한 프레임웍이 잔뜩 벼르고 있는 상황이라

(심지어는 C의 라이브러리를 픽셀벤더로 통채로 쓰기도 하죠)

Chris의 예상보다는 진통이 덜 할거라는 생각입니다.



여러분은 어떻게 생각하세요?

아마 Flash를 오래 하신분들은 한번쯤 들어봤지만 지금은 다들 잊고 계실만한 메소드가 있습니다.

바로 flash.utils.describeType 이라는 클래스인데요.

객체를 넘겨주면 그 객체의 정보를 자세하게 파악해서 XML로 돌려주는 메소드입니다.

"어따 쓸까"하고 묻어뒀던 메소드인데

오늘 의외의 쓰임새를 알아냈습니다.



먼저 몸을 먼저 풀어보죠.

var mcClass: Class = Object( mc ).constructor;

trace( mcClass ); // [class MovieClip]

var mc2: MovieClip = new mcClass();

trace( mc2 ); // [object MovieClip]

이라는 코드가 있습니다.

mc라는 instance에서 flash.display.MovieCilp 이라는 Class를 가져오는 방법은 뭘까요?

var mcClass: Class = Object( mc ).constructor;

trace( mcClass ); // [class MovieClip]

var mc2: MovieClip = new mcClass();

trace( mc2 ); // [object MovieClip]

위와 같이 할 수 있겠죠.

이 방법이 instance로부터 class를 가져오는 방법입니다.



하지만 이것도 가능할까요?

먼저 A라는 class가 있습니다.

package
{
     import flash.display.MovieClip;

     public class A
     {
          public var mc: MovieClip = null;

          public function A()
          {

          }
     }
}

이 A라는 class에는 mc 라는 property가 있습니다.

만약 A.mc 가 객체로 들어있는 상태라면 문제가 없겠지만

아직 선언을 하지 않은 상태라면 mc는 현재 값이 null이라서

constructor를 가져올 수 없는 상태입니다.

이때는 어떻게 해야할까요?

이때 쓸 수 있는게 바로 describeType() 메소드입니다.

파라미터로 넘겨진 class나 instance의 구조를 샅샅히 뒤져줍니다.



테스트를 한번 해볼까요?

위에서 만든 A라는 class를 한번 돌려보겠습니다.

trace( describeType( A ).toXMLString() );


직접 해보실분들은 describeType( MovieClip ) 해주셔도 됩니다.

결과는 다음과 같죠.

<type name="A" base="Class" isDynamic="true" isFinal="true" isStatic="true">
  <extendsClass type="Class"/>
  <extendsClass type="Object"/>
  <accessor name="prototype" access="readonly" type="*" declaredBy="Class"/>
  <factory type="A">
    <extendsClass type="Object"/>
    <variable name="mc" type="flash.display::MovieClip"/>
  </factory>
</type>

장난 아니죠.

클래스를 샅샅히 살펴줍니다.

여기에 보면 <factory> 노드가 바로 class의 내용입니다.

여기에 보면 <variable> 이라는 노드가 보이죠.

여기에 @type을 보면 이쁘게 적혀있습니다.

이것을 응용하면 됩니다.



하지만 중요한게 property는 <variable> 노드로 나오지만

getter의 경우는 <accessor> 노드로 나옵니다.

여기서 끝이 아닙니다.

class의 경우는 <factory> 노드로 되어 있지만

instance의 경우에는 그렇지 않습니다.



간단하게 A 라는 class를 넘긴다고 가정하고 예제를 만들어보자면

다음과 같습니다.

trace( describeType( A ).factory.variable.( @name == "mc" ).@type.toString() );

복잡하지요?

풀어보자면 이렇습니다.

trace( describeType( A ).
factory. // factory 노드중에
variable. // variable 노드중에
( @name == "mc" ). // attribute가 "mc"인 녀석의
@type.toString() ); // "type" 이라는 attribute 값을 toString()

입니다.

이 기능을 메소드화 시키려면

class인지 instance인지 구분해야하고

accessor인지 variable인지 구분해야합니다.

이 모든걸 적용해서 메소드를 만들면 다음과 같습니다.

package
{
     import flash.utils.describeType;
     import flash.system.ApplicationDomain;

     public function getClassOfProperty( $instance: *, $propertyName: String ): Class
     {
          var describedXML: XML = describeType( $instance );

          if( $instance is Class )
               describedXML = describeType( $instance ).factory[ 0 ];

          var propertyClassName: String = describedXML.variable.( @name == $propertyName ).@type.toString().replace( "::", "." );

          if( propertyClassName == null )
               propertyClassName = describeType( $instance ).accessor.( @name == $propertyName ).@type.toString().replace( "::", "." );

          var propertyClass: Class = Class( ApplicationDomain.currentDomain.getDefinition( propertyClassName ) );

          return propertyClass;
     }
}


좀 복잡하지만 결과는 깔끔하게 class로 뽑아줍니다.



예제와 소스 첨부합니다.

getClassOfProperty 유틸 [ 다운 받기 ]





For the Better.
플래시로 개발하기 시작하면서 이태까지 경험하면서

실제로 책이나 블로그에서는 잘 가르쳐주지 않는 사실들을 가끔 깨달을 때가 있다.

그중에서도 내가 가장 크게 깨달았고

플래시 프로그래밍을 공부하는 분들께 도움이 되었으면 하는 바람에서

몇 가지 숨겨져있는 사실들을 이야기해보겠다.



1. 클래스는 대부분 재사용되지 않는다.

OOP가 플래시에서도 뜨거운 감자로써

기본 소양처럼 널리 공부되고 있다.

OOP의 원칙은 두 가지.

바로 재사용성과 확장성.

하지만 실제로 플래시 개발이 고도화되고 복잡해질수록

클래스가 재사용되는 일은 매우 드물다.

오히려 프레임웍으로 만들어 프레임웍 자체가 재사용되면 되었을까

프로젝트에서 만들어진 클래스의 대부분(특히 UI관련)을 재사용되지 않는다.

클래스를 만들때는 각종 OOP기법과 디자인 패턴을 적용하여

최대한 재사용되고 확장될 수 있도록 만들려고 애를 쓴다.

하지만 정작 새로운 프로젝트와 새로운 모듈을 만들때는

그 프로젝트만의 특성이 있기 때문에 결국 새로운 클래스를 만들게 된다.

재사용되는 클래스는 완전 프로젝트와 분리될 수 있는 각종로더나 문자열 관련 유틸, 숫자 연산같은

유틸성이 대부분이다.

프로젝트를 진행하면서 앞으로도 재사용될 수 있는 클래스를 바로 바로 만든다는 것은

경력 8, 9년차정도 되어야 가능한 일이라고 본다.

프로젝트를 진행하면서 클래스를 재사용하려고 너무 시간을 허비하는 것 보다

일단 어떻게든 돌아가게 개발하고 그것을 리팩토링하는게 5배이상 프로그래밍 실력 향상에 도움이 되리라 믿는다.

Do First, then Fix After.

먼저 어떻게든 돌아가는 프로그램을 짜고

마음에 안들거나 바꿔야하는 부분이 생기면 그때 바꾸는게 훨씬 효율적이며

결과적으로도 더 깔끔한 컴퍼넌트가 나오는 걸 경험할 수 있다.



2. 디자인 패턴은 약보다 독이 될 경우가 훨씬 더 많다.

미친 소리로 들릴 수도 있겠지만

디자인 패턴은 실제로 경력 4, 5년차 미만의 플래시 개발자의 경우

득보다 독이 되는 경우가 훨씬 많다.

디자인 패턴은 어떤 패턴 한 두개가 핵심이 되는게 아니라

아키텍쳐의 한 부분을 가지를 쳐내다보면 디자인 패턴으로 보이는것이지

디자인 패턴이 모여서 아키텍쳐가 되는게 절대 아니다.

디자인 패턴이라는 개념 자체가

굉장히 많은 프로그래밍 경험을 토대로

이런 이런 상황에서는 이런 이런 식으로 해서 쓰니까 좋"더라"라는

경험의 축적으로부터 나온 것이기 때문에

그 경험이 충분치 않은 개발자들에게 디자인 패턴은

초등학생에게 철학을 가르치는 것과 마찬가지다.

디자인 패턴을 공부하고나서 중독증상으로

자기 앞의 모든 코드를 모두 패턴이라는 이름하에서 코딩하려고 하는 디자인 패턴 초입자들은

대부분 자기가 원래 개발할 수 있는 시간보다

세배 네배, 심지어는 아예 개발을 못하고 멈춰버리는 수가 많다.

프로그래밍은 코드 자체가 의미있는게 아니다.

프로그래밍은 만들고자하는 것을 쉽게 만들어주는 도구이지

코드를 얼마나 이쁘게 짜는지가 프로그래밍이 아니라는 뜻이다.

까짓거 한글 변수면 어떻고, 4중 for문이면 뭐 어떻나...

for 문 좀 많이 썼다고 프로젝트가 망하는거 아니다.

디자인 패턴은 무의식중에 코드를 무지막지하게 써내려가다가

손끝에서 알아서 나올때 그게 유용한 디자인 패턴인 것이다.

이 모든 사설을 다 빼고 이렇게 한 문장으로 말할 수 있을것이다.

"디자인 패턴은 공부하지 않아도 경력이 쌓이면 알아서 익혀지게되는 것들이다."



3. Flash는 느리지 않다.

HTML5가 이끈 퍼포먼스에 대한 Flash 이슈들에 대해서 많이들 들어봤을 것이다.

"Flash is sucks"라는 말까지 듣는 상황이다.

플래시가 느리다는 대부분의 이유는 바로

대부분의 플래시는 Display 관련 처리가 많고

거기다가 엉망으로 짠 플래시들은 대부분 이미지를 대량으로 최적화 없이 싣고 있기 때문이다.

사실 enterFrame이나 single-thread 여서 느린것도 있다.

하지만 "대부분"의 경우에는 이미지를 무지막지하게 쓰거나 벡터나 동영상들을

최적화 없이 마구 돌리기 때문이다.

실제로 Flash는 virtual machine 위에서 돌아가기 때문에

기본 연산이나 반복문, 바이너리 처리는 굉장히 빠른편이다.

물론 C나 Java에 비할바는 아니겠지만

적어도 Flash is Sucks라는 말을 들을 정도까진 아니다.

HTML이나 Javascript는 아예 비교할 가치도 없을 뿐더러 ShockWave나 Unity(3D기능 빼고 ㅋ)에 비해서

결코 뒤지는 퍼포먼스가 아니라는 이야기다.

int 대신 Number를 쓰면 메모리 많이 먹는다고 걱정하거나

클래스가 너무 많아서 고민이라거나

이미 로드된 swf를 사용하지 않으면 어떻게 unload 해야할지 발을 동동구르거나

하는 걱정들은 솔직히 프로젝트에 아무 영향 없을 때가 훨씬 많다. (사실 대부분이다.)

for 문이나 메모리 때문에 플래시 개발이 막히는 경우는 거의 없다.

게임이나 모바일, 미디어 관련 프로젝트에는 중요하겠지만

게임도 대부분의 미니게임에서는 메모리나 for 문 한두개, 클래스 1, 200개 정도로 문제가 되진 않는다.

Flash는 여러분의 생각보다 충분히 빠르며

이 역시도 마찬가지로 일단

Do First, then Fix After, 일단 만들어보고 문제가 된다면 그때 고쳐도 충분하다.



4. Frame Script는 의외로 좋다.

ActionScript 3.0이 나오고 나서

Frame Script가 죄악시되는데

Frame Script는 fla안에 코드가 있어서

UI와 개발이 분리되는 개발환경일 때 코드가 일원화 되어 있지 않다는 문제가 있을 뿐이지

Frame Script가 느리거나 절대 쓰면 안되는 그런 죄악은 아니다.

프로그래밍이라는 의미자체가

반복작업을 줄여주고 인간의 사고를 최대한 효율적으로 기계어로 풀어내는 것일진데

UI에 붙어있는 짧은 코드 한줄은

클래스 수십개를 능가하는 효율을 발휘할 때가 있다.

가령 예를 들자면

마지막 프레임에 넣어놓은 stop() 구문을 굳이 따로 개발한다면

어떻게 개발할건가?

솔직히 난 Frame Script를 쓰지 않고는 잘 방법이 떠오르지 않는다.

this.addFrameScript( stop, this.totalFrames - 1 ); 이거 말고는 생각이 나지 않는다.

적절히, 다른 클래스들에게 영향을 끼치지 않는 한에서는

Frame Script는 개발 편의성 측면에서 한 점의 화룡정점이 될 수 있다는 것을 잊지 않았으면 한다.



5. Event 구조는 매우 안좋은 기능이다.

특히 Display List에서 Dispatch - Listen 구조는

정말 최악중에 최악이다.

Event의 장점은 단 하나다.

SRP - Single Responsibility Principle

바로 클래스를 캡슐화하는데 있어서 내부의 상황을 바깥으로 알리는데 드러내지 않고 구현할 수 있기 때문이다.

하지만 Display List에서의 이벤트는 너무 느리다.

특히 child 구조가 복잡해질수록 event의 전달과정은 느리기 짝이 없다.

그중에서도 가장 나쁜 이벤트 방식은

내부에서 이벤트를 받아다가 다른 이벤트를 새로 작성해서 바깥으로 보내는 경우다.

btn.addEventListener( "click", clickListener );

function clickListener( $e: MouseEvent ): void
{
    this.dispatchEvent( new Event( "merong" ) );
}

Display List에서 마우스 이벤트는 전달되는 과정이 생각보다 매우 복잡해서

메모리 뿐만 아니라 속도도 매우 느리다.

이는 작은 프로젝트에선 모르다가 이벤트를 맹신하고 마음놓고 쓰기 시작하면서부터 경험할 수 있는데

이를 경험하고 나서 부터는 반드시 필요한 때가 아니면

주로 callback 방식으로 바꿔서 쓰고 있다.

Event는 클래스를 캡슐화하는데 있어서 탁월한 기능이 있지만

Display List 구조에서는 생각보다 굉장히 느리다는 단점이 있다는 것을 반드시 기억해야한다.



블로그에 포스팅하면서 처음쓰는 네거티브한 내용의 글인것 같은데

그만큼 너무 부풀어 있는 거품을 좀 걷어내어야 할 필요성을 느꼈고

실제로 크고 작은 개발을 해보면서 느낀 바를 옮겨적어보았다.

옳다 그렇다의 이분법적인 이야기를 하려하기보다는

책이나 포스팅에서 너무 이론적인 접근만 하는

공부보다 실제 개발을 할 때 도움이 되었으면 하는 이야기들이라고 생각했다.

혹시 다른 생각을 가진 분이 계시면 꼭 댓글을 달아주었으면 한다.

:D

+ Recent posts