Adobe AIR2011.04.24 19:34

 얼마 전에 Adobe AIR 기반으로 다음 뮤직의 음원을 다운받는 어플리케이션을 개발했습니다. AIR 기반으로 어플리케이션을 개발한다는것 이 많은 사례를 가지고 있지 않았고 국내에는 2권 정도의 AIR 개발 서적밖에 존재 하지 않아 구글링에만 의존해서 여러가지로 고생을 했습니다. 


  지금부터 작성할 포스팅은 제목 그대로 AIR 개발을 하기 전에 알아 두면 좋은 것들입니다. 제가 몰라서 실수 했던 것들은 정리 한다는 의미가 더 크니 읽기 전에 참고 하세요.


 AIR 기반으로 개발한다는것은 사용자 컴퓨터에 설치 후에 실행되는 어플리케이션을 만드는 것 입니다. Flash Player 기반은 주로 웹에 올려져서 사용되고 브라우저 라는 종속된 공간 안에서 실행 되는 것이기 때문에 사용자에게 영향을 미치는 범위가 AIR 에 비해 작습니다. 그래서 AIR 개발시에는 Flash Player 기반으로 개발 할 때는 하지 않았던 Applications & Installer Setting 작업을 하게 됩니다. 이번 포스팅에는 Application Setting 에 대해 다루겠습니다. 


 Flash IDE 나 Flex/Flash Builder 를 보면 어플리케이션과 설치할때 사용되는 인스톨러를 셋팅하는 패널이 있습니다. 이 패널 셋팅을 통해 기본적인 내용과 세부적인 내용을 셋팅 합니다. Flash IDE 에서는 위의 패널을 통해 셋팅을 하고 어플리케이션이 컴파일 될때 -app.xml 파일에 해당 내용이 포함되어 컴파일 됩니다. Flash Builder 에서는 -app.xml 파일을 직접 셋팅해서 어플리케이션과 인스톨러를 셋팅합니다. 셋팅된 내용들은 결과 적으로 -app.xml 파일로 작성 되는데 기본적인 내용들은 다음과 같습니다.




	AirTest
	AirTest
	AirTest
	v1
	
	


-app.xml 이 많은 설정 값을 가지고 있기 때문에 모든 노드에 대해 설명하는건 의미 없을것 같고, 주의 해서 봐야할 부분은 다음과 같습니다.


1. <id></id>

어플리케이션의 고유 이름이다. 다른 어플리케이션과 겹치게 하면 절대로 안되며, 고유성을 유지 해야 한다. 배포시 변경했을 경우 새로운 어플리케이션으로 인식 되므로 업데이트가 안된다. 브라우저에서 어플리케이션을 실행 시킬때도 이 id 값을 이용한다.


trace(NativeApplication.nativeApplication.applicationID);


2. <version></version>

어플리케이션의 버전이다. 어플리케이션을 업데이트 할때 사용되며, 설치 파일을 생성할 당시 설정한 Version 과 Updater 클래스를 이용하여 업데이트 할때 전달하는 버전 정보가 다를때 업데이트를 실패 한다.


var descriptor:XML = NativeApplication.nativeApplication.applicationDescriptor;
var air:Namespace = descriptor.namespaceDeclarations()[0];
var currentVersion:String = descriptor.air::version;


3. <programMenuFolder></programMenuFolder>

프로그램 메뉴 설정 옵션이고 아래는 Daum 뮤직 다운로드 매니저를 <programMenuFolder>Daum</programMenuFolder> 에 설정한 화면이다.



4. <installFolder></installFolder>

기본 설치 폴더를 설정하는 옵션이다. 아래는 Daum 뮤직 다운로드 매니저를 <installFolder>Daum</installFolder> 에 설정한 화면이다.



 다음으로 다룰 내용은 어플리케이션 인증에 관한 부분입니다. AIR 기반의 어플리케이션은 사용자 컴퓨터에 설치 되고 악의적으로 사용자의 컴퓨터를 조작할 수 있는 기능들을 가질수 있기 때문에 사용자로 하여금 설치 전에 해당 어플리케이션이 안전한가를 인증서를 통해 입증 하는 것 입니다. 아래는 인증서 설정 탭 입니다.



 인증서는 어플리케이션 설치 파일을 만들때만 사용됩니다. 이 인증서는 설치 파일이 배포된 후에 어플리케이션을 배포한 사람 외의 개발자가 어플리케이션을 임의로 수정하여 배포 하는 것도 방지해 줍니다. 실제로 AIR 개발 결과물인 .air 파일은 .zip 파일로 확장자만 바꾼다면 그 안에 포함되어 있는 .swf 파일 등을 볼수 있기 때문에 이 설치 파일을 임의로 변경 한다면 파일이 손상되어 어플리케이션이 설치 될 수 없다는 에러 메시지가 나타나게 됩니다.




인증서 발급 기관

