2003-06-24
베타 테스터로서 플래시 MX를 접하면서부터 우리 팀이 느끼는 건 한마디로 ‘고마움’이었다. 매크로미디어사의 플래시 MX는 우리들이 원해 왔던 바로 그것들을 해 주었기 때문이다.
웹 저작에 있어서 그 어떤 툴보다도 플래시 MX는 우리들에게 강력한 비쥬얼적인 요소를 가진 인터렉티브하고, 동적인 컨텐츠 제작을 가능케 한다. 만약 이 작업에 있어서 플래시MX내에 자체적으로 내장된 컴포넌트를 이용한다면 놀랍도록 빠른 시간 안에 가능해진다. 달라진 작업 인터페이스는 디자이너, 프로그래머, 그리고 애니메이터들이 개인 혹은 팀으로 작업하는 데 있어서 더욱 효율적으로 할 수 있게 하였다. 더욱 강력해진 액션스크립트, JPEG의 로드, 비디오 임포트, MP3 스트리밍, 웹애플리케이션서버 ColdFusion과의 연동 등 새로워진 기능은 수없이 많지만 이 글에서는 우리 팀이 플래시 MX로 제작한 이전 버전에서는 구현 할 수 없었던 몇 가지 사례를 소개하고자 한다.
활용 사례 1: ‘안세병원 예약관리시스템 구축사례’- 빌트 인 컴포넌트
재사용이 가능한 기능을 가지는 무비클립을 만들기 위하여 이전 버전에서는 프로그래머들이 오랜 시간을 투자해야만 했다. 물론 이러한 작업들은 대부분 어려운 일이어서 시간뿐만 아니라 프로그래머로서의 오랜 경험을 요하는 일이었다. 플래시의 내장된 컴포넌트들은 이러한 우리들의 수고를 미리 대신해서 제공해 주었다. 이제 우리는 단지 끌어다 사용하기만 하면 되었다.
‘안세병원 예약관리시스템’은 사용자 인터페이스와 관리자 인터페이스 모두 매크로 미디어 플래시로 구현되었고 서버 사이드는 php와 mysql을 사용하였다.
빨간색 네모부분이 플래시MX에서의 scrollPane 컴포넌트를 사용한 부분이다.
사용방법
scrollPane은 플래시MX안에 있는 컴포넌트 패널에서 드래그하여 스테이지상으로 끌어낸다. property 창에서 간단한 설정을 하게 된다.
1. 인스턴스 네임을 정해준다.(여기서는 "pane"이라는 이름을 사용했다.)
2. scrollPane안에 불러질 무비클립의 linkage ID를 적어준다.("nemo3")
3. 가로 스크롤바/세로스크롤 바 설정을 한다.
컴포넌트를 사용해서 간단하게 스크롤되는 무비를 만들 수 있다.
[소스분석]
안세병원 예약시스템에서 사용된 부분은 의사의 목록을 표시하는 부분으로서 의사는 삭제될 수도 있고 추가될 수도 있다(DB와의 연동을 통해 유기적으로 data가 갱신됨).
즉 scollPane으로 불러지는 무비클립의 크기가 유동적으로 변하게 된다. 그렇게 되면 크기가 고정되어 있는 무비클립의 linkage ID는 쓸 수가 없다.
안세병원 예약시스템에서는 scrollPane에 로드되는 무비클립이 유동적인 크기를 가지고 있는 무비클립을 만들어 사용했다. 이때 scrollPane으로 로드된 무비클립이 인스턴스 네임을 가지고 있지 않기 때문에 다른 계층이나 타임라인과 상호작용을 할 수가 없다.
그렇게 되면 scrollPane으로 라이브러리에 있는 무비를 불러온 후에 scrollPane에 불러진 무비는 다른 타임라인에서 제어할 수가 없게 되는데 다른 타임라인에서 제어하기 위해서는 scrollPane 컴포넌트 내부의 인스턴스 이름을 사용하면 된다.
그래서 scrollPane으로 로드될 무비클립 안에 미리 액션스크립트를 적어주고 scrollPane 에 로드된 무비클립 안에서 의사의 이름이 있는 무비클립을 attachMovie(혹은 duplicate) 하게 된다. (한 개의 scrollPane안에 여러 개의 무비클립을 로드시킬 수 없다. 오직 한 개의 무비클립만 로드시킬 수 있다.)
이때 중요한 것은 그냥 무비클립이 attachMovie가 되면 스크롤바가 생기지 않는다. 반드시 액션스크립트(로드되는 무비클립의 크기가 변한다든지 위치가 변한다든지) 실행 후에는 아래의 refreshPane(); 이라는 메소드를 실행하여 scrollPane를 갱신시켜 주어야 한다.
일반적으로property창에서는 linkage ID만 쓸 수 있지만. Myscrollpane.setScroll Content 이라는 매소드를 사용하게 되면 linkage ID와 무비클립의 인스턴스 네임을 사용할 수 있다.
또한 loadScrollContent라는 매소드를 사용하게 되면 다른 경로나 웹상에 있는 jpg파일이나 swf파일을 로드무비하듯이 scrollPane안으로 불러서 보여줄 수도 있다. (html태그에 ifame과 유사함).
활용사례 2 : 스크래치형 복권
이전 버전까지 플래시를 이용해 스크래치형 복권 게임을 제작하기 위해서는 스크래치 되는 부분을 모두 나누어 버튼으로 만들고 사용자가 버튼으로 드래그 하는 것을 감지하여 보이지 않게 하는 방법을 사용하였다. 이러한 방식은 제작하는데 있어서도 수없이 많은 200~300개의 아주 작은 버튼 무비클립을 조작해야 할 뿐 아니라 사용자도 스크래치를 하는데 있어서 불편함이 있었다.
이 문제를 해결해 주는 플래시 MX의 새로 추가된 기능이 바로 setMask(); 라는 메소드다.
이는 플래시 5.0 까지는 불가능했던, 마스크의 영역을 액션 스크립트만으로 동적으로 변화시키는 것을 가능하게 해준다.
사용자들의 입장에서는 실제로 스크래치를 하는 느낌으로 부드러운 모션이 가능해 졌다.
플래시 5.0에서는 마스크레이어라는 형태로 마스크를 지원했지만, 이 때는 마스크레이어에 놓여있는 무비클립을 스크립트를 사용해 변화시켜줘도 실제로 적용되지 않았다.
물론 트위닝을 사용해 변화를 주는 것은 가능했지만, 이는 어떤 식으로 변화할 지가 제작 단계에서 이미 결정되는 것이고, 사용자와의 상호작용은 불가능했다.
활용사례 3 : RegisterClass
플래시 5.0 때부터 액션스크립트는 객체 지향적인 개념에 기반하여 만들어 졌고, 사용자들이 그것에 대해 잘 인식하지 못할 정도로 구조적으로 잘 짜여졌다. 사용자들이 이런 객체들의 속성들을 어떻게 활용하느냐 하는 것에 관심을 가지게끔 하였고 사실 그것들만 잘 활용해도 부족함이 거의 없었다. 스크립터들은 약간의 기능 향상이나 자주 쓰는 루틴에 대한 재사용의 목적으로 이미 정의되어 있는 객체들에 속성을 추가하는 경우는 많았지만 (주로 Movieclip, Array, String 객체) 사용자가 객체를 직접 만들 필요성을 거의 느끼지 못했으며 버전 5.0에서는 이런 것들을 만들어도 실무에 응용하기가 쉽지 않았는데 그 이유는 사용자 정의 객체는 무비클립을 정의한 것이 아니라는 것이었다. 대부분의 경우 액션 스크립트는 무비클립을 제어하는 데에 관심이 있고 또 그것이 하나의 목적이다. 사용자가 정의한 클래스는 단지 새로운 객체 정의일 뿐 그 인스턴스 자체가 무비클립이 될 수는 없었다. 예를 들어 눈에 익숙한 클래스 정의 예제 예제를 보면,
function Ball (radius, color)
{
this.radius = radius;
this.color = color;
this.GetArea = function()
{
return Math.PI * this.radius * this.radius;
};
}
Ball 인스턴스를 만들어 낼 수 있는 클래스를 정의하였다. 두 개의 데이터 멤버와 하나의 메소드로 구성되어 있다. Ball 객체를 만들고 체적을 구해 보자.
myBall = new Ball(10, “white”);
area = myBall.GetArea();
area에는 기대했던 대로 myBall의 체적이 계산되어 들어갈 것이다.
이런 코드가 필요한 곳은 아마도 실제 공 그림을 무비클립으로 만들고 그 무비클립을 이것저것 제어하는 가운데 (예를 들어 공이 지면에서 막 튀게 하거나 곡선으로 날아가는 등) 공의 체적을 구하고 싶을 때일 것이다. 위의 myBall 과 무비클립으로 존재하는 공의 인스턴스와는 완전히 별개이다. 개념으로 존재하는 공을 튀게 할 수는 없다. 이게 문제였다( 예를 들어 위의 Ball 클래스의 인스턴스를 만들어 그것을 무비클립처럼 쓰기 위해 메소드에서 _x, _width같은 속성을 참조해도 무시될 것이다. 이는 무비클립만이 가지는 속성이기 때문이다). 개념만으로 존재하는 클래스를 무비클립과 어떻게 연관지을 것인가.. 무비클립인 공은 이미 하나의 객체(Movieclip 클래스에서 인스턴스화됨) 이다. 이것을 다시 Ball이라는 클래스를 정의하여 이것과 연관시킬 필요가 없다.(5.0 버전에서는 그렇게라도 하여 클래스 정의를 이용해 보고 싶었다. 어떤 경우는 아예 위의 생성자 함수를 Movieclip 객체의 속성으로 엇비슷하게 정의하여 개념과 실체의 한계를 극복하려 했지만 상속, 함수 재생등에 문제가 많았다)
이번에 MX버전에서 추가된 기능인 registerClass 는 이런 문제점을 보완하여 객체지향 프로그래밍에 더 가깝게 다가갈 수 있게 되었다.
이 메소드는 최상위 객체인 Object 객체의 속성이다. 플래시의 모든 객체는 Object 객체로부터 파생되었다. 따라서 특정무비클립을 스크립트로 정의한 새로운 클래스에 등록시키고 이를 Object 클래스에 등록시킨다는 의미로 생각하면 될 듯하다.
Object.registerClass (symbol_ID, theClass)
Symbol_ID는 라이브러리에 있는 무비클립의 linkage 이름이다(다른 내장 클래스 식별자를 써도 되지만(Array, String…) 무비클립일 때 만큼 의미가 크지 않고 5.0 버전에서 다른 방법으로 비슷하게 할 수 있었다 ).
theClass 는 위의 예인 Ball 클래스 정의처럼 클래스 이름이다. 무비클립과 사용자가 정의한 클래스를 연관 지어줄 것처럼 보인다. 실제로 그렇다. 개념(위에서 사용자가 에디터에 기술한 클래스 정의)과 실체(실제 그림인 무비클립)를 연관지어 준다. 스크립트로 정의한 클래스가 이름만 가지고 존재하는 무비클립과 결합하여 하나의 새로운 클래스 정의가 된다. 이것은 이미 무비클립이기 때문에 그것의 인스턴스를 만들어 그것을 실제로 제어하기 위한 _x, _width 같은 무비클립의 속성들과 startDrag(), attachMovie() 등의 메소드를 쓸 수 있고(물론 이것들은 자기 자신인 this를 참조할 때 의미가 있다) 스크립트에 추가적으로 정의한 속성들을 쓸 수 있다. 5 버전에서 무비클립에 새로운 속성을 추가 하기 위해 많이 쓰던 방법과 개념상 비슷해 보인다 (예를 들어 무비클립을 흔들리게 하기위한 메소드를 정의한다면 Movieclip.prototype.shakeClip = function(ratio) { … }; ). 하지만 이는 모든 무비클립들에게 적용되기 때문에 어떤 무비클립이 이 메소드를 사용하는지 눈으로 보기에 명확하지 않다. RegisterClass를 이용한 방법은 오직 지정한 그 무비클립의 인스턴스에서만 쓸 수 있는 속성을 정의하는 것이다. 무엇보다 중요한 것은 이미 말했듯이 개념을 실체화 하는 방법을 제공했다는 것이다. 이 객체의 인스턴스는 물론 new 연산자로 생성할 수는 없다. 또한 우리가 정의한 생성자 함수에 파라미터를 전달할 수 없다. 초기화는 다른 메소드를 정의하면 된다. 미리 정의한 클래스와 linkage name을 연결해준 후 우리가 일반 무비클립의 인스턴스를 만드는 것과 마찬가지로 attachMovie나 duplicateMovieClip으로 인스턴스를 만들 수 있다. 무비가 플레이 된 후 동적으로 생성된 무비클립에만 작용한다.(duplicateMovieClip 을 위해 오서링시 인스턴스화한 무비클립에는 작동 안함)
위의 Ball 클래스에 적용해 보자. 지금 라이브러리에 MC_ball이라는 linkage 이름을 가진 무비클립 심볼이 있다고 하자. Ball의 생성자 함수가 파라미터를 받을 수 없는 관계로 초기화 하는 메소드를 따로 두었다. Move()에는 _x, _y를 this로 참조하였고 Ball의 prototype의 속성으로 직접 정의하였다(어떤 면에서는 더 나은 방법일지도 모르겠다) Check_mouse()에서는 마우스와의 충돌 감지를 위해 무비클립의 메소드인 hitTest()를 역시 this로 참조하였다(여기서의 this는 경로를 나타내는 this의 의미가 아니라 자신의 인스턴스를 포인트한다는 의미이다). 주의할 것은 registerClass로 사용자 정의 클래스와 연결된 무비클립의 인스턴스는 무비클립의 속성을 상속받지 않는다는 것인데 hitTest()같은 메소드를 쓰기 위해서는 Ball 클래스가 무비클립의 속성을 대신 상속받아야 한다. 이를 위해 클래스간 상속의 일반적인 방법으로 Ball 클래스의 prototype 객체를 무비클립(super class)의 인스턴스로 바꿔준다.
function Ball ()
{
this.radius = radius;
this.color = color;
this.Set_Init = function(radius, color) {
this.radius = radius;
this.color = color;
};
this.GetArea = function() {
return Math.PI * this.radius * this.radius;
};
this.Check_mouse = function() {
if(this.hitTest(_root._xmouse, _root._ymouse)){
trace("hit");
}
};
}
Ball.prototype = new MovieClip(); //무비클립의 속성 상속
Ball.prototype.Move = function() { //생성자 밖에서 다른 방법으로 정의된 메소드
this._x = this._y = 200;
};
if(!(success = Object.registerClass("MC_ball", Ball))) { //클래스 등록
trace("register failed");
}
this.attachMovie(“MC_ball”, “newBall”, depth); //attachMovie 에 의한 인스턴스 생성
//ball1.duplicateMovieClip(“newBall”, depth); //duplicateMovieClip에 의한 방법
//ball1이라는 인스턴스네임을 가진 무비클립을 오서링시 꺼내 놨다고 가정했을 때
newBall.Set_Init(10, “white”); //초기값 설정
newBall.GetArea();
newBall.Move();
좀더 구체적이고 실용적인 경우는 무비가 플래이 된 후 계속적으로 새로운 유닛들이 생성되고 그 유닛들이 가져야 할 속성들을 정의해야 하는 경우일 것이다. 유닛이 사람이라면 좌표, 화력, 에너지, 아이템 등의 속성과 Attack(), Move(), Damaged(), Change_Item() 등의 동작을 무비클립의 속성을 이용하여 정의할 수 있을 것이다. 자신이 할 일을 자신에서 정의하고 또 잘 알고 있기 때문에 프로그래밍도 합리적이고 수월해진다. 동작을 시키면 자기 자신(this)을 참조하여 알아서 하게 될 것이다. 또한 유닛들의 구조가 계층적이라면 플래시 MX에서 지원되는 상속이나 메소드 재생을 이용해 더 나은 프로그래밍을 할 수도 있을 것이다. 다음은 Object.registerClass의 이런 이점을 살려 만든 예제이다. 무비에서 겉으로 드러나지는 않지만 코딩에서는 정말 수월하고 간결해진다.