VeriSign ( http://www.versign.com )

thawte ( http://www.thawte.com ) 


인증서가 없어도 개발자가 본인의 인증서를 만들어 사용할 수 있습니다. 하지만 공인 인증 기관에서 발급하지 않은 인증서는 위의 이미지와 같이 제작자 ID 가 알수 없다고 나오게 됩니다. 또한 어플리케이션을 출시한 뒤에 정상적으로 서비스를 하는 도중 인증서를 바꾸게 되면 기존에 서비스 하고 있는 어플리케이션이 새로운 버전의 어플리케이션으로 업데이트 할 수 없습니다.


오랜만에 쓰는 글이라 역시 힘드네요. 다음 포스팅에서는 업데이트에 대해 다룰 예정 입니다. 잘못된 내용이나 AIR 개발 중 고민하고 있는 부분들은 댓글을 통해 공유 주세요~ 

Posted by Flash 동강
Actionscript3.02011.03.05 12:13

 Flash Player 는 다양한 멀티미디어를 불러오고 재생 할 수 있다. 그 중에서 오디오 관련 파일은 기본적으로 MP3 파일을 재생 할 수 있으며, popforge (http://code.google.com/p/popforge/) 와 같은 라이브러리를 사용하면 WAVE 파일도 재생 가능 하다. 하지만 이 문서에서는 Actionscript3 에서 제공하고 있는 기본 API 를 가지고 파일을 불러오고 재생 하기 위한 기본적인 이론에 대해 다룬다.


 Flash 에서 오디오 파일을 재생 하기 위해서는 Sound, SoundChannel 를 사용한다. 디테일한 플레이어를 구현하기 위해서는 다른 클래스도 알아야 하지만 기본 기능만 만든다면 위 두가지 클래스의 레퍼런스만 봐도 충분히 구현 할 수 있다. 


Sound Class


 Sound Class 를 MP3 파일을 로드 하고 재생 하는 기능을 담당한다. 파일을 로드 하기 위한 load, 재생하기 위한 play, 재생을 끈어버리기(재생의 멈춤이 아니다) 위한 close 메소드 등을 가지고 있다. MP3 파일을 재생 하기 위해서는 다음과 같은 절차를 따라야 한다.


1. Sound 객체 생성

2. Sound 객체에 Event.COMPLETE 이벤트 등록

3. load 메소드를 이용하여 파일 로드

4. 로드가 완료 되면 2 에서 등록했던 이벤트가 발생

5. 로드가 완료 된 후에 play 메소드를 이용해서 재생 


 오디오 파일을 로드 하는 방법은 URLLoader 나 Loader 에서 사용하는 방법과 동일하다. 다음은 위의 절차를 코드화 한 것이다.



package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.media.Sound;
	import flash.net.Socket;
	import flash.net.URLRequest;
	
	public class SoundPlayerTest extends Sprite
	{
		private var _player:Sound;
		public function SoundPlayerTest()
		{
			_player = new Sound();
			_player.addEventListener(Event.COMPLETE, playerReadyHandler);			
			_player.addEventListener(IOErrorEvent.IO_ERROR, playerIOErrorHandler);
			_player.addEventListener(SecurityErrorEvent.SECURITY_ERROR, playerSecurityErrorHandler);
			
			_player.load(new URLRequest("remote/file/10cm_01.mp3"));
		}
		private function playerReadyHandler(event:Event):void 
		{		
			_player.play();
		}		
		private function playerIOErrorHandler(event:IOErrorEvent):void 
		{
			trace("로드에러");
		}
		private function playerSecurityErrorHandler(event:SecurityErrorEvent):void 
		{
			trace("보안에러");
		}
		
	}
}


 위와 같은 방법으로 로드를 하면 해당 파일에 대한 length 로 음원의 길이를 알수 있고, MP3 파일은 곡의 정보를 담고 있는 id3 태그를 가질수 있기 때문에 해당 파일에 id3 태그가 있다면 접근 할 수 있다. 기본적으로 접근 할 수 있는 id3 는 다음과 같다.



_player.addEventListener(Event.ID3, id3TagLoadHandler);
private function id3TagLoadHandler(event:Event):void 
{
	trace("album : "+_player.id3.album);
	trace("artist : "+_player.id3.artist);
	trace("comment : "+_player.id3.comment);
	trace("genre : "+_player.id3.genre);
	trace("songName : "+_player.id3.songName);
	trace("track : "+_player.id3.track);
	trace("year : "+_player.id3.year);
}


id3 태그에 대한 더 자세한 내용은 뒷부분에서 다루고 있다.


주의 해야 할 점은 새로운 파일을 로드 할때마다 Sound 객체를 새로 생성해 줘야 한다. 재사용할시 에러가 발생한다.


SoundChannel Class 


Sound Class 가 중요한 기능을 하고 있지만 모든 기능을 제공 하지는 않는다. SoundChannel Class 를 이용하여 사운드를 재생 하면서 디테일한 조작을 할 수 있다. SoundChannel Class 를 보면 다음과 같은 메소드와 속성이 정의 되어 있다.


속성


leftPeak, rightPeak : 왼쪽 오른쪽의 현재 진폭(볼륨)을 나타내는 0(묵음)부터 1(최대 진폭)까지의 값

position : 사운드가 재생 중일 때 position 속성은 사운드 파일에서 재생 중인 현재 위치를 밀리초 단위 나타냄

soundTransform : SoundChannel 이 가지고 있는 사운드를 조작하기 위한 SoundTransform 객체



메소드

stop : 사운드 재생을 중단


위의 Sound 객체에 stop 메소드가 없고, SoundChannel 에 stop 메소드가 정의 되어 있다. 그 이유는 Sound 객체는 play 메소드를 이용하여 로드한 파일을 열어 주는 역할을 하고 SoundChannel 은 열린 파일 스트림에 대해 조작 역할을 한다.

load 메소드를 이용해 파일을 로드 하고 play 를 할때 play 메소드의 반환값으로 SoundChannel 객체가 넘어오므로 사운드를 조작 하기위해서는 이 반환객체를 조작 하여 사운드를 컨트롤 할 수 있다.



var channel:SoundChannel = new SoundChannel();

channel = _player.play();


일시 정지 및 재생 위치 변경


Sound Class 나 SoundChannel Class 나 모두 일시정지하는 메소드가 없다. 일시정지 기능은 SoundChannel 의 position 값과 Sound Class 의 play 메소드를 사용하여 구현 할 수 있다. 먼저 사운드를 일시 정지 할때 SoundChannel 의 position 값을 저장하고, 다시 재생 하면 Sound 의 play 메소드의 파라미터로 해당 position 값을 넘겨 줘서 사운드를 재생 하면 된다. 코드는 다음과 같다.

 
private function play(position:Number = 0):void 

{	
		
	_channel = _player.play(position);

}


private function pause():void 

{

	_channel.stop();

}

// 재생 버튼 클릭

private function playButtonClicked(event:MouseEvent):void

{

	play(_channel.position);

}

// 일시 정지 버튼 클릭		

private function pauseButtonClicked(event:MouseEvent):void

{

	pause();

}


재생 위치를 변경하는것도 위와 같은 방식으로 하면 된다. 단 play 할때 position 의 위치가 로드된 파일 길이보다 길면 재생이 안된다. 그러므로 Sound 객체의 length 보다 긴지 확인이 필요하다.


private function play(position:Number = 0):void 

{		

       if(position > _player.length)	
       { 
                 position  = _player.length; 
       }

       _channel = _player.play(position);

}


볼륨 변경


볼륨은 SoundChannel 의 soundTransform 을 이용한다. soundTransform 속성은 SoundTransform 객체 이다. 이 객체는 사운드 볼륨을 조작 하기 위한 여러 속성을 가지고 있다. 이 속성 중 volume 값을 변경 하면 된다. 값은 0 ~ 1 사이 이다.



var soundTransform:SoundTransform = new SoundTransform();

soundTransform.volume = 변경할 값;

_channel.soundTransform = soundTransform;


주의할 점은 SoundChannel 객체의 soundTransform 값을 직접 변경 하는것이 아니라, 새로운 SoundTransform 을 생성하여 값을 변경한 후에 적용해 주는 방식이다.


id3 태그



 MP3 파일에는 id3 태그가 파일안에 정의 되어 있다. 그 형식들은 여러가지가 있으며, Flash Player 9 이후 버전 및 AIR 에서는 ID3 2.0 태그, 특히 2.3 및 2.4 태그를 지원 한다. 위의 예제에서 Event.ID3 이벤트를 통해 접근한 속성들은 Actionscript3 ID3Info (http://help.adobe.com/ko_KR/Flash/CS5/AS3LR/flash/media/ID3Info.html객체에서 정의하고 있는 값들이고 이외에도 Flash IDE 나 Flash Builder 의 자동완성에는 나오지 않지만 아래의 속성들이 접근 가능하다. 하지만 모든 값들은 해당 파일에 해당 속성이 정의 되어 있을 경우에만 접근 가능하고 정의 되어 있지 않다면 null 을 반환 한다.


Posted by Flash 동강
Actionscript3.02011.02.18 14:36

Adobe 에서는 Flash Player 10 부터 TLF( Text Layout Framework ) 를 제공하고 있다. 기존 TextField 를 사용하는 방식은 사용 방법이 편하긴했지만, 텍스트를 다루는데 기능적으로나 퍼포먼스 측면에서 부족한게 많았다.

TLF 에서는 이러한 단점들을 Text 를 다루는 Flash Player 의 low level 에 접근하는 프레임워크를 제공하므로 부분적으로 해결되고 있는 움직 임이다. 더 자세한 내용은 Adobe Labs - TLF 에서 확인 가능 하다.

사용 방법은 Adobe Labs 에 자세히 나와 있고, 한가지 주의할 점은 Flash CS5 에서 작업할때 Actionscript 3.0 Settings 패널에서 Runtime Shared Library Settings 가 Runtime shared library(RSL) 로 되어 있는데 이 설정은 textLayout.swc를 외부에서 불러와서 사용하기 때문에 외부 서버 상태에 따라 로딩 지연이 있을수 있으니 swf의 용량이 증가되더라도 Merged into code 로 바꿔 주는게 좋다.




문제는 TLF 를 사용한 프로젝트에서 loaderInfo 에 있는 FlashVars 를 접근할때 parameters 에 있는 값들이 null 로 인식 되는 버그가 있다. Main.swf 에서 TLF 를 로드하는 과정에서 loaderInfo 가 달라져서 발생하는 문제 인데 다음과 같은 방법으로 해결 가능 하다.


if (stage) {
	init();	
} else {
	addEventListener(Event.ADDED_TO_STAGE, init);	
}		

function init( e:Event = null ):void {

        var flashVars:Object = {};
	removeEventListener(Event.ADDED_TO_STAGE, init);
			
	if (parent != null && parent.parent != null) {
		flashVars = parent.parent.loaderInfo.parameters;
	} else {
		flashVars = this.root.loaderInfo.parameters;
	}
}


TLF flashvars bug : http://forums.adobe.com/message/3259520?tstart=0

Posted by Flash 동강
Adobe AIR2010.09.25 19:59

 Adobe 에서는 Openscreen project의 일환으로 Android OS 에서 돌아가는 Adobe AIR Runtime for Android 를 개발중에 있다. AIR for Android 는 Adobe AIR 를 설치한 Android OS 기반 디바이스에서 설치형 어플리케이션을 운영할 수 있게 해주는 기술(런타임) 이다. 






왜 Adobe AIR 인가?



Adobe AIR 란?


 Adobe AIR는 운영체제에 상관 없이 데스크톱에서 RIA(Rich Internet Aapplications)를 개발 및 배포할 수 있는 런타임입니다. 여러분은 전통적인 데스크톱 개발 기술을 배우지 않고도 기존에 사용하던 웹 기술(HTML, Javascript, Adobe Flash®, Adobe Flex™, Ajax)로 개발한 웹 어플리케이션을 데스크톱에서 실행할 수 있습니다.  (출처 : adoberia.co.kr )



 이전 글에서도 언급했듯이 Flash platform을 이용하여 데스트톱 앱이나, 모바일 앱을 개발하면 높은 확장성을 가질수 있다는점이 가장 큰 장점이다. 데스크탑 환경이나 모바일 환경등 여러가지 플랫폼이 존재하는 상황에서 개발하려고 하는 프로그램이 여러 플랫폼을 커버 할수 있어야 한다면 Adobe AIR 를 도입해 보는것이 좋다. 예를 들어 보면, Twitter 클라이언트로 인기를 끌고 있는 TweetDeck ( http://www.tweetdeck.com/ )은 AIR로 개발한 데스크톱 프로그램으로 Window, Mac, Linux 에서 모두 실행 가능하다. AIR를 사용하지 않는다면 각각의 플랫폼(OS)에 맞춰서 따로 개발해야 하지만, AIR를 이용하여 하나의 결과물로 여러 플랫폼에 설치되는 프로그램 개발이 가능 하였다.



AIR for Android (http://labs.adobe.com/technologies/air2/android/)


 현재는 Adobe AIR 2.5 상태이고, Adobe 에서는 2011년 상반기 릴리즈를 예정으로 Android OS ( 넥서스원, 겔럭시 A,S 디자이너 등과 같은 )를 탑재한 디바이스에서 AIR 어플리케이션을 실행 시킬수 있게 하는 런타임을 개발하고 있다. 현재 프리 릴리즈 상태로 개발자 프로그램에 가입하면 개발중인 버전을 테스트 할 수 있다. 필자가 기대하고 있는건 기존 데스크톱 환경에서 이미 구축되어 있는 게임이나 컨텐츠들을 비교적 쉽게 모바일 환경으로 가져올수 있다는 점이다. 



 하나의 소스를 이용하여, 거의 모든 플랫폼을 커버 할 수 있는 컨텐츠 개발이 가능하다. 



그러기 위해서는 앞으로 가야할 길이 많이 남아 있지만, 앞으로 데스크톱, 모바일 환경에서 Adobe AIR의 가능성은 상당히 기대가 된다. 



Posted by Flash 동강
Flash platform2010.09.19 14:53

 몇일전 Apple 이 아이폰 앱 개발 정책 약관을 변경에 따라 다시 Flash CS5 를 이용하여 아이폰 앱 개발이 가능해 졌다. 정책이 바뀌기전 심사 중이었던 플래시로 만든 앱들도 심사 완료 상태가 되었다. 


 이 문서에서는 두가지,  Flash CS5 의 Package for iPhone 으로 개발하는 아이폰앱과 Adobe 에서 2011년 상반기 런칭을 목표로해서 개발하고 있는 Android for AIR 에 대한 소개 및 가능성에 대해 다룰 것이다. 


 먼저 Package for iPhone 이다. Flash Pro CS5를 이용해 만든 결과물이 아이폰 설치 파일인 .ipa 로 나온다. 개발자는 맥에서 xcode 와 object-c를 이용하여 개발한 .ipa 를 테스트하는 방법과 동일하게 자신의 아이폰에 설치 할 수 있다. 



(출처 : http://www.mikechambers.com/blog/ )


 단순히 Flash 툴을 이용해 ( Actionscript3.0 ) 만든 코드를 LLVM ( Low Level Virtual Machine ) 을 통해 .ipa 로 컴파일하는 것이다. 


 몇 가지 테스트를 해보니, 아이폰에서 제공하는 네이티브 API 를 사용하지 않는 컨텐츠라면 데스크톱 환경에서 사용하고 있는 소스를 아이폰 용으로 컴파일해서 사용해 보니 크게 퍼포먼스가 떨어지지 않는다. 다만 폰(스마트폰)이라는 디바이스적인 한계가 있기때문에 최적화가 필요 하다. 


최적화에 대한 내용은 어도비 에반젤리스트인 마이크챔버스의 블로그 내용을 참고하라.



 장점은 데스크톱에서 사용하는 플래시 컨텐츠의 소스를 그대로 가져다 쓸 수 있다는 점이다. 다만 데스크톱은 마우스를 이용하고 폰은 터치를 이용하는 점이 다를 뿐이지 소스를 전반적으로 수정할 필요는 없다. UI 를 구성하는 뷰단과 이벤트 처리만 바꿔준다면 손 쉽게 서비스가 가능한 앱을 만들수 있다. 




 단점은 굳이 플래시를 가지고 개발을 할 필요가 없다는 것이다. LLVM 의 성능이 향상된다면 컴파일되서 나오는 결과물의 퍼포먼스도 빨라지겠지만 xcode 와 object-c 를 이용하여 개발한 앱이 같은 기능을 한다면 더 빠르다. 그리고 데스크톱 자원을 사용해서 무리 없이 실행되던 게임들도 아이폰에서 실행 시키면 느릴수 있다. 아니 느리다. 퍼포먼스 튜닝이 반드시 필요한 부분이다. 하지만 모바일 용으로 퍼포먼스 튜닝을 한다면 데스트톱에서는 더 빠르게 실행 시킬수 있기 때문에 그 소스는 더 경쟁력이 생길 것이다. 


위의 단점들을 보면 굳이 Flash를 이용하여 아이폰 앱 개발을 할 필요성을 못느낀다. 하지만 같은 소스로 Android 앱까지 개발할수 있다면 생각이 달라질 것 같다.


현재 prerelease 상태로 Android OS 에 설치되는 AIR Runtime 이 개발 중에 있다. 아이폰 앱 개발과는 방법이 조금 다르지만 Flash CS5를 이용하여 안드로이드 앱을 개발하는 건 같다. 다만 안드로이드 OS 2.2 버전 이상에서 설치되며 폰에 AIR Runtime 을 설치해야만 Flash 로 개발한 앱을 설치 할 수 있다. 


자세한 개발 방법은 아래 사이트를 참고 하라.



위의 링크에서 확인할 수 있듯 많은 앱들이 이미 개발 되었다. 아직 prerelease 상태이기 때문에 Flash CS5 Android extention을 설치해야 한다. 설치는 AIR for Android prerelease program 에 가입한 후에 해당 사이트에 가면 다운로드 받을수 있다. 


Adobe AIR 가 폰에 설치되어 있어야만 Flash 로 만든 앱들을 설치 할 수 있다는 단점이 있지만, 이 부분은 정식 릴리즈가 되는 시점에서 해결책이 나올 것으로 본다. 몇가지 앱들을 넥서스원(Android 2.2)에 설치 해봤는데 성능이 기대보다 좋다. 개인적으로 아이폰 앱 보다는 안드로이드 앱 개발의 가능성이 높게 느껴 진다. 


다만, 아이폰과 안드로이드 해상도가 다르기 때문에 같은 뷰를 보여 주기 위해서는 소스 변경이 불가피 하고 안드로이드가 탑재되는 스마트폰도 역시 폰에 불가하기 때문에 성능 최적화가 필요 하다. 하지만, 이를 제외 하면 상당히 괜찮다. 아니 나쁘지 않다. 큰 리소스를 필요로 하는 앱이라면 네이티브 코드를 이용하여 개발하는게 휠씬 좋겠지만, 가벼운 컨텐츠 개발이라면 상당히 매력적인 기능이 될 것이다. 


하나의 코드를 이용하여, 데스트 톱( Windows, Mac, Linux), 모바일 ( 아이폰, 안드로이드 그리고 추가적으로 확장 예정인  OS ) 에서 모두 실행 될 수 있는 앱을 개발할 수 있다는게 Adobe가 내세우는 장점이고 나에게도 큰 장점으로 다가 온다. 다만 아직 갈 길이 많이 남아 있다. 퍼포먼스 측면에서 HTML5를 이용해서 개발한 것과 별 다를게 없다면 HTML5의 확장성에 밀리게 될게 뻔하기 때문이다. 하지만 네이티브 API가 접근 할 수 있다는 것 만으로도 상당히 큰 장점이 될 것이다. 그리고 소스를 재사용할 수 있다는 점은 인력 부족 상태에서 하나의 대안으로 자리 잡을 수도 있을것 같다. (또한 아직 prerelease 다 )


다음은 웹에서 서비스 하고 있는 소스를 이용해 뷰만 바꾼것을 아이폰과 안드로이드 앱으로 컴파일해서 설치해본 영상이다.






'Flash platform' 카테고리의 다른 글

Flash App Performance : Image Sprite Sheet  (0) 2012.01.25
[Mobile] Flash Platform for Mobile  (0) 2010.09.19
Flex for Mobile Devices  (0) 2009.11.06
Flash / Flex 로 만든건 느리다?  (2) 2009.09.08
Posted by Flash 동강
Actionscript3.02010.06.13 20:43

Actionscript 3.0 의 Event Model 은 이벤트를 dispatch 하는 방식으로 이루어져 있습니다. 많은 클래스들이 클래스 내부적으로 "어떠한 행동"에 대해 이벤트를 외부로 알려주는 방식을 사용하고 있습니다. 예를 들어 Loader 클래스를 사용할때, 이미지나 파일들을 로드한 후에 Loader 클래스 내부적으로 이벤트 dispatch 가 일어나서 사용자나 개발자는 그 상황에 따른 후 처리를 할 수 있습니다.


import flash.display.Loader;
import flash.events.Event;
import flash.events.EventDispatcher;

var ld:Loader = new Loader();
ld.addEventListener(Event.COMPLETE, hnLoaded);

function hnLoaded( e:Event ):void{   
	// 로드끝
}

// Loader 내부
public class Loader extends EventDispatcher{
	public function Loader(){}
	private function loaded(){
		dispatchEvent(new Event(Event.COMPLETE));
	}
}

개발자들은 addEventListener 를 이용하여 내부적으로 dispatchEvent 되는걸 청취(addEventListener) 하고 있다가 반응이 오면 다운로드 된 데이터에 접근 가능 하게 됩니다. 이렇게 대부분의 AS3 이벤트 모델은 dispatch event 에 근거 하고 있습니다.


저도 AS3을 공부하고 초기에는 dispatchEvent 의 개념에 익숙하지 않아, 바보 같은 짓을 하곤 했는데요. 예를 들어 Event.ENTER_FRAME 으로 이벤트가 끝날때 까지 기다린다던지, Timer 를 이용하여 비슷한 방법을 사용하곤 했습니다. 

var ld:Loader = new Loader();
ld.addEventListener(Event.ENTER_FRAME, hnLoaded);

function hnLoaded( e:Event ):void{    
   // 로드끝
   if(ld.content) {

        // null 이 아니면 로드끝이라 판단
	ld.removeEventListener(Event.ENTER_FRAME, hnLoaded);
	
        // 로드후 후처리 로직 구현    
   } 
}



dispatch Event 는 그 밖에도 클래스의 재사용성에 대한 강점을 가지고 있습니다. 내부적으로 dispatch 되는 이벤트(행동)들을 addEventListener를 이용하여 청취하기만 하기 때문에 객체 유연성이 높습니다. 그 밖에도 여러 장점이 있지만, 자랑은 여기까지 하겠습니다.



dispatchEvent를 사용하지 않고 대안으로 사용할 수 있는 방법이 해당 행동에 대한 callback 메소드를 이용하는 것 입니다. Adobe에서 제공한 flashplatform optimizing content 문서를 보면 플래시 콘텐츠 최적화 방법중에 이벤트 구현을 dispatchEvent를 사용하기 보단 callback 을 사용하는게 더 효율적이라고 하고 있습니다. 이유는 여러가지가 있겠지만, 제가 생각하는 걸 나열해 보면 다음과 같습니다.


  • dispatchEvent 가 일어났다는걸 알기 위해서 addEventLister 를 등록해야 한다.
  • 너무 많은 addEventListener 사용은 메모리나 퍼포먼스에 영향을 줄수 있다.
  • 너무 많은 addEventListener 사용 코드를 지져분 하게 한다. (개인적 취향입니다.)

그래서 그 문서에서는 dispatchEvent 를 사용하지 말고 callback 메소드를 전달하여 이벤트 후처리를 수행하는게 퍼포먼스에 이점이 있다고 말하고 있습니다. 아래와 같은 방식으로요.


var ld:LoaderCallback = new LoaderCallback(hnLoaded);

public class LoaderCallback extends EventDispatcher{
	private var _callback:Function;   
	private var _ld:Loader;    
	
	public function LoaderCallback() {
		_ld = new Loader();
		_ld.addEventListener(Event.COMPLETE, loaded);
	}    
	public function load(url:String,callback:Function):void {
		_callback = callback;       
		_ld.load(new URLRequest(url));
	}    
	private function loaded(e:Event) {
		callback(e);
	}
}


callback 메소드를 로드를 수행하는 LoaderCallback의 load 메소드에 파라미터로 넘기기 때문에 따로 addEventListener를 등록할 필요도 없고 이벤트 관리를 효율적으로 할 수 있습니다.


프로젝트를 하면서 고민했던 부분이 바로 이 부분이었는데요. 퍼포먼스를 생각하면 (그밖에도 여러이점이 있겠지만) callback 을 사용해야 하지만, dispatchEvent 를 이용하면 나중에 API 로 변경 했을때 추가 작업없이 바로 사용 할 수 있다는 장점 때문에 두가지 선택 사항에서 고민을 많이 하였습니다. 그래서 내린 결론은 addEventLister 등록을 최소한으로 하고 API 로서 기능을 수행할 가능성이 적은 클래스는 callback 를 사용하고 API 의 기능을 수행해야 하는 객체에는 dispatchEvent 를 사용하였습니다. dispatchEvent 도 일일히 각각의 이벤트를 등록하여 청취하는 방법이 아니라, 하나의 이벤트를 수신하여 커스텀 이벤트에 있는 type 으로 이벤트 유형을 판단 하도록 하였습니다.


아래와 같은 방법은 3번의 addEventListener를 해야 되지만


stream.addEventListener(StreamEvent.PLAY,hnStreamPlay);
stream.addEventListener(StreamEvent.STOP,hnStreamStop);
stream.addEventListener(StreamEvent.PAUSE,hnStreamPause);

public class Stream extends EventDispatcher{ 
	public function Stream(){}
        public function play():void { 
		dispatchEvent(new StreamEvent(StreamEvent.PLAY));
	}  
	public function stop():void {
		dispatchEvent(new StreamEvent(StreamEvent.STOP));
	}
	public function pause():void {
		dispatchEvent(new StreamEvent(StreamEvent.PAUSE));
	}
}

function hnStreamPlay( e:StreamEvent ):void{}
function hnStreamStop( e:StreamEvent ):void{}
function hnStreamPause( e:StreamEvent ):void{}


아래 방법은 한개의 등록만으로 처리가 가능 합니다.

stream.addEventListener(StreamEvent.ECHO,hnStreamEcho);

public class Stream extends EventDispatcher{ 
	public function Stream(){}       
	public function play():void {
		dispatchEvent(new StreamEvent(StreamEvent.ECHO,StreamEvent.PLAY));
	}
	public function stop():void {
		dispatchEvent(new StreamEvent(StreamEvent.ECHO,StreamEvent.STOP));
	}
	public function pause():void{
		dispatchEvent(new StreamEvent(StreamEvent.ECHO,StreamEvent.PAUSE));
	}
}
function hnStreamEcho( e:StreamEvent ):void{ 
	// StreamEvent 에 label 을 구현함    
	if(e.label == StreamEvent.PLAY){} 
	else if(e.label == StreamEvent.STOP){}
	else if(e.label == StreamEvent.PAUSE){}
}


개인적으로 두번째 방법을 더 선호 하는데요. 그때 그때 상황에 따라 선택이 중요한것 같습니다.


Flashplatform 개발 작업이 다른 언어에 비해 이벤트를 관리해야 되는 상황이 많은데요. 사용하기 편한것도 좋지만, 메모리나 퍼포먼스, 코드 가독성을 생각하여 판단하는 능력이 필요 하다는 생각이 드네요.


posted by dongkang




Posted by Flash 동강
Flash Programming 란?2010.03.07 15:05

 지금까지 Flash 에서의 Timeline 에 대해 알아보았습니다. Timeline 에 대한 개념이 정리가 되셨는지요? 보통 사람들은 아래 그림 A와 같이 흰 도화지 안에 Timeline이 존재 하는 줄 알고 있습니다. 하지만 실제로는 반대입니다.



그림 A

그림 B



 그림 B와 같이 Timeline 안에 희 도화지가 속해 있는 형식으로 구성되어 있습니다. Timeline의 한 프레임 당 하나의 흰 도화지를 가지고 있고, 코드를 입력 할 수 있는 공간을 가지고 있습니다. 그림 A와 B는 단순히 Timeline 이 흰 도화지 보다 크다 (Timeline > 흰 도화지) 라는 의미를 뜻하지만, Flash의 구조 안쪽으로 들어가면 Flash에서의 객체라는 것의 뿌리가 되는 개념입니다. 왜냐 하면 모든 객체들은 이 Timeline에 속하게 되므로서 사용자들에게 보일 수 있게 되는 것이기 때문입니다. 이번 장을 진행하면서 왜 Timeline이 Flash의 구조의 뿌리가 되는 이유에 대해 살짝 엿보고, Flash에서의 객체가 어떻게 정의 되어 있고, 생성 되었다가 소멸 되는 과정에 대해 이야기 해 볼 것입니다.


 Flash는 객체기반 툴입니다. Flash에서 사용되는 것들 중에 객체가 아닌 것은 없을 정도로 모두 객체로 이루어져 있습니다. 지금 말하고 있는 객체란, MovieClip과 Button 그리고 툴로 그릴 수 있는 모든 것들을 의미 합니다. 잠시 객체의 의미에 대해 잠깐 짚고 넘어가겠습니다. 사전에서는 객체를 이렇게 정의 하고 있습니다.



 객체 [客體, object]

객체 지향 프로그래밍(OOP)이나 설계에서, 데이터(실체)와 그 데이터에 관련되는 동작(절차, 방법, 기능)을 모두 포함한 개념. 예를 들어 기차역에서 승차권을 발매하는 경우, 실체인 ‘손님’과 동작인 ‘승차권 주문’은 하나의 객체이다. 실체인 ‘역무원’과 동작인 ‘승차권 발매’도 하나의 객체이다.



백과 사전에서 정의한 것과 같이 동작의 주체가 되는 사람이나, 사람이 하는 동작 자체도 모두 객체라고 할 수 있습니다. 프로그래밍을 처음 접하는 사람들은 객체를 이해 할 때 사람과 같은 정해진 사물은 객체라고 이해 하지만, 동작이나 수학 공식을 처리해 주는 객체 같은 경우에는 객체가 아니라고 생각하는 경우가 많습니다. 객체는 보통 생각하는 것 보다 더 커다란 의미를 가지고 있습니다. 예를 들어 놀이터에 철수와 영희라는 객체가 놀고 있습니다. 놀이터에는 그네 객체, 미끄럼틀 객체가 있고 철수와 영희는 이들 놀이 기구 객체들을 사용할 수 있습니다. 이 경우는 모두 객체의 구분이 분명하기 때문에 이해하기에 어려움이 없을 것입니다. 하지만, 객체는 이러한 경우뿐만 아니라 우리가 행하는 동작이나, 기계들이 가지고 있는 기능들의 모음 또는 문서에 저장되는 데이터 모두 객체라고 할 수 있습니다. 이러한 객체들을 이용하는 툴을 객체 기반 툴이라고 하고, 객체 기반 언어라고 하는 것입니다. 그럼 Flash 에서의 객체는 어떤 것이 있을까요? 예를 들어 보겠습니다. Flash를 실행시키면 바로 보이는 것은 흰 도화지입니다. 그리고 그 아래 타임라인, 옆에는 Color패널과 Properties 와 라이브러리패널이 위치하고 있습니다. 이들 모두 객체입니다. 그리기 툴을 이용해서 사각형을 그린다고 하면, Color 패널을 사용하여 그리고 난 후에 사각형의 색상을 변화 시킬 수 있습니다. 왜 변화 시킬 수 있을까요? 그건 그려진 사각형에 color 라는 속성을 가지고 있기 때문에 변경을 할 수 있는 것입니다. 객체는 아무 것도 없는 빈 상태로 다른 객체를 담을 수 있는 역할도 하고, 속성과 메소드를 추가하여 그 자체로서 역할을 갖기도 합니다.

객체의 의미에 대해서 어느 정도 감이 왔을 것이라 생각이 듭니다. 그럼 본격적으로 Flash의 객체 구조에 대해서 다뤄 보도록 하겠습니다.


  • Flash 의 Display 구조

 Flash는 기본적으로 가지고 있는 구조가 있습니다. 과일을 담으려면 바구니가 필요하듯, Flash는 자체적으로 객체를 담을 그릇을 가지고 있습니다. 그 그릇이 바로 이전 포스팅에서 배웠던 Timeline입니다. 지금까지는 Timeline이라고 말했지만, 이 Timeline은 실제로 MainTimeline이라고 불리는 Flash에서 최상위 부모(바구니) 역할을 하는 객체입니다. 하지만 바구니가 있다고 해서 그 바구니가 가장 크기가 큰 개념은 아닙니다. MainTimeline 위에는 Stage 라는 객체가 더 존재하게 됩니다. 이러한 관계는 부모와 자식의 관계로 비유 하는 경우가 많으나, 여기에서는 바구니를 놓는 공간과 큰 바구니의 관계로 비유해 보겠습니다. Flash는 기본적으로 Stage 라는 공간 안에, MainTimeline 이라는 Timeline을 가지고 있는 바구니가 들어가게 됩니다. 그리고 그 MainTimeline 안에 모든 객체들이 만들어 지는 것입니다. 아래 그림을 보면 그러한 관계가 나타나 있습니다. 실제로 이러한 관계는 코드를 통해 확인해 볼 수 있습니다.





첫 번째 프레임에 아래 코드를 입력 합니다.

trace("this.parent : "+this.parent);

trace("this : "+this);


실행결과

this.parent : [object Stage]

this : [object MainTimeline]

 


실행 결과에서 볼 수 있듯이, 아무 것도 존재 하지 않은 상태의 this 는 MainTimeline을 가리키고 있습니다. 그리고 부모 객체를 알 수 있게 해 주는 parent 속성을 통해 MainTimeline의 부모를 보니 Stage 라고 나오는 것을 확인할 수 있습니다. 이와 같이 Flash는 사용자가 객체를 만들기 전에 그 객체가 담겨질 그릇에 해당하는 Stage와 MainTimeline을 준비해 놓고 객체가 만들어 지기만을 기다립니다.

Flash의 display 구조는 Stage-MainTimeline-만들어지는객체 로 이루어져 있습니다. 하지만 같은 객체를 나타내는 것이라도, 표현 방법은 여러 가지가 있습니다.



// 기본 display list

trace("this :"+this);

trace("this.parent :"+this.parent);

trace("this.stage :"+this.stage);

trace("-------------------------");


// root 에 관하여

trace("root : "+root);

trace("this.root :"+this.root);

trace("this.stage.root :"+this.stage.root);


//결과

this :[object MainTimeline]

this.parent :[object Stage]

this.stage :[object Stage]

-------------------------

root : [object MainTimeline]

this.root :[object MainTimeline]

this.stage.root :[object Stage]

 



이와 같이 같은 의미 이지만, 다르게 표현 될 수 있는 경우가 많이 있습니다. 또한 코드를 MainTimeline에 작성했을 경우에는 위와 같은 결과를 나타내지만, 빈 스테이지에 무비클립을 만든 후 그 안에 아래와 같은 코드를 입력할 경우에는 결과가 달라집니다.



 

// 기본 display list

trace("this :"+this);

trace("this.parent :"+this.parent);

trace("this.stage :"+this.stage);

trace("-------------------------");

// root 에 관하여

trace("root : "+root);

trace("this.root :"+this.root);

trace("this.stage.root :"+this.stage.root);

// 결과

this :[object Symbol1_1]

this.parent :[object MovieClip] // MainTimline이 나올 것이라 예상했을 것이다.

this.stage :[object Stage]

-------------------------

root : [object MovieClip]

this.root :[object MovieClip]

this.stage.root :[object Stage]



stage 관련 코드를 제외 하고는 모두 결과가 바뀌었습니다. 왜 그럴까요? 결과 분석에 앞서 root의 개념에 대해 짚고 넘어 가겠습니다. root 속성은 어떠한 객체가 포함되고 있는 최상위 부모객체를 나타내는 속성입니다. 예를 들어 보겠습니다. 빈 스테이지에 SuperMother이 있고, 그 안에 Mother, 또 그 안에 Child 라는 무비 클립 객체가 있습니다.




// 각각의 무비 클립은 포함 관계에 있으며 instanceName이 부여 되어 있다.

trace(_supermother.root);

trace(_supermother._mother.root);

trace(_supermother._mother._child.root);

// 결과

[object MainTimeline]

[object MainTimeline]

[object MainTimeline]

 


결과와 같이 root는 자기 자신이 존재하고 있는 최상위의 부모를 나타냅니다. MainTimeline 과 Stage는 자기 자신이 최상위이기 때문에 root 속성을 보아도 자신이 출력 되는 것입니다.

 

Adobe에서 제공하고 있는 as3.0 설명서에서 DisplayObject에 root 속성을 찾아보면 상황에 따라 root 가 어떻게 다르게 쓰이는가를 볼 수 있습니다. 아직 배우지 않은 개념들을 이용해서 설명해야 하므로 관련된 포스팅에서 더 자세히 알아보도록 하겠습니다.

 

 다시 이전 예제로 돌아가서, MainTimeline으로 나올 것이라 생각했던 값이 MovieClip으로 출력되었습니다. 그 이유는 스테이지 위에 생성된 무비클립에서는 자기 자신의 부모의 타입이 MovieClip 이라는 것은 알고 있지만, 정확한 이름을 알고 있지 못하기 때문에 MovieClip 이라고 출력해준 것입니다. 해결 방법은 간단합니다. Flash에 이름을 알려주면 되는 것이지요. 소스는 생성된 무비 클립 안에 작성 되었으니, trace(this.root); 코드를 MainTimeline에 입력해 봅시다.



 

// 기본 display list

trace("this :"+this);

trace("this.parent :"+this.parent);

trace("this.stage :"+this.stage);

trace("-------------------------");

// root 에 관하여

trace("root : "+root);

trace("this.root :"+this.root);

trace("this.stage.root :"+this.stage.root);

// 결과

[object MainTimeline]

this :[object Symbol1_1]

this.parent :[object MainTimeline]

this.stage :[object Stage]

-------------------------

root : [object MainTimeline]

this.root :[object MainTimeline]

this.stage.root :[object Stage]



MainTimeline 에서는 자신이 MainTimeline이라는 것을 알고 있었기 때문에, MainTimeline이라 출력해 주었고, Flash는 가장 먼저 실행되는 trace(this.root);를 통해서 정보를 알게 되었기 때문에 MovieClip 으로 출력해 주었던 것은 MainTimeline 으로 좀 더 객체를 명확하게 나타내 주었습니다. 이와 같이, 같은 키워드를 사용하는데도 불구하고 자신의 의도와는 다르게 나타나는 경우가 있습니다. 특히 this 와 root 그리고 parent의 개념을 잘 알고 사용해야 버그를 줄일 수 있습니다. 


 

this 의 의미 변화


AS2.0때까지만 해도 this가 의미 하는 것은 같은 코드 페이지에서 사용하여도 this를 사용하는 함수에 따라 달라졌습니다. AS2.0 코드에서는 아무것도 없는 스테이지상에서 trace(this);를 입력해 보면 _level0 이라는 최상위 표시객체를 나타내 줍니다. 하지만 스테이지 상에 mc 라는 무비 클립을 만든 후에 onRelease 이벤트를 걸어준 후에 나타나는 this는 _level0.mc입니다.


 이와 같이 같은 페이지(객체)에 코딩을 하고 있더라도, this의 의미는 어떤 이벤트에서 사용되는가에 따라 그 이벤트의 행위의 주체가 되는 객체로 의미가 바뀌면서 사용 됩니다. 아래의 코드를 보면 이벤트에 속해 있지 않았을 때의 this 는 _level0 은 나타내고 있지만, onRelease 라는 이벤트 안에서는 이벤트의 주체가 되는 _level0.mc를 가리키고 있는 것을 보면 이와 같이 동작하고 있다는 것을 알 수 있습니다. 하지만 as3.0 에서는 달라졌습니다.



trace(this);

mc.onRelease = function(){ // AS2.0 에서의 Click 이벤트입니다.

trace(this);

}

 

// 결과

_level0

_level0.mc // mc 라는 무비 클립을 클릭했을 때



 as3.0 의 경우 ‘같은 객체’ 안에서 사용되는 this의 의미는 항상 코드가 입력되고 있는 자기 자신을 나타냅니다. 우리가 지금 하고 있는 프레임 코딩 같은 경우에는 코드를 입력하는 장소가 MainTimeline 이기 때문에 최상위의 프레임일 경우 this는 항상 MainTimeline을 가리킵니다. 위에서 ‘같은 객체’ 라고 표현한 이유는 앞으로 우리들은 MainTimeline 뿐만 아니라, 새로운 객체(클래스)를 만들어서 그 안에 코딩 할 것이기 때문에 표현을 한정시킨 것입니다. 빈 스테이지에 무비 클립을 만든 후에 더블클릭으로 만들어진 무비클립의 타임라인에 trace(this); 라고 코딩해 보면 [object Symbol1_1] 라는 결과를 출력합니다. 무비 클립을 만들 당시에 객체 이름 즉, 클래스 이름을 정의 하지 않았기 때문에 Flash에서는 임의로 Symbol1_1 이라는 이름을 부여한 것입니다. 이 이름은 무비클립을 만들 때 입력했던 Name을 바탕으로 만들어 지는 것이나, 실제로 여기서 만든 무비 클립을 바로 동적으로 생성하여 사용할 수는 없습니다. Linkage 라는 클래스 연결 작업을 통해서 하나의 클래스 객체가 되는 것입니다. 다시 this의 의미로 돌아와서, as3.0 에서의 this는 항상 자기 자신을 가리킵니다. this를 통해서 자신의 부모객체인

this.parent 로 접근할 수 있으며, 자신의 자식 객체가 존재할 경우에는 this.자식객체이름 으로 접근 가능한 것입니다. 마지막 예로 AS2.0 에서는 이벤트에 포함했을 때 this의 의미가 바뀌었으니, as3.0 에서는 이벤트에 포함된 this 는 어떤 의미를 나타내는지 보겠습니다. 위의 예제와 같이 빈 스테이지에 무비 클립을 만든 후 이벤트를 걸어 줍니다.



trace(this);
mc.addEventListener(MouseEvent.CLICK, onClickHandler);  // as3.0의 Click이벤트
function onClickHandler(event:MouseEvent):void
{
trace(this);
}

// 결과
[object MainTimeline]
[object MainTimeline]     // mc 라는 무비 클립을 클릭했을 때



이와 같이 MainTimeline 에 작성된 this 는 모두 MainTimeline을 가리킵니다.


Posted by Flash 동강
Flash Programming 란?2010.02.15 11:52

  지금 까지 Flash프로그래밍에서의 타임 라인의 역할과 함께 Timline이 움직이는 흐름에 대해 이야기 해 보았습니다. 이제 타임라인이 어떻게 동작하는지에 대한 기초적인 개념을 파악 하셨을 것입니다. 지금 까지 다룬 내용은 Timeline의 프레임 순서에 따른 실행 순서 였습니다. 프레임 1에 있는 코드는 프레임 2에 있는 코드 보다 먼저 실행이 되고, 여러 메소드를 이용하여 재생헤드의 위치를 조작하므로 실행 순서를 조작 할 수 있었습니다. 그렇다면 같은 레이어에 존재 하지 않는 다른 레이어에 존재하는 코드의 경우에는 어떤 순서로 실행되게 될까요? 가장 상위에 있는 레이어에 있는 코드부터 실행되게 됩니다. 아무것도 아닌 것 같이 보여도 이 개념에 대해 알지 못하고 툴 작업을 하는 분들이 많이 있습니다. 예를 들어 circle_mc라는 객체를 만들고, circle_mc가 존재 하는 레이어 바로 위에 새로운 레이어를 만든 후에 trace(circle_mc)라는 코드를 입력하여 실행해 보면 다음 과 같은 결과가 나옵니다.



실행 결과

[object MovieClip]


 예상했던 대로 trace문은 circle_mc를 인식하고 결과를 나타내 줍니다. 그럼 action 레이어와 circle_mc 레이어의 위아래를 바꾸면 어떻게 될까요? 레이어를 클릭한 후 드레그해서 action 레이어를 circle_mc레이어 아래로 이동시킨 후 다시 실행 시킨 결과는 다음과 같습니다.



 

실행 결과

[object MovieClip]


 레이어 위치에 상관없이 똑같은 결과가 나옵니다. 이는 Timeline 에 만들어진 circle_mc의 참조를 어느 레이어에서나 상위, 하위에 상관없이 접근이 가능하다는 의미입니다. 하지만 코드로 생성되어 지는 객체에 대해서는 다른 결과를 나타냅니다. 예를 들어 2개의 레이어를 가지고 있는 Timeline이 있습니다. 위에 있는 create 레이어에는 trace(circle_mc); 라고 코드를 입력하고 아래 있는 trace 레이어에는 var circle_mc:MovieClip = new MovieClip(); 라고 코드를 입력 한 후 Ctrl+Enter를 눌러 실행 시킵니다.


실행 결과

[object MovieClip]


레이어의 코드 실행 순서는 상위에 있는 레이어부터 시작하기 때문에 [object MovieClip] 이라는 결과를 나타냅니다. 하지만 위아래 레이어의 위치를 바꾼 후에 실행하면 어떤 결과가 나타날까요?


실행 결과

null


 null 객체가 존재 하지 않는 다는 의미를 가지고 있는 null을 나타냅니다. 이렇게 코드의 작성 위치에 따라 코드가 길어질 경우 복잡한 에러를 발생시키는 요인이 되기도 합니다. 이러한 코드의 실행 관계는 프레임에 작성하는 코딩뿐만 아니라, 클래스 코딩에서 중요한 부분입니다. 여러 분들은 앞으로 이 에러를 자주 보게 될 것입니다.


 실행결과

TypeError: Error #1009: null 객체 참조의 속성이나 메서드에 액세스할 수 없습니다.

at 1_fla::MainTimeline/frame1()


 해당 에러를 줄이기 위해서는 코드가 실행되는 전후 관계를 확실하게 파악해야 한다는 점을 다시 한 번 강조 합니다. 정리하면, 프레임1부터 프레임 20까지 모든 프레임에 AS 코드가 작성 되어 있을 경우 재생 헤드의 움직임에 따라 모든 코드가 실행될 것입니다. 어떤 분들은 꼭 stop() 메소드로 재생 헤드를 정지 시켜야만 해당 프레임에 있는 코드가 실행되는 것이라고 잘못 이해하고 있습니다. 재생 헤드가 위치한 순간 코드는 실행되는 것입니다. 이 말은 재생 헤드가 지나가지 않은 프레임에 있는 코드는 실행되지 않는다는 의미입니다. 따라서 실행되고 있는 프레임보다 뒷 프레임에 정의된 코드에 포함된 변수를 아무리 참조해 봤자 null 값이 나오는 것은 당연한 것입니다.


 Flash 에서의 레이어


  레이어는 투명한 도와지 입니다. 애니메이션 작업을 할 때, 등장인물과 배경을 따로 그린 후에 합치는 작업을 하는 것처럼, Flash 에서도 레이어 개념을 가지고 각각의 레이어에 만들어 지는 객체들은 도와지에 그려지게 되는 것입니다. 하지만 이 도와지 들은 하나의 객체(MainTimeline 이나 MovieClip)에 속해 있고 위, 아래 개념을 가지고 있습니다. 그림과 같이 A 도와지에 파란 원을 그리고 B도와지에 빨간 원을 그린다면, A 에서의 파란 원의 좌표와, B 에서의 빨간 원의 영역이 겹치지 않는 한, 두 원 모두 보이는 객체로 처리가 됩니다. 하지만 A에 있는 파란 원이 B의 빨간 원과 영역이 겹친다면 파란원은 빨간 원에 가려서 안 보이게 됩니다. 만약 빨간 원과 파란원의 영역이 완전히 겹쳐서 파란원이 안 보인다고 해서 파란원이 사라진 것은 아닙니다. 단지 B 레이어가 A 레이어 보다 아래 존재하기 때문에 가려진 것입니다. 이 개념은 뒤에서 다룰 Index 개념과 비슷한 특징을 가지고 있습니다. Index 역시 위, 아래 개념을 가지고 있지만 레이어와는 다른 것입니다. 레이어는 Flash 툴 상에서 Timeline을 가지고 있는 객체 즉 MainTimeline 이나 MovieClip 등이 가지고 있는 그래픽 작업을 도와주기 위한 방법으로서 제공 되는 기능입니다. 이 개념은 에 다룰 Index 개념과 혼동 될 수 있으니 확실하게 알고 넘어가시기 바랍니다.


Depth 와 Index 에 대해 자세히 알고 싶다면 이 포스팅을 읽어 보세요.





Posted by Flash 동강
Flash Programming 란?2010.01.30 15:34

  • Timeline 제어

 Flash의 Timeline이 그냥 시간에 따라 진행 되는 것만은 아닙니다. AS를 통해서 이를 제어하고 코드가 발생하는 순서를 정할 수 있습니다. 기본적으로 Timeline을 제어 하는데 사용하는 액션은 다음과 같습니다.


- stop() : Timeline에 있는 재생헤드를 정지합니다.

- play() : Timeline에 있는 재생헤드를 움직입니다.

- gotoAndPlay(frame, scene =null) : 해당 Scene 에 존재하는 frame으로 이동한 후 재생헤드를 움직입니다.

- gotoAndStop(frame, scene =null) : 해당 Scene 에 존재하는 frame으로 이동한 후 정지 합니다. (정지상태)



 gotoAndPlaygotoAndStop의 파라미터로 들어가는 scene 의 경우는 생략이 가능합니다. 위에서 =null 이라고 선언되어 있는 것은 해당 파라미터가 입력되지 않았을 때는 scene 값을 null 값으로 처리 하겠다는 의미입니다. Timeline에 여러개의 프레임이 존재 하고 있을 때 재생헤드는 현재 머물고 있는 프레임에 해당하는 일을 마친 뒤 다음 프레임이 존재 한다면 다음 프레임으로 자동으로 넘어가서 또 그 프레임에 있는 일을 처리 합니다. 하지만 이러한 동작은 사용자가 원하지 않는 것일 수도 있습니다. 평소에는 프레임 1에 있는 것을 보여 주다가 어떠한 이벤트가 발생 했을 때 다른 프레임으로 이동 시키고 싶은 경우 평소에는 재생 헤드가 항상 프레임 1에 존재해야 되기 때문에 stop() 함수를 사용하게 됩니다. Timeline을 제어 하는 액션은 아주 다양한 용도로 사용 되고, 많은 것을 만들 수 있게 도움을 주는 메소드입니다. 예를 들어, Flash에는 마우스가 오버, 다운, 업 일 때의 이벤트를 처리를 미리 구현해 놓은 SimpleButton이라는 객체가 있습니다. SimpleButton은 내부적으로 구현되어 있는 객체지만 위의 Timeline을 제어 하는 메소드만을 이용하여 만들 수 있습니다. 우선 SimpleButton이 어떻게 구성되어 있는지부터 알아보겠습니다. 



 1. Flash File(Actionscript3.0) 로 새로운 파일을 생성 한후, Rectangle Tool(R)을 이용하여 사각형을 만듭니다.



2. 사각형을 선택 한 후, F8 또는 Modify-Convert to Symbol...을 선택하고 Type을 MovieClip으로 선택 한 후 OK를 누릅니다. 




3. 만들어진 MovieClip 객체를 마우스로 클릭 한 후, 우측 상단에 있는 Properties에 Instance Name을 입력하는 곳에 rect_mc라고 이름을 입력합니다.

 


4. 사각형을 더블클릭하여 하위 객체의 Timeline으로 이동한 후 2,3 프레임에 마우스 오버일 때의 상황과 마우스 버튼을 클릭 했을 때의 상황을 정의 합니다. 이 예제에서는 3개의 프레임에 각각 아래와 같은 도형을 그려 넣었습니다. 그리고 프레임 1에 stop(); 메소드를 입력 합니다.


 




5. 다시 상단에 있는 네비게이션 버튼을 클릭하여 Scene1(상위객체)로 올라 와서 프레임 1에 아래의 코드를 입력 합니다.




// 코드

stop();                   // 재생헤드가 움직이지 않게 정지 시킨다.// 각각의 이벤트를 등록해 준다.rect_mc.addEventListener(MouseEvent.MOUSE_UP,onUphandler);rect_mc.addEventListener(MouseEvent.MOUSE_OVER,onOverhandler);rect_mc.addEventListener(MouseEvent.MOUSE_OUT, onOuthandler);rect_mc.addEventListener(MouseEvent.MOUSE_DOWN,onDownhandler); function onUphandler(event:MouseEvent):void{        rect_mc.gotoAndStop(1);}function onOverhandler(event:MouseEvent):void{         rect_mc.gotoAndStop(2);}function onOuthandler(event:MouseEvent):void{         rect_mc.gotoAndStop(1);}function onDownhandler(event:MouseEvent):void{         rect_mc.gotoAndStop(3);}



 위에서 만든 사각형에 rect_mc 라는 이름(Instance Name)을 적용하므로써 코드에서 접근을 할 수 있게 되었습니다. rect_mc 에 Flash가 정의하고 있는 4가지 마우스 이벤트를 정의하고, 이벤트에 종류에 따라 gotoAndStop 문을 써서 재생헤드의 위치를 변경 하였습니다. 이 예제에서는 마우스의 움직임에 따라 rect_mc안에 있는 Timeline을 조작하므로 SimpleButton와 같은 동작을 하게 됩니다. (객체에 마우스 이벤트가 발생하는 과정은 후에 자세히 다룰 것임으로 생략 합니다.) 이러한 원리를 이용하면, 사용자의 마우스 움직임에 따라 마우스 이벤트가 발생한 객체뿐만 아니라, Timeline을 가지고 있는 모든 객체의 Timeline 속성을 조절할 수 있습니다. 여러 웹 사이트를 돌아다니다 보면, 화려한 모션과 함께 사용자의 반응에 따라 액션이 일어나는 사이트들이 많이 존재 합니다. 이러한 사이트들의 대부분이 이러한 Timeline을 메소드를 사용하는 이벤트만으로도 쉽게 만들 수 있습니다. 다만 Adobe AfterEffect 와 같은 모션 툴에서 한 작업을 Flash 의 Timeline으로 가져와서 조절하기 때문에 가능해지는 것입니다. 물론 Flash로 작업한 애니메이션도 가능합니다. 이렇게 타임라인을 이용한 작업은 간단하게 멋진 결과물이 나올 수 있게 도와줍니다. 


 하지만, Timeline 의 프레임 번호만을 가지고 재생헤드를 이동시키는 것은 여간 번거로운 작업이 아닐 수 없습니다. 프레임 번호를 맞춰가면서 gotoAndPlay를 사용해 가며 인터렉션을 만들었다고 해도, 유지보수가 있을 때 Timeline의 길이가 변하거나, 효과가 변하는 일은 비일비재 하게 일어나는 일이기 때문에 또 다른 방법을 요구 하게 됩니다. 그래서 Flash는 이러한 번거로움을 줄이기 위해 Timeline에 label 속성을 제공해 주고 있습니다. label 속성이란, Timeline을 조절할 때 프레임 번호로 위치를 참조해야 하는 번거로움을 없애기 위해 해당 프레임에 이름을 부여 하는 기능입니다. 아래 그림과 같이 마우스로 프레임을 선택하면 Properties 창에 LABEL 속성이 나타나게 됩니다. Name 에 해당 프레임으로 지정하고 싶은 Name을 입력하게 되면 해당 프레임은 지정된 이름의 참조 값을 갖게 됩니다. 



이 그림에서는 프레임 1에 Out, 프레임 10에 Over, 프레임 20에, Down 이라는 이름을 지정하였습니다. 이렇게 LABEL 값이 정해지게 되고, 위에서 구현했던 소스를 다음과 같이 변경하면 같은 기능을 하게 됩니다.


// 코드

부록 CD: Example\1-4\1_4_3.fla// 이벤트 등록 부분이 동일함으로 생략하였습니다.// 바뀐 부분은 bold 처리 되었습니다.function onUphandler(event:MouseEvent):void{	rect_mc.gotoAndStop("Out");}function onOverhandler(event:MouseEvent):void{	rect_mc.gotoAndStop("Over");}function onOuthandler(event:MouseEvent):void{	rect_mc.gotoAndStop("Out");}function onDownhandler(event:MouseEvent):void{	rect_mc.gotoAndStop("Down");}


 이러한 간단한 구조의 Timeline 에서는 필요하다는 느낌을 받지 못할 수도 있습니다. 하지만, 언제 바뀔지 모르는 프레임 번호를 신경 쓰기보다는 label을 지정함으로서 예측 할 수 없는 유지 보수에 대해 대비 할 수 있고, 훨씬 유연하게 대처할 수 있는 작업 방법입니다.


 지금까지 Timeline을 제어 하는 방법에 대해 알아보았습니다. Timline을 어떻게 조절하고 어떤 효과를 삽입하느냐에 따라 gotoAndPlay 만으로도 멋진 Flash를 만들 수 있는 비결이 될 수 있습니다. 그만큼, Timeline을 기반으로 하고 있는 Flash 프로그래밍에서 Timeline 제어는 중요한 부분을 차지하고 있습니다. 

 

Posted by Flash 동강
Flash Programming 란?2010.01.24 09:33
  • TimeLine

 시작부터 Timeline의 중요성에 대해 강조를 했습니다. 그 이유는 메인에 존재 하는 Timeline 이 실제로 MainTimeline 이라는 Flash 객체이기 때문입니다. 많은 사람들이 Timeline은 그냥 Flash툴에 속해 있는 도구로만 인식하는 경우가 많이 있습니다. 하지만 Timeline은 단지 도구로서의 의미보다 더 중요한 위치를 차지하고 있습니다. 왜냐 하면 Flash에서 생성되고 삭제되는 모든 객체들은 이 MainTimeline 위에 생성되고 삭제되기 때문 입니다. 모든 객체를 담는 그릇과 같은 역할을 하는 것입니다. 즉, 최상위에 있는 부모역할을 담당하고 있습니다. Actionscript 에서도 MainTimeline은 중요한 역할을 합니다. 최상위의 부모 역할 뿐만 아니라, 일반적으로 .as (클래스파일)로 작성되지 않은 AS 코딩은 타임라인 위에 작성되기 때문입니다.

Flash는 Timeline에 코드를 삽입 할 수 있는 특징을 가지고 있습니다. 아래 그림과 같이 자신이 원하는 프레임을 선택하고 F9또는 상단메뉴의 Window-Actions를 선택하면 코드를 입력할 수 있는 창이 뜨게 됩니다.



 각각의 프레임들은 코드를 입력 할 수 있는 공간을 가지고 있지만, 모든 프레임에 코드를 입력 할 수 있는 것은 아닙니다. 프레임은 빈 프레임과 키 프레임 두 가지 종류가 있는데, 오직 키 프레임에만 코드를 입력 할 수 있습니다. Timeline을 선택하고 마우스 오른쪽 버튼을 클릭 하였을 때 아래 그림과 같이 Insert Keyframe을 이용하여 삽입한 프레임이 키 프레임입니다. 



 빈 프레임은 프레임에 아무런 표시가 없지만 키 프레임은 아래쪽에 원이 표시 되어 구분 할 수 있습니다. Timeline에는 오직 키 프레임에만 코드를 입력할 수 있고, 타임라인 위에 작성 되어지는 AS는 키 프레임의 순서에 따라 실행 되게 됩니다. 1 프레임에 작성된 AS 가 먼저 실행이 되고 시간의 흐름에 따라 2,3,4 .... 순서대로 실행됩니다. 예를 들어 보겠습니다. 


 1. Flash CS를 실행시킨후, Flash File(Actionscript3.0) 로 새로운 파일을 생성 합니다.



2. 하단에 있는 Timeline의 1 프레임을 선택 한 후 F9를 눌러 Script를 입력 할 수 있는 창을 띄움니다.


3. Actions창에 다음 코드를 입력 합니다.

trace("프레임 1“);   // trace는 문자나 객체의 속성을 output창에 나타내 주는 메소드입니다. 



4. Timeline에서 15 프레임을 선택하고 F6 또는 마우스 오른쪽 버튼 - Insert keyframe을 선택 하여 15 프레임을 키 프레임으로 생성 합니다. 



5 . 위의 1~3 작업과 같이 F9를 눌러서 Actions창에 다음 코드를 입력 합니다.


trace("프레임 15“);


6. Crtl + Enter 또는 Control - Test Movie메뉴를 이용하여 지금까지 만든 작업을 실행 시킵니다. 


실행 결과

프레임 1

프레임 15

프레임 1

프레임 15

프레임 1

반복 ..... 


 

 결과에서 볼 수 있듯이 프레임의 순서에 따라 액션코드가 실행된다는 것과 마지막 프레임에 가서 멈추는 것이 아니라 계속 루프가 돈다는 것을 알 수 있습니다. 액션코드 및 애니메이션의 시작은 Timeline 위에 존재하는 재생헤드(빨간 라인)의 움직임에 따라 실행됩니다. fps를 조절 함에 따라 재생헤드의 움직임을 조작할 수 있는 것이고, 위의 예제와 같이 각각의 프레임에 입력된 코드가 순서에 따라 실행 되는 것처럼, 애니메이션도 각각의 프레임에서는 움직임이 없지만, 재생헤드가 이동함에 따라 움직이는 것처럼 보이게 되는 것입니다. 이렇게 Flash는 프레임을 이동하므로 액션과 이벤트가 실행되는 절차 기반 프로그래밍 구조를 가지고 있습니다.




Posted by Flash 동강
Flash Programming 란?2010.01.16 23:58


  예전부터 간간히 써오던 문서를 블로그에 올리기 시작하였습니다. 문서의 내용이 Flash 프로그래밍의 기초를 다루고 있고 제가 예전에 썼던 "동강의 AS3.0 강좌" 의 내용을 자세히 풀어 썼다고 보시면 될것 같습니다. 처음 Flash 공부를 시작 하시는 분들에게 도움이 되었으면 하네요. 문서 내용에 대한 질문은 댓글로 달아 주세요.

 

  • Flash 프로그래밍이란 ?

 

 새롭게 Flash 를 배우려고 하시는 분들은 Flash 버젼은 뭐가 있고 언어는 뭘로 시작해야 하는지 막막 하실 겁니다. 우선은 Actionscript3.0 학습법을 읽고 본 문서를 보는 것을 추천 드립니다. 그러면 자연스레 AS3.0 과 Flash CS3 이상의 Flash IDE로 공부를 해야 겠다는 마음을 먹으실 겁니다. 본 문서는 Flash CS4 로 진행 됩니다.

 

 

 예전에 쓴 문서를 보면 왜 Actionscript3.0(이하 AS3.0) 을 사용해야만 하는가에 대해 다루고 있습니다. 하지만 AS2.0 보다 좋다는 것을 알았다고 해서 그동안 편리하게 사용해왔던 AS2.0에서 AS3.0으로 옮기기란 여간 힘든 일이 아닙니다. 저 또한 AS1.0, 2.0을 사용하여 Actionscript 프로그래밍을 시작해서, AS3.0으로 옮기기까지는 적지 않은 노력을 해야만 했습니다.

 

 Flash 프로그래밍은 이미 많은 개발자들이 사용하고 있는 C, C++, Java 보다 쉬워 보이면서 접근하기 어려운 면을 가지고 있습니다. 물론 개인적인 차이도 있겠지만, 제 주위에는 Java를 하던 C 를 하던 AS는 프로그래밍 언어 이면서 조금 다른 느낌이 난다고 어려워 하는 사람들을 보았습니다. 디자이너나 타언어의 개발자들이 Flash 프로그래밍을 어렵다고 생각하는 이유는 무엇일까요? 바로 Timeline 이 존재하기 때문입니다. 일반 언어와는 다르게 시간의 흐름에 따라 이벤트가 발생하고 애니메이션이 움직이는 Timeline 의 존재가 있기 때문에 다들 어렵다고 합니다. 하지만 이러한 Timeline 이 있기 때문에 Flash 프로그래밍이 가능해 지는 것이고, 모든 Actionscript(이하 AS)의 원리는 이 Timeline에서부터 시작하게 됩니다.

 

 Flash CS4를 실행 시키면 흰색 캔버스가 눈에 들어옵니다.

 

 

앞에서 Flash는 Timeline을 가지고 있다고 말 하였는데, 위 그림 하단에 보이는 것이 바로 Timeline입니다. 이곳에 애니메이션을 적용하거나, Flash CS4에서 제공하는 많은 툴 작업을 통해 간단하게 플래시 애니메이션을 적용시킬 수 있는 공간입니다. 이 공간은 단지, 애니메이션을 위한 공간으로서 존재 하는 것은 아닙니다. Timeline 이 존재 하므로 Actionscript를 사용하지 않아도 화려한 모션이라든지, 간단한 인터렉티브가 가능해 집니다. (타임 라인에 코드 삽입도 가능합니다 )

 

  • Frame rate

 

Flash에는 Timeline이 존재함과 더불어 FPS(framerate)를 통해서 Flash가 SWF로 컴파일 됐을 때 렌더링 속도를 조절하는 방법을 제공해 주고 있습니다. 아래 그림에서 오른쪽에 FPS : 24.00 부분에서 이 속성을 조절할 수 있습니다.

 

 FPS 가 24 라는 의미는 1초에 24 프레임이 이동하는 속도로 렌더링을 하겠다는 의미입니다. 애니메이션에서 그림을 24 프레임으로 처리 했다는 의미와 같습니다. 이 FPS 는 보통 24~36 frame 으로 조절하여 사용합니다. 숫자가 커질수록 처리에 사용하는 프레임을 많이 사용하겠다는 의미이고 컴파일 된 SWF 는 더욱 부드러운 느낌을 줍니다. 반대로 작아질수록 화면이 자연스럽지 않고 끈기는 느낌을 주게 됩니다. 이러한 FPS를 조절하는 것은 작업자의 몫입니다. 물론 FPS를 높게 하여 더욱 부드러운 느낌을 주면 좋겠지만, FPS를 높게 설정 할수록 단위시간당 처리해야 되는 프레임 수가 늘어나므로 SWF가 요구 하게 되는 CPU 사용량을 증가 하게 됩니다. 더욱이 SWF는 주로 html 에 올려 웹에서 보여 지는 경우가 많기 때문에 FPS를 잘 설정 하여 테스트 하는 것이 중요합니다. 이 속성은 작업자가 fla파일 자체에서 컨트롤 할 수도 있지만 AS를 이용하여 동적으로 조작하는 것도 가능합니다. frameRate라는 속성을 조작하여, SWF가 전반적으로 CPU를 적게 차지하고 있을 때는 frameRate(fps)를 높게 주어 부드럽게 동작 시키고, 데이터를 불러 오는 작업이나, 한번에 많은 모션이 동작할 때에는 CPU의 부담을 덜어 주기 위에 frameRate는 줄이는 방법을 사용하기도 합니다.

Posted by Flash 동강
Actionscript3.02010.01.14 11:03

작년에 썼던 Javascript vs Actionscript 라는 글에서는 비교 관련 자료가 06년도의 Flash player 9 와 그때 당시의 브라우져를 대상으로 테스트한 것인데요. jacksondunstan.com 블로그에서 최근에 AS3 기반의 Flash player 10과 최근 브라우져의 Javascript 와 Performance 테스트를 한 포스팅이 있었네요. 아래는 테스트 한 결과 입니다.



참고 자료 :  AS3 vs Javascript Performance Test

                AS3 vs Javascript Performance Test Followup

                


Posted by Flash 동강
Actionscript3.02010.01.12 01:06

외부 데이터를 불러 와서 TextField 에 넣어 줄때, 외부 데이터 문자 길이를 UI 에 맞게 잘러서 나타내는 경우가 있습니다. 기본적으로 String 클래스에서 제공하는 substr 등을 이용하여 문자열을 보기 좋게 자르는데요. 여기서 소개 하는 방법은 substr 과 TextField 의 getLineOffset를 이용하여 한정된 라인에만 글짜를 출력 하는 방법 입니다.

var field:TextField = new TextField();
field.width = 250;
field.wordWrap = true;
field.text = "안녕하세요.이것은 테스트 입니다.안녕하세요.이것은 테스트 입니다.안녕하세요.이것은 테스트 입니다.";
addChild(field);
위의 코드를 출력하면 아래와 같은 결과가 나옵니다.


위와 같이 width 값은 고정되어 있고 wordWrap = true 로 TextField 의 자동 줄바꿈이 설정 되어 있을때 getLineOffset 을 이용하여 원하는 최대 라인수 보다 넘어 갔을때 그 다음 라인의 첫번째 문자 인덱스 값을 가져온 뒤에 그 인덱스의 -2 만큼 String 값을 잘라 버리는 방식 입니다. getLineOffset 의 설명은 아래와 같습니다. 

var field:TextField = new TextField();
field.width = 250;
field.wordWrap = true;
field.text = "안녕하세요.이것은 테스트 입니다.안녕하세요.이것은 테스트 입니다.안녕하세요.이것은 테스트 입니다.";
cutNumLines(field,2);
addChild(field);
function cutNumLines( $field:TextField,$maxLen:int ):void{
	if($field.numLines-1 < $maxLen) return;
	
	var idx:int = $field.getLineOffset($maxLen);
	$field.text = $field.text.substr(0,idx-2)+"..";
}

getLineOffset(lineIndex:int):int
lineIndex 매개 변수로 지정된 행에 있는 첫 문자의 문자 인덱스를 반환합니다.


위의 함수를 실행한 후의 결과는 다음과 같습니다.



'Actionscript3.0' 카테고리의 다른 글

AS3 vs Javascript Performance Test  (0) 2010.01.14
[AS3] TextField 에 한정된 라인에만 글짜 넣기  (0) 2010.01.12
Avoid ints in Actionscript  (10) 2009.11.14
Factory Pattern (AS3)  (0) 2009.10.25
Posted by Flash 동강
Actionscript3.02009.11.14 19:56

 오랜만에 블로그를 둘러 보다 흥미로운 포스팅을 보았는데요. Actionscript 로 작업할시 숫자 타입의 int 를 사용을 자제 하라는 내용 입니다. 일반적으로 생각하면 int 가 Number 보다 크기가 작으니 int 로 처리 하면 더 빠르다고 생각하는 분들이 많으실텐데요. 이 포스팅에서는 여러 이유를 통해 부정 하고 있습니다.


이유 1. Number 를 사용하는게 int를 사용하는 것 보다 빠르다.

아래 코드를 실행 시키면 어떤 결과가 나올까요? 


public function timingTest() : void
{
	var intTime : Number;
	var numberTime : Number;

	var i : int;
	var j : int = 0;

	intTime = (new Date()).time;
	for (i=0; i<10000000; i++)
		j = (j + 15) / 7;

	intTime = (new Date()).time - intTime;

	var n : Number;
	var m : Number = 0;

	numberTime = (new Date()).time;
	for (n=0; n<10000000; n++)
		m = (m + 15) / 7;

	numberTime = (new Date()).time - numberTime;

	var message : String =
		"int version: " + intTime + "ms\n" +
		"Number version: " + numberTime + "ms";

	Alert.show(message);
}

int 를 사용한 코드 : 331ms

number 를 사용한 코드 : 291ms

 

  조금 의아해 할수도 있는데요. number 가 조금 빠르게 나왔습니다. 여기서는 조금한 차이지만 더 많은 루프를 돌리면 더 많은 차이를 낼 것 입니다. 일반적으로 number 가 더 많은 대역의 숫자를 커버 하기 때문에 연산할때 더 느릴텐데 왜 number 를 사용한 코드가 더 빠르게 나온걸까요? 


 j = ( j + 15 ) / 7;


 연산 비교에 사용된 코드를 보면 나누기 연산을 하고 있습니다. 이 나누기 연산이 number 가 더 빠른 연산 속도를 낼 수 있었던 이유 입니다. 연산이 이루어 질때 시스템은 내부적으로 int 범위 내에서 처리 할 수 없는 것은 number (double) 로 바꾸어 처리 하기 때문에 int - > number 로 변환 하는 처리 비용이 더 들기 때문에 number 가 더 빠른 결과를 낸 것 입니다. 


이유 2. Number 는 더 많은 bit 를 가지고 있다.


Number를 나타내는 데이터 format 은 아래와 같습니다. int 에 비해 더 많은 데이터 범위를 저장 할 수 있고 ( 12 ~ 63 ) 연산이 손실되는 데이터 없이 이루어 집니다. 그 만큼 오차를 줄여서 계산할 수 있다는 의미 입니다. 


 S EEEEEEEEEEE FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

  0 1        11 12                                                63 


실제로 + 연산이나 - 연산에서는 int 를 이용한 연산이 더 빠릅니다. 하지만, number 에 비해서 많이 빠르지 않습니다. 아래 결과를 보면 gskinner 가 "Types in AS3: ints not so fast, uints slow!" 포스팅을 통해 퍼포먼스 테스트를 한 결과 입니다. int 는 number 에 비해 많이 빠르지 않고, 느릴때도 있으니 차라리 데이터 손실 없이 연산이 이루어 지는 number 를 주로 사용하는게 좋다는 내용 입니다.  


Assignment ( var a:TYPE = 0; )
int: 24-45ms
Number: 24-36ms
uint: 25-37ms

Statistically, they look the same, which is to be expected.

Assignment ( var a:TYPE = 0.5; )
int: 56-83ms
Number: 26-43ms
uint: 57-92ms

Predictably, Number is faster for fractional assignments, as the value does not need to be converted to an integer.

Division ( var a:TYPE = i/2; )
int: 60-105ms
Number: 34-64ms
uint: 184-278ms

Number is a much faster type for division, as expected from Sho's post. uint trails badly.

Multiplication ( var a:TYPE = i*2; )
int: 78-129ms
Number: 39-64ms
uint: 207-280ms

Similar results to division. I thought int might perform better as the value would never have to be converted to a float (whereas in division it would).

Addition ( var a:TYPE = i+2; )
int: 31-49ms
Number: 44-55ms
uint: 85-113ms

As expected from the plain iterator test, int is slightly faster for integer addition.

Bitshift ( var a:TYPE = i<<1; )
int: 31-63ms
Number: 61-114ms

uint: 71-130ms 


가장 좋은 방법은 상황에 따라서 Number 와 int 를 골라 쓰는 건데요. 그 판단이 항상 좋을 수는 없으니, 잘 생각해서 써야 할 것 같습니다. 실제로 "Types in AS3: ints not so fast, uints slow!" 의 댓글에서 Number 의 연산 퍼포먼스가 휠씬 떨어 진다는 내용도 있었습니다. 그러면 언제 int 를 사용하면 좋을까요? 


1. 별로 차이가 없겠지만, 메모리를 적게 쓰고 싶을때

2. var i : int = j / 2; 와 같이 int 를 사용할 때

3. 클라이언트와 서버 측의 통신이 이루어 질때 오차를 줄이고 싶을때 


아무리 여러 테스트가 있어도, 정답은 "상황에 따라 맞는 방법을 쓴다." 이네요.




'Actionscript3.0' 카테고리의 다른 글

[AS3] TextField 에 한정된 라인에만 글짜 넣기  (0) 2010.01.12
Avoid ints in Actionscript  (10) 2009.11.14
Factory Pattern (AS3)  (0) 2009.10.25
Actionscript3.0의 DisplayList  (2) 2009.09.22
Posted by Flash 동강
Actionscript3.02009.10.25 23:47

목적 : 애플리케이션을 특정 구현으로 부터 분리시킨다. 객체를 만드는 일을 한다.

(크리에이셔널 패턴 : 생성과정과 관련된 패턴)

팩토리 메소드 패턴 - 팩토리 메소드 패턴에서는 객체를 생성하기 위한 인터페이스를 정의하는데, 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하게 만듭니다. 팩토리 메소드 패턴을 이용하면 클래스의 인스턴스를 만드는 일을 서브클래스에게 맡긴다.


목적 : 두개나 그 이상으로 분리 됐지만 서로 관련이 있는 클래스들의 계층 구조를 엮어주기 위한 것이다.


- 상속을 통해서 객체를 만든다.

- 객체를 생성할 때는 클래스를 확장 하고 팩토리 메소드를 오버라이드 해야 한다.



Factory Pattern에서 중요시 하는 디자인 원칙

추상화된 것에 의존하도록 만들어라. 구상 클래스에 의존하도록 만들지 않도록 한다.


원칙에 도움이 될만한 가이드 라인

어떤 변수에도 구상 클래스에 대한 레퍼런스를 저장하지 않는다.

구상 클래스에서 유도된 클래스를 만들지 않는다

베이스 클래스에 이미 구현되어 있던 메소드를 오버라이드 하지 않는다.


추상 팩토리 패턴 - 추상 팩토리 패턴에서는 인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않고도 생성할 수 있다.

- 객체 구성을 통해 제품을 구현 한다.

- 새로운 제품을 추가 하려면 인터페이스를 바꿔야  한다.

- 팩토리 메소드를 써서 구상 팩토리를 구현하는 경우가 종종 있다.



결론 : 팩토리는 구상 클래스가 아닌 추상 클래스/인터페이스에 맞춰서 코딩할 수 있게 해 주는 기법이다.


'Actionscript3.0' 카테고리의 다른 글

Avoid ints in Actionscript  (10) 2009.11.14
Factory Pattern (AS3)  (0) 2009.10.25
Actionscript3.0의 DisplayList  (2) 2009.09.22
What is "Flashplatform" ?  (3) 2009.08.25
Posted by Flash 동강
Actionscript3.02009.08.21 16:48

OpenCV란 무엇인가?

OpenCV

OpenCV(영어: Open Computer Vision)은 오픈소스 컴퓨터 비전 C 라이브러리이다. 원래 인텔에서 개발되었다. 현재 버전 1.0이 나와있으며 윈도, 리눅스 플랫폼에서 사용할 수 있다. 실시간 이미지 프로세싱에 중점을 둔 라이브러리이다. 인텔 CPU에서 사용되는 경우 속도의 향상을 볼 수 있는 Intel Performance Primitives (IPP)를 지원한다.


출처 : Daum 백과 사전


OpenCV 라이브러리를 이용하여 할 수 있는것?

OpenCV를 이용하면 영상처리 기술을 비교적 손쉽게 구현 할 수 있다. 입력과 출력 그리고 영상 처리에 대한 기본적인 기능들이 대부분 구현 되어 있다. 예를 들어 다음과 같은 작업 들을 할 수 있다.

- 얼굴 인식

- Corner Detection

- 증강 현실 (AR)

- 바코드 인식

- 문자 인식


OpenCV in Flash

OpenCV 라이브 러리를 Actionscript3.0 으로 컨버팅 하여 Flash 에서도 OpenCV 의 물건 인식 기능을 사용할 수 있게 되었다. Ohtsuka Masakazu 가 만든 이 라이브러리를 Marilenna 라는 프로젝트 명으로 Spark Project 에서 받아 볼 수 있다.


예제)
http://www.quasimondo.com/examples/face_detection/FaceDetector_Camera.html

http://www.francois-tarlier.com/blog/wp-content/uploads/2009/03/Marilena01/


'Actionscript3.0' 카테고리의 다른 글

What is "Flashplatform" ?  (3) 2009.08.25
OpenCV in Flash  (2) 2009.08.21
Flash player 의 보안  (17) 2009.06.24
AS3.0의 통신 - 브라우저와의 통신 (Javascript)  (11) 2009.06.02
Posted by Flash 동강
Actionscript3.02009.03.30 16:57
package{                

	import flash.display.MovieClip;		
	import flash.display.Sprite;		

	/**	 * @author kang	 */		

	public class ResourceTest extends Sprite {		

		public function ResourceTest() {						

			var mc : MovieClip = new MovieClip();                        

			addChild(mc);			

			mc.addEventListener(Event.ENTER_FRAME, onEnterframeHandler);		

		}	
		private function onEnterframeHandler(event : Event) : void {			

			trace("execute event");		

		}	

	}

}
위와 같은 코드가 있다고 하자. mc는 Event.ENTER_FRAME 이벤트를 가지고 있는 객체 이다. 하지만 어떠한 상황이 발생하여 mc를 메모리 해제를 할 경우가 발생 하였다. 많은 AS개발자들이 아래와 같은 코드를 입력하여 메모리를 해제 할 것이다. 


private function disposeMc(_mc:MovieClip):void{	
	if(_mc.parent != null)		
	_mc.parent.removeChild(_mc);		
	_mc = null;
}
mc 라는 객체의 모든 참조 값이 제거 되었으므로 mc는 Garbage collection의 수집대상이 될 것이다. 그리고 곧 메모리 상에서 사라질 것이다. 하지만 이 코드에는 문제가 있다. 이벤트를 등록했던 객체는 사라졌지만, 등록된 이벤트 자체는 사라지지 않았다. 그래서 output 창에는 execute event 메시지가 계속호출 될 것이다. 많은 Flash 개발자들이 잘못 알고 있는게 해당 객체를 제거 하면 그 객체에 등록 되어 있던 이벤트들도 제거 된다고 생각한다. 이는 아주 심각한 문제를 발생 시킬수 있는 원인을 제공한다. 컴퓨터가 느려 진다던지, 메모리 사용량 증가로 프로그램 자체나, 브라우져가 멈춰 버리는 일이 발생 할 수도 있다. 그러므로 객체를 메모리 상에서 제거 하기 전에 반드시 removeEventListener로 이벤트를 반드시 해제 해야 한다. addEventListener 의 파라미터로 약한참조를 해 주면 객체가 제거 되면 그 객체에 등록되어 있는 이벤트들도 제거 되지만 약한 참조로 했을때 불편한 점이 많기 때문에 기본값은 강한참조로 되어 있다. 
addEventListener()메서드

public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void

useWeakReference는 false 값이 기본으로 강한 참조이다. 하지만 이 파라미터를 true로 넘겨 주면 약한 참조가 된다. 위에서 언급했듯이 약한 참조로 등록된 이벤트들은 해당 객체가 제거 되었을때 같이 메모리에서 제거 된다.



이와 비슷한 경우가 MovieClip을 사용할때 발생할 수 있다. 예를 들어 다음과 같이 1~40frame까지 계속
 

루프를 도는 MovieClip이 있다고 하자. 이렇게 루프를 돌고 있는 도중 갑자기 이 무비 클립을 메모리 상에서 제거 하면 어떤 일이 발생 할까?? 결과는 위 ENTER_FRAME 이벤트에서와 같이 계속 루프를 도는 현상이 발생한다. 계속 루프를 돈다는 것은 그 만큼 CPU를 사용한다는 말이 되고, 메모리 낭비를 하고 있다는 말이 된다. 하지만, 이걸 인식 하지 못하고 그냥 MovieClip만 제거 하면 해당 무비 클립에 대한 모든 것들이 메모리 상에서 없어 진다고 잘 못 생각하고 있는것이다. 그러므로 위와 같이 MovieClip을 사용한 작업을 할때는 꼭 MovieClip을 stop() 해 준뒤에 메모리를 해제 해 줘야 한다. stop 해주지 않고 메모리를 해제 했다간, 모든 참조 값들이 사라 졌기 때문에 해당 타임라인을 멈출 수 있는 방법이 존재 하지 않는다. 

이러한 리소스 관리 문제는 위의 두가지 경우에만 국한된 것이 아니다. AS에서 제공하는 Sound 나 Loader를 이용한 이미지로드 및 SWF 로드 또는 Video 작업을 할때 모두 위와 같은 메모리 문제가 발생 할 수 있다. 이 사실을 항상 유념하고 Flash 작업을 해야 한다. 더 자세한 AS3에서의 메모리 관리 방법은 다음 링크를 통해 확인 하길 바란다. 




예제다운로드

아무리 여러 테스트가 있어도, 정답은 "상황에 따라 맞는 방법을 쓴다." 이네요.



Posted by Flash 동강