플래시 플레이어에는 AVM이라는 액션스크립트 판독/실행기와 렌더링을 담당하는 렌더러가 있다. enterFrame이벤트인 경우에는 frameRate에 의존하여 실행속도(실행횟수)를 결정하게 되는데 마우스 이벤트인 경우에는 재생속도와 관계없이 독립적으로 실행을 한다. 따라서 frameRate가 낮을 경우에 버튼등을 클릭하여 화면에 표현하려면 다음 렌더링엔진이 실행할 때 까지 기다려야한다. 즉 frameRate를 초당1씩 실행하고 실행시 바로 클릭하여 어떤 액션을 화면을 통해 보여진다면 1초뒤에 클릭한 액션이 가시적으로 표현이 된다.
그러한 경우 AS1에서도 제공되었던 updateAfterEvent()를 호출하여 강제로 렌더러를 실행시킨다. updateAfterEvent가 호출되는 즉시 화면이 갱신되므로 frameRate에 영향을 받지않는 마우스 이벤트를 구현할 수 있게 된다.
신고
Posted by 정윤수 버터백통
마우스를 이용하여 많은 작업을 하다보면 현재 이벤트를 반환하는 객체상에 마우스 좌표를 전역 값으로 사용해야 하는 경우가 종종 발생한다. AS1에서는 _root._xmouse와 _root._ymouse라는 속성을 사용하여 전역(절대)좌표를 알아 낼 수 가있었는데 AS3으로 오면서 localToGlobal라는 메소드를 통해 전역좌표 값을 알아내야한다.
localToGlobal를 사용하기 위해서는 마우스이벤트에서 받은 지역 좌표 값을 저장한 Point와 함께 사용한다.

이벤트를 발생하는 객체.localToGlobal( 객체의 지역좌표값 )

가령 e로 넘어오는 객체의 지역 좌표를 localPoint라는 포인트에 저장하고 전역좌표로 변환하는 변수를globalPoint 라고 한다면 아래와 같이 변수를 선언하면 된다.
var localPoint:Point = new Point( e.localX , e.localY );
var globalPoint:Point = e.target.localToGlobal( localPoint );

경로에 해당하는 객체의 지역좌표 값을 localToGlobal()를 통하여 전역 좌표값으로 변환한다.
신고
Posted by 정윤수 버터백통
외부에서 이미지 파일을 불러오는 것은 컴파일시 [Embed]를 사용하여 swf파일안에 포함시킬 수 있다. 하지만 실행중에 이미지를 불러오려면 Load라는 클래스를 사용하여야한다. Load클래스는 이미지파일이나 비디오등의 visual관련된 파일을 불러오는 역할을 담당하고 URLLoader는 데이터를 주고 받는데 사용한다.

Loader를 통해 불러올 수 있는 파일은 jpg , gif , png , swf가 있고 load라는 메서드를 통해 파일을 불러온다.
외부의 파일로 접근하기 위해서는 Loader클래스 단독적으로 사용할 수 없다. 서버나 로컬에 접근할 수 있는 통로를 담당하는 URLRequest라는 클래스와 함께 사용한다.
 var ldr:Loader = new Loader();
ldr.load( new URLRequest( "링크" ));

위의 코드는  로더 클래스를 통해 외부 이미지를 불러오는 명령이다. 그리고 호출이후 어떠한 상태인지를 알수 있는 여러가지 이벤트를 사용할 수 있다.

* 이벤트
Event.OPEN : 로드가 시작될 때 전달됩니다.

ProgressEvent.PROGRESS : 파일이 로드되는 동안 계속해서 발생.

Event.COMPLETE : 파일 다운로드가 완료된 후, 로드된 무비 클립의 메서드와 속성이 사용 가능한 상태가 되기 전에 전달.

Event.INIT : 로드된 SWF 파일을 조작할 수 있도록, 로드된 SWF 파일의 속성과 메서드가 액세스 가능한 상태가 된 후에 전달됩니다. 이 이벤트는 complete 핸들러에 앞서 전달됩니다. 스트리밍 SWF 파일의 경우 init 이벤트는 complete 이벤트보다 훨씬 더 이전에 발생할 수 있습니다. 대부분의 경우에는 init 핸들러를 사용합니다.

HTTPStatusEvent.HTTP_STATUS : 로드 중 실패한 HTTP요청이 감지될 때 발생

IOErrorEvent.IO_ERROR : 파일을 로드할 수 없는 경우 또는 로드 프로세스 중 오류가 발생.

SecurityErrorEvent.SECURITY_ERROR :  보안샌드박스 때문에 로드할 수 없을 때 발생한다.

이러한 이벤트는 Loader클래스에 직접 사용하는 것이 아니고 contentLoaderInfo라는 속성에 리스너를 추가한다. contentLoaderInfo는 어떠한 대상이 로드될 때의 정보를 파악하여 제공하기 위해 설계된 것이다.

Loader클래스는 DisplayObjectContainer를 상속받은 클래스이다. 따라서 불러들인 컨텐츠는 Loader안에 존재하며 content속성을 통해서 컨텐츠에 접근할 수 있다.
가령 A.swf에 run라는 메서드가 있다. 이 A.swf파일을 ldr이라는 delegate로 불러들였을 때  run를 호출하기 위해서 다음과 같이 코딩한다.
var movie:* = ldr.content;
movie.run();

위에 movie의 데이터타입을 *로 설정한것은 현재 이 프로젝트에는 run이라는 메서드가 없으므로 에러를 발생한다. 이를 방지하기 위한 처리이다.

* 외부에서 이미지파일의 데이터 자체를 받아오는 경우 인코더가 필요하며 ByteArray로 변환된 데이터를 loadBytes라는 명령문으로 이미지처리 할 수있다.
신고
Posted by 정윤수 버터백통

플래시에서 버튼심벌로 등록을 하면 4개의 상태 프레임이 나온다.
up과 over , down , hit이라는 프레임으로 심플버튼에서 역시 4개의 상태를 구분하는 upState,overState,downState, hitTestState 속성이 있다. 이 속성들은 대입식으로 디스플레이 오브젝트를 값을 설정하여야 하고 반드시 hitTestState를 설정하여야 버튼으로 작동하게 된다.

upState : 평상시의 디스플레이 상태
overState : 마우스 커서가 ht영역에 닿을 때의 디스플레이 상태
downState : 마우스로 클릭하였을 때의 디스플레이 상태
hitTestState : 버튼의 영역을 결정하는 곳으로 통상 버튼의 up영역을 사용한다.


var sbtn:SimpleButton = new SimpleButton();
sbtn.upState = createRect( 0xFF0000 , 100 , 100 );
sbtn.overState = createRect( 0x00FF00 , 100 , 100 );
sbtn.downState = createRect( 0x0000FF , 100 , 100 );
sbtn.hitTestState = sbtn.upState;
sbtn.addEventListener( MouseEvent.ROLL_OVER , onOver );
sbtn.addEventListener( MouseEvent.CLICK , onConfirm );
addChild( sbtn );
 
function createRect( color:int , width:int , height:int ):Shape
  {
   var rect:Shape = new Shape();
   rect.graphics.beginFill( color );
   rect.graphics.drawRect( 0,0, width , height );
   rect.graphics.endFill();
   return rect;
  }
 
function onOver( e:MouseEvent ):void
  {
   trace("SimpleButton Over.")
  }
 
function onConfirm( e:MouseEvent ):void
  {
   trace("확인을 눌렀습니다.")
  }


이 처럼 작성된 버튼에 마우스를 가져다 대면 "SimpleButton Over."라고 출력하게 된다. 또 버튼을 클릭하게 되면 "확인을 눌렀습니다."라는 메세지를 볼 것이다.

신고
Posted by 정윤수 버터백통

컨테이너의 인덱스 번호가 큰것이 앞으로 나와 보다 작은 인덱스의 객체를 가린다고 설명하였다. 그렇다면 이미 화면에 붙어있는 객체의 인덱스 순서를 바꾸어 앞으로 혹은 뒤로 이동시키고자 할때는 setChildIndex()를 사용한다.

* setChildIndex( 이동할 객체 , 이동할 인덱스번호 )
어떠한 컨테이너에 10개의 객체가 붙어있다고 가정하면 그 컨테이너의 인덱스 범위는 0~9까지 이다. 이 컨텐이너에 제일 앞에서 두번째인 8번인덱스에 객체를 붙이고자 한다면 setChildIndex( 객체 , 8 )이라고 입력하면 된다. 또는 특정 객체 green의 위치에 앞에 붙이고자 할때 green의 인덱스 번호를 구하기 위해서는 getChildIndex라는 메서드르 사용한다. setChildIndex( 객체, getChildIndex(green) ) 이 처럼 green의 인덱스값을 구하여 그 위치에 객체를 이동 시키면 green의 인덱스는 1증가하여 해당 객체 앞에 놓이게 된다.

var red:Shape = new Shape();
red.graphics.beginFill(0xFF0000)
red.graphics.drawRect(0,0,100,100)
red.graphics.endFill();
red.x = 50
addChild( red )

var green:Shape = new Shape();
green.graphics.beginFill(0x00FF00)
green.graphics.drawRect(0,0,100,100)
green.graphics.endFill();
green.x = 100
addChild( green )

var blue:Shape = new Shape();
blue.graphics.beginFill(0x0000FF)
blue.graphics.drawRect(0,0,100,100)
blue.graphics.endFill();
blue.x = 150
addChild( blue )

var gray:Shape = new Shape();
gray.graphics.beginFill(0x666666)
gray.graphics.drawRect(0,0,100,100)
gray.graphics.endFill();
gray.x = 80
gray.y = -50
addChild( gray )

setChildIndex( gray , getChildIndex(green) )

* getChildIndex( 인덱스번호를 알려는 객체 )
getChildIndex은 어떠한 특정 객체의 인덱스값을 반환하는 메서드이다.


* getChildAt( 인덱스번호 )
delegate한 객체의 이름을 모르고 인덱스 번호를 알고있을 때 해당 객체로 접근하는 메서드이다.

신고
Posted by 정윤수 버터백통

addChild또는 addChildAt을 통하여 디스플레이 컨테이너에 추가된 객체를 지우고자 한다면 removeChild()또는 removeChildAt()을 통하여 제거해야 한다.

* removeChild( 제거할 객체 )
removeChild는 제거할 delegate를 통해 객체를 제거한다.


* removeChildAt( 인덱스번호 )
removeChildAt는 컨테이너의 인덱스번호를 참조하여 배치된 객체를 제거한다. 만얀 컨테이너의 모든 객체를 지우고자 한다면 순환문을 이용하여 배치된 객체를 제거한다.

참고 : 디스플레이 리스트에서 removeChild를 통하여 리스트에서 지우면 렌더링 엔진에서만 삭제되는 것일 뿐 객체가 완전히 삭제되는 것은 아니다. 만약 삭제하려면 객체를 참조하는 모든 것을 null로 설정해야 한다.

신고
Posted by 정윤수 버터백통
앞서 디스플레이 리스트라는 것을 공부하였다. 디스플레이 리스트는 화면에 보일수 있도록 렌더러가 그리는 대상 목록이 되는데 이 목록에 추가하기 위해서는 new생성자를 통해 AVM2에 추가하고 addChld()와 addChildAt() 메서드를 통하여 목록에 추가한다.

var red:Shape = new Shape();    //생성자를 통해 AVM에 등록한다.
red.graphics.beginFill(0xFF00FF)
red.graphics.drawRect(0,0,100,100)
red.graphics.endFill();
addChild( red )                       //addChild()를 통해 디스플레이 리스트에 등록시킨다.

* addChild( 화면에 붙일 객체)
컨테이너에 추가할 객체를 매개변수로 받아 렌더링 엔진의 디스플레이 리스트에 등록한다.
기본적으로 컨테이너에는 배열처럼 정수인덱스로 상,하를 구분하게 되는데 나중에 화면에 붙은addChild가 인덱스 값이 이전 객체보다 1이 더 크다.

* addChildAt( 화면에 붙일 객체 , 인덱스 번호 )
컨테이너에 붙일 객체를 2번 째 매개변수의 값으로 인덱싱하여 디스플레이 리스트에 등록한다.

* 컨테이너의 인덱스
컨테이너에는 배열처럼 정수색인 인덱스를 통해 객체의 깊이를 설정할거나 배치할 수 있다. 이 값은 0부터 화면에 붙은 자식수-1 만큼의 범위를 갖는다.
addChild( red1 )    
addChild( red2 )    
addChild( red3 )    
위처럼 3개의 객체가 어떤 컨테이너에 자식으로 추가 되었다면 red3이 화면 제일 앞쪽에 배치되며 red1,red2를 가리게 된다. 그리고 인덱스의 값은 2에 위치하게 된다.

이러한 인덱스는 자식이 추가되면 자동으로 1씩 증가하며 범위내에 빈공간이 없도록 배치한다. 예전 AS1에서는 swapDepth나 dupliacetMovieClip , attachMovie..등을 통하여 인덱스를 설정하였는데 인덱스 중간에 빈값이 존재하고 개발자가 입력하는 값에 의존하였다. 따라서 이로인한 객체간 인덱스 충돌을 개발자가 신경써서 코딩하여야 했지만 이제는 자동으로 관리하게 되었다. 그리고 인덱스 범위내에 객체가 지워지면 자동으로 뒤에 객체들이 앞으로 당겨져 빈공간을 채워주도록 설계가 되었다. 단 addChildAt()을 통하여 이미 채워진 인덱스에 객체를 넣거나 범위를 벗어난 값으로 배치하려 하면 에러를 발생하게 된다.

* 부모 컨테이너의 교체
A.addChild( red1 )    
A.addChild( red2 )    
A.addChild( red3 )  
B.addChild( red1 )    <- red1을 B로 이동
위처럼 red1이 A에서 B로 이동하게 되었다. 예전 같으면 A에 red1을 제거하고 새로운 red1을 만들어 B객체에 넣어 주어야 했다. 하지만 AS3에서는 위의 코드처럼 A에 addChild한 상태임에도 불구하고 B에 다시 red1을 addChild하면 자동으로 A에서는 객체가 제거되고 B의 자식으로 붙게 된다. 따라서 A의 자식수는 2개이고 B의 자식수는 1의 값으로 설정된다.









신고
Posted by 정윤수 버터백통
디스플레이 리스트라는 것은 플레시플레이어의 렌더러를 통해 화면에 그려질 객체의 리스트이다. AS3를 인식할 수 있는 플래시 플레이어는 9버전 이상부터 지원하는데 AVM2(actionscript virtual Machine)라는 액션스크립트 판독/실행기와 렌더링을 담당하는 렌더러를 포함하고있다. AS3이전 버전의 AS는 무비클립이 생성될 때 자동으로 화면에 그려지게 되고 자신이 속한 부모를 바꿀 수 없었다. 만약 부모를 옮겨야 한다면 삭제 후 새로 생성하는 과정을 거쳐야만 했다. 하지만 새로운 렌더러는 이러한 기능을 대폭 개선하여 유연한 구조와 렌더링 프로세스의 개선에 중점을 두었다.

* 디스플레이 리스트 3원소
스테이지 :
스테이지는 디스플레이 계층 구조의 최상위이다. 한 개의 무비당 유일한 한개의 스테이지를 가지고 있으며 한개의 디스플레이 컨테이너(main application class)를 갖는다. 그리고 모든 디스플레이 객체는 stage를 통하여 접근 할 수 있다.

디스플레이 컨테이너 : 객체 안에 다른 자식 객체를 가질 수 있는 객체이며 자식을 포함 할 수 있는 스테이지도 디스플레이 객체 컨테이너이고 Sprite,MovieClip, Shape도 디스플레이 객체 컨테이너이다. 디스플레이 객체 컨테이너가 디스플레이 리스트에서 지워지면 해당 컨테이너 안의 자식들도 디스플레이 리스트에서 지워진다.

디스플레이 객체 : 디스플레이 오브젝트는 눈에 보이는 원소이다. MovieClip, Sprite는 디스플레이 컨테이너인 동시에 디스플레이 오브젝트이고 TextField는 디스플레이 오브젝트이다. 이러한 디스플레이 오브젝트를 화면에 보이고자 한다면 디스플레이 리스트에 등록되어진 컨테이너에 붙여야 화면에 보여지게 된다.

[ 디스플레이 리스트 계층 구조 1]

사용자 삽입 이미지

[ 디스플레이 리스트 계층 구조 2]

사용자 삽입 이미지

DisplayObject :
DisplayObject 클래스는 표시 목록에 배치할 수 있는 모든 객체의 기본 클래스입니다.

Bitmap :

Bitmap 클래스는 비트맵 이미지를 표시하는 표시 객체를 나타냅니다.

InteractiveObject :

InteractiveObject 클래스는 사용자가 마우스와 키보드를 사용하여 상호 작용할 수 있는 모든 표시 객체의 추상 기본 클래스입니다

MorphShape :

MorphShape 클래스는 표시 목록에서 MorphShape 객체를 나타냅니다. MorphShape 객체는 ActionScript에서 직접 만들 수 없으며, Flash 제작 도구에서 모양 트윈을 만들 때 함께 만들어집니다.

Shape :

Shape 클래스는 ActionScript 드로잉 API를 사용하여 가벼운 모양을 만드는 데 사용됩니다. Shape 클래스에는 Graphics 클래스의 메서드에 액세스할 수 있게 해 주는 graphics 속성이 포함됩니다.

StaticText :

이 클래스는 표시 목록의 StaticText 객체를 나타냅니다. ActionScript로는 StaticText 객체를 만들 수 없습니다. StaticText 객체를 만들려면 제작 도구를 사용해야 합니다.

Video :

Video 클래스를 사용하면 SWF 파일에 포함하지 않고도 응용 프로그램에서 라이브 스트리밍 비디오를 표시할 수 있습니다.

DisplayObjectContainer :

DisplayObjectContainer 클래스는 표시 목록에서 표시 객체 컨테이너 역할을 할 수 있는 모든 객체에 대한 기본 클래스입니다.

SimpleButton :

SimpleButton 클래스를 사용하여 SWF 파일에 있는 버튼 심볼의 모든 인스턴스를 제어할 수 있습니다. 제작 도구에서 버튼 인스턴스를 만든 후 SimpleButton 클래스의 메서드와 속성을 사용하여 ActionScript에서 버튼을 조작할 수 있습니다.

TextField :

TextField 클래스를 사용하면 텍스트 표시 및 입력을 위한 표시 객체를 만들 수 있습니다.

Loader :

Loader 클래스는 SWF 파일이나 이미지(JPG, PNG 또는 GIF) 파일을 로드하는 데 사용됩니다.

Sprite :

Sprite 객체는 무비 클립과 유사하지만, 타임라인이 없기 때문에 타임라인이 필요 없는 객체에 적합한 기본 클래스입니다.

Stage :

전역적으로 액세스할 수 없으며 DisplayObject 인스턴스의 stage 속성을 통해 액세스해야 합니다.

MovieClip :

MovieClip 클래스는 Sprite, DisplayObjectContainer, InteractiveObject, DisplayObject 및 EventDispatcher 클래스로부터 상속됩니다. Sprite 객체와 달리 MovieClip 객체에는 타임라인이 있습니다.


신고
Posted by 정윤수 버터백통
AS3.0 Cookbook/배열2008.07.20 14:00

hash table은 원소의 번호가 달리없이 키로만 구성되어 있으므로 정수색인 배열처럼 for를 사용하여 원소로 접근할 수 가 없다. 따라서 키를 검사하는  for in문을 사용한다. for in문은 선택된 연관배열의 키를 특변 변수에 담아 그 이름과 값을 검색할 수 있다.

* for in 선언법
for( key  in Object ){
   // Action
}


가령 다음과 같은 도서 데이터를 검사할 수 있고 이들을 배열에 넣어서 sortOn을 하여 필요한 데이터로 정렬 또는 가공할 수 있다.
var book1:Object = { "writer":"이외수" , "title":"사람사는 마을", "cost":10000  };
var book2:Object = { "writer":"박한별" , "title":"연예계 생활", "cost":5000  };
var book3:Object = { "writer":"브루스" , "title":"men of world", "cost":18000  };
var book4:Object = { "writer":"오라일리" , "title":"cool codes", "cost":28000  };
for (var i:int=1; i<=4; i++) {
 for ( var atrb:String in this["book" + i] ) {
  trace( atrb , ":" , this["book"+i][atrb] );
 }
}


출력
cost : 10000
title : 사람사는 마을
writer : 이외수
cost : 5000
title : 연예계 생활
writer : 박한별
cost : 18000
title : men of world
writer : 브루스
cost : 28000
title : cool codes
writer : 오라일리

* for in 문은 내장된 속성까지 보여주지 않는다.

신고
Posted by 정윤수 버터백통
AS3.0 Cookbook/배열2008.07.20 13:50

연관배열은 AS3에서 Object라는 클래스로 최상위 객체로 제공한다.
선언은 키와 값을 같이 작성하며 객체문자( {} )안에 작성한다.
var obj:Object = { "키" : 값 , "키":값 ... }

접근이나 출력은 해당 배열의 키명으로 접근한다.
var obj:Object = {  "country":"korea" ,  "maker":"hyundai" , "model":"pony" , "year":1982  }
trace( obj.model )  // 출력 : pony

신고
Posted by 정윤수 버터백통
AS3.0 Cookbook/배열2008.07.20 13:39

배열 원소의 무작위 정렬은 sort와 random을 같이 사용한다. sort()에서 두 원소의 비교 함수의 값이 음수일 때 앞의 원소가 두번째 원소앞에 위치하게 되고 비교함수의 값이 양수이면 첫 번째 원소는 두 번째 원소 뒤로 위치하게 된다. 따라서 sort( randomSort )에 비교 값을 양수 또는 음수의 값을 랜덤하게 넣어주면 원소끼리의 순서가 바뀌게 된다.

* sort의 비교함수 값을 임의의 값을 바꾸어 준다.
private function randomSort( elementA:Object , elementB:Object ):Number
{
   var num:Number = (Math.random() - 0.5) * 10;
   return num
}

Math.random은 0.0에서 1.0까지의 값이 랜던하게 반환한다. 따라서 -0.5를 하면 -0.5 에서 0.5까지 양수와 음수를 반환하게 되는데 각 값이 너무 작은 값이기에 소수점 한자리로 포인터를 이동시켜준다.
 




신고
Posted by 정윤수 버터백통
AS3.0 Cookbook/배열2008.07.20 13:31

 배열의 원소를 정렬하는 메서드는 sort와 sortOn이 있다. sort는 기본적인 Array클래스의 정렬에 사용되며 몇개의 상수로 정렬기준을 정할 수 있다. sortOn은 연관배열의 키를 기준으로 정렬을 한다.

sort에는 다음과 같은 상수가 있다
* 배열 정렬 상수
Array.CASEINSENSITIVE : 대소문자 구분 없이 오름차순으로 정렬
Array.DESCENDING : 내림차순으로 정렬
Array.NUMERIC : 숫자를 기준으로 오름차순
Array.RETURNINDEXEDARRAY : 오름차순으로 정렬하고 그 원소 번호를 반환
Array.UNIQUESORT : 오른차순으로 정렬하자는 않고 원소의 번호만 반환 , 같은 값이 있을 경우 0을 반환


* Array.NUMERIC을 제외한 sort는 배열안에 숫자가 있을 경우 아스키로 취급하여 그 값의 크기로 정렬한다.
* Array.UNIQUESORT를 제외하고는 전부 원소의 상태를 정렬한다.

sortOn은 키를 기준으로 정렬한다.
옵션으로 키와 소트 상수를 제공한다.

sort를 잘사용하면 편리한 점이 많이 있다. 그 중에 숫자 값의 최소와 최대를 구하면 간단히 숫자정렬을 하면된다.
var ary:Array = [10 , 24 , 5 , 8];
ary.sort( Array.NUMERIC );
trace("min :" , ary[0]);
trace("max :" , ary[ary.length - 1]);
출력 : min = 5 , max = 24


신고
Posted by 정윤수 버터백통
AS3.0 Cookbook/배열2008.07.13 18:27

배열을 만들 때는 가독성있게 값을 참조하기 위해 연관배열을 사용한다. 연관배열은 Object라는 클래스로 이름과 값을 같이 저장하는 배열을 말하는데 가령 자동차 회사에서 연식과 색상 제조회사에 대한 데이터를 아래와 같이 만들었다고 할 때 이 값들을 참조하기 위해서는 알수 없는 숫자들로만 참조해야 한다.
var car:Array = [];
car.push(["은색" , "2000년식" , "대우"]);
car.push(["흰색" , "2003년식" , "현대"]);
car.push(["빨강색" , "1998년식" , "현대"]);
car.push(["파랑색" , "20002년식" , "기아"]);

var len:int = car.length;
for (var i:int=0; i<len; i++) {
 trace(car[i][0] + "   " + car[i][1] + "    " + car[i][2]);
}

출력 :
은색   2000년식    대우
흰색   2003년식    현대
빨강색   1998년식    현대
파랑색   20002년식    기아


위처럼 누군가가 이 코드를 보면서 어떤 데이터가 있는 추측하기란 실행전까진 쉽지않다. 따라서 원소의 이름을 붙인 연관배열을 정수색인 배열에 포함하여 그 값을 유추하기 쉽도록 바구어 보자.
var car:Array = [];
car.push({color:"은색" , year:"2000년식" , maker:"대우"});
car.push({color:"흰색" , year:"2003년식" , maker:"현대"});
car.push({color:"빨강색" , year:"1998년식" , maker:"현대"});
car.push({color:"파랑색" , year:"20002년식" , maker:"기아"});

var len:int = car.length;
for (var i:int=0; i<len; i++) {
 trace(car[i].color + "   " + car[i].year + "    " + car[i].maker);
}
출력 :
은색   2000년식    대우
흰색   2003년식    현대
빨강색   1998년식    현대
파랑색   20002년식    기아

이처럼 연관배열을 사용하면 2차 3차원 그 이상의 배열일지라도 무섭지 않다!! 뭐 심하게 다차원이라면 싫지만요..

* 연관배열은 중괄호 {}로서 그 값을 설정한다.
var num:Object = { name:"홍길동" , ....}
중괄호( {} )안의 내용은 네임탭과 값 그리고 나열은 정수색인 배열처럼 컴머를 기준으로 나열된다.

신고
Posted by 정윤수 버터백통
AS3.0 Cookbook/배열2008.07.06 21:59
많은 데이터를 xml로 파싱하여 보내야하는데 실 데이터 보다는 부가설명이 더 많은 경우 특정 심벌을 사용하여 데이터 그룹을 만든다...
<user id="Flex" name="홍길동" addr="서울 강남구 청담1동" phone="010-555-5555" job="개발자"/> 라는 데이터가 있다...물론 위에 정의된 속성 정도는 많지 않기 때문에 경우에 따라 보기좋게 그냥 사용하여도 무방하지만 이러한 데이터 노드가 1000개..또는 노드는 적더라도 속성이 많아서 데이터 자체의 용량이 무거울 때 보통 특수 심벌을 정하여 데이터를 묶는다.
<user>"Flex|홍길동|서울 강남구 청담1동|010-555-5555|개발자"</user>
이처럼 가독성은 떨어지지만 불필요한 속성 이름들을 줄여주면 와이브로나 무선인터넷을 사용하는 생보사 직원들에게는 1초라도 빨리 데이터를 넘겨주어 화면에 출력하게 할 수 있다.
실제로 오래된 어떤 보험사의 경우 한번에 던져주는 데이터가 3메가 이상 던져주는 경우도 있었다..오래된 데이터 구조와 해를 거치면서 연관되고 묶여진 관련 데이터가 많아지고 현업에서는 손대기 싫다고 하더랍니다..그래서 우리 동료들이 무지 고생들 해서  통신 클래스를 새로 때려 만들어서 해결했다는 후담이 있다.

여튼 요는 불필요한 이름이라도 줄여 "데이터심벌데이터심벌데이터"과 같은 형태로 용량을 줄이고 이를 as3에서는 문자열을 쪼개서 데이타그리드를 만들어야 한다. 이때 걸쳐야하는 것이 배열이다...
가령 앞서 요약된데이터 ("Flex|홍길동|서울 강남구 청담1동|010-555-5555|개발자")가 들어오면 split("|")를 사용한다. 데이터의 문자열중에 "|"를 기준으로 좌우로 원소를 분해하여 배열에 포함시키거나 값으로 선언할 수 있다.
var user:Array = ( "Flex|홍길동|서울 강남구 청담1동|010-555-5555|개발자" ).split("|")
trace(user)    
// 출력 : Flex , 홍길동 , 서울 강남구 청담1동 , 010-555-5555 , 개발자

위의 코드는 심벌 "|"를 사용하여 데이터를 나누어 각 원소로 등록한 것이다.





신고
Posted by 정윤수 버터백통
Tip And Tech2008.07.06 14:48

AS3는 기본적으로 국제 표준인 UTF-8을 사용한 인코딩을 하고 있다. 하지만 경우에 따라서 시스템인코깅을 사용해야할 경우가 발생한다. 그럴때는 System.useCodePage를 설정한다.
* 국제 표준을 지키지 않고 현재 시스템의 인코딩을 사용하겠다.
System.useCodePage = true
* 국제표준 인코딩을 사용하겠다.(AS3 프로젝트 기본값)
System.useCodePage = false

그리고 프로젝트를 하다보면 여러단계의 서버를 걸치게 된다. 그때마다 도메인을 수정하기에 번거롭고 더욱 중요한것은 최종 테스트 서버에서 실서버에 오를때는 파일 수정없이 바로 올라가는 경우가 많다. 따라서 xml설정파일을 두어 경로 데이터를 수정하여 올리거나 내부적으로 URLManager에 자신의 도메인을 root.loaderInfo.url 통해얻어와 setter를 설정하여 사용하도록 한다.

신고
Posted by 정윤수 버터백통
Tip And Tech2008.07.06 14:01
swf에서는 flv파일을 재생할 수 있는 Video객체가 존재한다.
flv파일은 스트리밍이 가능한 파일이다 이는 곧 파일의 일부인 패킷(packet)단위의 데이터만 들어와도 재생할 수 있는 것이다.

* 스트리밍(streaming)
스트리밍의 정의는 파일의 일부만 존재하여도 재생 활용 할수 있는 의미를 갖는다.
현재 swf는 반스트리밍 파일이다 이는 root의 프레임단위 스트리밍이기 때문에 프레임에 모션을 담은 무비클립이나 loader를 통한 애니메이션이 존재한다면 재생 중 이를 다 받고 다음프레임의 정보를 다운로드하게 된다.
그렇기 때문에 모션이나 영상 개발시 프레임구조 또한 중요한 차지를 하게 된다. 이를 제외하고 swf에 포함되는 flv만 놓고 보았을 때는 스트리밍을 지원한다. 이때 파일을 제공하는 서버가 FMS가 아니면 progressive방식으로 스트리밍을 한다. progressive방식은 패킷단위로 저장된 정보순으로 재생을 하며 이를 벗어나서는(스킵) 재생할 수 없다. 하지만 FMS에서 제공하는 flv파일 재생은 nonprogressive가 된다.
nonprogressive는 클라이언트에 저장된 패킷(데이타)이 없더라도 가고자 하는 장면(시간)으로 이동 재생할 수 있는 마치 내 컴퓨터에 파일이 존재하는 것 처럼 사용할 수 있다.

참고) 영상(VOD)이나 음원(AOD)처럼 일부 패킷만으로  스트리밍이 가능하여 재생할 수(사용할 수 )있지만 zip , 이미지파일 , hwp , doc등 전체 파일포맷이 다운되어 완성되어 보여져야 하는 파일들은 스트리밍의 개념이 없다. 단 http://www.bytearray.org/에서 제공하는 ASZip같은 경우에는 압축파일이 전송된 양만큼 활용할 수 있다.


아래 그림은 swf에서 flv를 받는 과정을 그려보았다
사용자 삽입 이미지
swf에는 Video라는 객체가 있다. 이 객체는 제공받은 flv파일을 재생하기 위한 viewer인데 제공받기 까지의 과정에 2개의 필수 객체가 필요하다. 우선 어느 서버(경로)로 접근할 때 사용할 길(대역 : 帶域 )인 NetConnection 필요하다. 그리고 이를 관리할 NetStream이 필요하다. 비디오객체에서 필요한 요청을 할 때는 NetStream를 통해서 요청을 하고 NetStream는 NetConnection을 통해 서버에 던진다. 요청받은 일을한 서버는 응답을 NetConnection를 통해 되돌려주고 가만히 앉아서 기다리던 NetStream은 응답이 오자 결과를 자신을 바라 보고 있는 Video객체에 전달하도록 되어있다.

* NetConnection 역할
 - 단순히 서버와의 길을 연결하는 통신선이다

* NetStream(흐름관리자) 역할 
- 자신이 관리할 NetConnection를 정하여 서버에 요청을 하고 응답이 오면 값을 전달하는 객체이다.
- ordering(순서) : 재생 순서(시간)를 지켜서 데이터를 Netconnection을 통해 보내거나 받는다.
- jitter(지터) : 패킷과 패킷사이에 거리(시간차), 거리를 맞추기 위해서 NetStream이 조절한다.

* 비디오 객체
- 흐름을 타고 넘어온 데이터가 최종적으로 화면에 출력하는 객체

위처럼 각 역할을 맡은 객체들이 서로의 역할을 수행하면서 비디오 파일을 가져올 때 해당 파일에 필요한 메타정보를 반드시 가져와야 한다. 가령 비디오파일 확장자를 가지고는 있지만 실제 파일이 이미지나 기타 파일 포맷인지를 재생하기 전에 확인하는 절차가 필요하기 때문이다. 따라서 비디오 객체를 포함하는 클래스에는 public으로 onMetaDataonCuePoint라는 함수를 반드시 만들어 놓아야 한다.

참고) 메타데이타(부가 정보)
- 이미지의 메타데이타는 크게 아래와 같다
  [ 부가정보(이름 , 파일용량 , 가로 , 세로 , 확장자 .. ) ] [ 핵심데이터(블럭) ] [ 핵심데이터(블럭) ]..

- 동영상의 메타데이타도 이미지와 비슷한 정보를 갖는다.
  [ 부가정보(이름 , 파일용량 , 가로 , 세로 , 전체 재생길이 , 코덱...) ] [ 핵심데이터(블럭) ] ....
단 flv만의 부가적 특징이 바로 cuePoint가 있다. 이는 영상 중간 중간에 변수(정보)를 삽입할 수 있다.
따라서 AS3에서는 반드시 onMetaDataonCuePoint를 체크하여야 한다. FMS서버일 때 이러한 cuePoint를 체크하여 서버의 파일의 위치를 찾아가 바로 바로 재생할 수 있도록 하기 위해서 이다.

신고
Posted by 정윤수 버터백통
AS3.0 Cookbook/배열2008.06.29 16:28
일반적으로 배열하면 정수색인 배열을 많이 사용한다. 연관배열은 따로 오브젝트라고 호명하기도 한다.
배열의 선언법은 다양한다.
var ary = new Array();
ary = [ "처음 값" , "두번째 값" , "세번째 값"]

과 같이 new를 통해 메모리에 할당하고 ary에 Delegate한다. 배열 ary의 값을 입력하기 위한 두번째 코드에는
대괄호안에 컴머(,)로 구분하여 일련의 슬롯에 값을 위치한다. ary = [ "처음 값" , "두번째 값" , "세번째 값"]는
0번째 슬롯 즉 0번 원소의 값은 "처음 값"이라는 문자열이 들어있고 , 왼쪽에서 부터 3번째는 0부터 세어 2번 원소라 하고 그 값은 "세번째 값"이라는 문자열이 선언되었다.

trace( ary[0] )     // 출력 : "처음 값"
trace( ary[1] )     // 출력 : "두번째 값"
trace( ary[2] )     // 출력 : "세번째 값"


이처럼 정수 색인 배열은 최초로 선언되는 값(왼쪽 끝)의 원소를 0이라고 정하고 컴머로 각 원소를 1씩 증가하여 참조할 주소지를 정하게 된다. 따라서 정수 색인 배열의 원소는 다음과 같이 정해진다.
ary = [ 0번 원소 , 1번 원소 , 2번 원소 , 3번 원소....]

아래는 내가 자주 사용하는 선언식이다.
new Array()라는 생성자 없이 바로 변수명과 값을 선언한다.
var ary = [ "처음 값" , "두번째 값" , "세번째 값"]
또는 빈 배열이 필요할 때는 아래와 같이 빈값을 준다.
var ary = [ ]

값의 입력과 참조는 위와 같은 방법으로 사용하면 된다.
trace( ary[0] )     // 출력 : "처음 값"
trace( ary[1] )     // 출력 : "두번째 값"
trace( ary[2] )     // 출력 : "세번째 값
"

마지막으로 다음과 같은 선언식이 있다.
var ary = new Array( "처음 값" , "두번째 값" , "세번째 값" )
이처럼 생성자에서 바로 값을 주어 배열을 선언하기도 한다.

배열의 값을 위처럼 선언시 설정하기도 하지만 보통은 런타임시 값을 대입하거나 수정,설정할 때는 해당 원소를 찾아가 값을 선언한다.
가령 ary에 3번 원소에 값을 "네번째 값"이라고 선언하고 싶으면 아래와 같이 선언한다.
ary[3] = "네번째 값";
배열 ary를 출력하면 "처음 값" , "두번째 값" , "세번째 값" , "네번째 값"과 같이,
0~3까지 4개의 원소가 출력된다.

그럼 위의 배열에 다음과 같이 6번째 원소에 값을 입력하자.
ary[6] = "일곱번째 값"
출력하면 다음과 같이 나타난다.
"처음 값" , "두번째 값" , "세번째 값" , "네번째 값" , undefined , undefined , "일곱번째 값"
위와 같이 중간에 undefined 가 포함된 이유는 원소가 순차적으로 값을 가지고 선언된것이 아니라
원소 6이 문자열을 갖고 생성되면서 원소 4와 5에는 아무것도 없는 무( 無 )로서 undefined 로 표현된다.
* 참조 : undefined는 아무것도 값이나 이름조차 없는 공간이다.
null인 경우는 선언된 Delegate는 있지만 그 값이 비어있는 무( 無 )일때 표현된다.


이처럼 ary배열은 0부터 6원소까지 7개의 값을 갖는 배열이다. 이러한 배열의 길이는 구하는 것이 length()라는 메서드이다. 이 length()는 배열의 원소 길이를 정수로 반환한다.
var ary = [ "처음 값" , "두번째 값" , "세번째 값" , "네번째 값" ]
trace( ary.length() )     // 출력 : 4

배열의 길이는 자연수의 증가이므로 원소번호와 혼돈하면 안된다.
가령 ary = ["A"]라하면 0번째 원소를 갖은 길이 1인 배열이다.


[ Array 클래스의 메서드 ]
concat(... args):Array

매개 변수에 지정된 요소를 배열의 요소와 연결하여 새 배열을 만듭니다. Array

every(callback:Function, thisObject:* = null):Boolean
지정된 함수에 대해 false를 반환하는 항목에 도달할 때까지 배열의 각 항목에 테스트 함수를 실행합니다.

filter(callback:Function, thisObject:* = null):Array
배열의 각 항목에 테스트 함수를 실행하고 지정된 함수에 대해 true를 반환하는 모든 항목이 포함된 새 배열을 만듭니다.

forEach(callback:Function, thisObject:* = null):void
배열의 각 항목에 함수를 실행합니다.
 
indexOf(searchElement:*, fromIndex:int = 0):int
완전 항등 연산자(===)를 사용하여 배열의 항목을 검색하고 항목의 인덱스 위치를 반환합니다.
 
join(sep:*):String
배열의 요소를 문자열로 변환하고, 지정된 분리 기호를 요소 사이에 삽입하고, 요소를 서로 연결한 후 결과 문자열을 반환합니다.

lastIndexOf(searchElement:*, fromIndex:int = 0x7fffffff):int
배열의 마지막 항목부터 역순으로 항목을 검색하고 완전 항등 연산자(===)를 사용하여 일치하는 항목의 인덱스 위치를 반환합니다.

map(callback:Function, thisObject:* = null):Array
배열의 각 항목에 함수를 실행하고 원래 배열의 각 항목에 대한 함수 결과에 해당하는 항목으로 구성된 새 배열을 만듭니다.

pop():Object
배열에서 마지막 요소를 제거하고 해당 요소의 값을 반환합니다.
 
push(... args):uint
배열 끝에 하나 이상의 요소를 추가하고 배열의 새 길이를 반환합니다.

reverse():Array
배열의 순서를 뒤집습니다.
 
shift():Object
배열에서 첫 번째 요소를 제거하고 해당 요소를 반환합니다.

slice(startIndex:int = 0, endIndex:int = 16777215):Array
원본 배열에 포함된 요소 중 일정한 범위의 요소로 구성되는 새 배열을 반환하되, 원본 배열을 수정하지 않습니다.

some(callback:Function, thisObject:* = null):Boolean
true를 반환하는 항목에 도달할 때까지 배열의 각 항목에 테스트 함수를 실행합니다.

sort(... args):Array
배열의 요소를 정렬합니다.

sortOn(fieldName:Object, options:Object = null):Array
배열에 포함된 요소는 해당 배열 내의 하나 이상의 필드에 따라 정렬합니다.

splice(startIndex:int, deleteCount:uint, ... values):Array
배열에 요소를 추가하고 배열에서 요소를 제거합니다.

toLocaleString():String
지정된 배열의 요소를 나타내는 문자열을 반환합니다.

toString():String
지정된 배열의 요소를 나타내는 문자열을 반환합니다.

unshift(... args):uint
배열의 맨 앞에 하나 이상의 요소를 추가하고 배열의 새 길이를 반환합니다.


신고
Posted by 정윤수 버터백통
Tip And Tech2008.06.25 11:03

과거 AS1에서는 대부분의 클래스가 동적 클래스 이므로  런타임시 변수를 선언하고 값을 줄 수 있었다. 하지만 AS3로 오면서 Object와 Array클래스 MovieClip클래스를 제외한 대부분의 사용가능한 클래스가 동적객체가 아니고 일반 public으로 비동적 객체로 설정되어있다. 따라서 이러한 비동적 객체에 런타임 변수를 설정하고 할때는 Dictionary()클래스를 사용해야한다.

동적 객체는 런타임시 무비클립에 mc.testVar = "변수값" 이라고 변수와 값을 설정할 수 있지만 Sprite등의 비동적 객체에는 런타임 변수설정이 불가능하다.

* AS1처럼 동적 변수 설정(AS3에서도 동적객체이 이와 같이 선언 할 수 있다)
function init():void
{
var man1:Object = new Object()
var man2:Sprite = new Sprite(); 
var man3:MovieClip = new MovieClip();
var man4:Array = new Array()

man1.testVar = "var 1"
man2.testVar = "var 2" -> 비동적 클래스인 Sprite이므로 런타임 변수를 줄 수 없다(에러발생)
man3.testVar = "var 3"
man4.testVar = "var 4"
}

위의 코드처럼 동적 클래스는 Delegate된 인스턴스 네임에 직접 접근하여 따로 속성이 없어도 변수와 값을 설정할 수 있다.
그러나 플렉스에서 사용하는 대부분의 UI기능을 하는 클래스는 Sprite(프레임이 없는 클래스)를 사용한다. 이 Sprite클래스는 비동적 클래스이므로 내부에 public변수나 setter / getter등으로 자리를 컴파일 시 마련해 두어야 한다. 하지만 어떠한 상황에 따라 런타임 변수를 설정해야하는 경우 Dictionary를 이용해야한다.

* Dictionary()
변수명을 Dictionary의 클래스 Delegate로 사용하고 그 안에 참조할 인스턴스 객체를 대입시킵니다.
개념적으로는 사용할 변수를 미리 설정하고 참조대상을 정하면 그 참조대상에 변수와 값을 딕셔너리를 통해 참조할 수 있습니다.. 방식으로 보면 "객체.변수 = 값"과 같은 형태가 아니고 사용할 변수(딕셔너리클래스)를 미리 선언하고 어떤 객체가 쓸 것인가를 정하는 "변수[객체] = 값"으로 사용방법이 조금은 낯설어 보입니다.

var addr:Dictionary = new Dictionary( );
var nick:Dictionary = new Dictionary( );
var age:Dictionary = new Dictionary( );


addr[ man1 ] = "삼성동";
addr[ man2 ] = "청담동";
addr[ man3 ] = "역삼동";
addr[ man4 ] = "갈월동";
   
nick[ man1 ] = "man1"
nick[ man2 ] = "man2"
   
age[ man1 ] = "34";
age[ man2 ] = "36";
age[ man3 ] = "32";
age[ man4 ] = "28";


이처럼  참조할 변수를 Dictionary 클래스로 선언하여 변수의 그룹을 만들어 줍니다.. 가령 "학교, 주소 , 이름 .."등 사용할 변수를 미리 딕셔너리로 설정하고 그 변수를 참고해야할 클래스를 대입시킵니다.
위의 코드에서는 man1~man4는 주소와 나이를 모두 알수있는 dictionary()참조가 있지만 별명은 man1~man2만 보유하고 있습니다.

값의 참조는 addr[ man1 ]과 같이 합니다.
tracce( addr[ man1 ] )              // 출력 : "삼성동"

for(var i:int=1; i<=4; i++ ){
    trace(addr[ this["man"+i] ])    //출력 : "삼성동"  "청담동"  "역삼동"  "갈월동"

 }

* Dictionary() 클래스를 생성시 생성자 파라미터가 weakKeys라는 부울변수가 있다,
  이는 weak reference의 성분을 설정하여 가비지 컬렉터의 대상여부를 설정합니다.

신고
Posted by 정윤수 버터백통
Tip And Tech2008.06.24 12:15

*** 가비지 컬렉터 관련 이전내용을 아래 내용으로 업데이트 하였습니다. ***

현재는 디버거와 AIR프로젝트에서만 gc가 실행되고있습니다. 따라서 저를 포함한 많은 분들이 소위 낚였습니다. 자~알 실행되는 줄알고...하지만 일반 플레이어에서는 아무리 gc()를 실행하여도 메모리는 꿈쩍도 하지 않습니다.

많은 고민과 연구를 거듭한 결과 출처불명의 로컬커넥션을 이용한 방법이 있다고 들었고 시행착오와 명용이의 자문을 구해 테스트한 결과 정말 gc()가 실행되더랍니다..

로컬커넥션은 메모리에 통신이 가능한 주소지를 설정하여 이곳을 통해 send객체와 이를 바라보는 connect객체를 통해 서로다른 swf간 통신을 하게하는것입니다.
주소지의 등록은 connect("이름")을 통해 주소지를 등록하는데, 메모리에 같은 주소지를 두번 호출(할당)하게 되면 그때 에러를 발생하면서 시스템의 가비지 컬렉션이 실행하게 됩니다. 따라서 try~catch문을 사용하여 무비가 먹통이 되는것을 방지하여야 합니다.



이 파일을 디버거가 아닌 플레이어 실행결과 System.gc();는 실행되지 않고 LC에 의한 메모리 감소를 확인하였습니다.

var before:String = tmp.currencyFormat( System.totalMemory , {  group:"," , decimal:"." ,
                                                                                          currency:"" , before : false } );

try {
          new LocalConnection().connect('myConnection');
          new LocalConnection().connect('myConnection');
} catch (error:ArgumentError) {
          trace("이미 연결되어있다");
}

var after:String = tmp.currencyFormat( System.totalMemory , {  group:"," , decimal:"." ,  
                                                                                        currency:"" , before : false } );

memory.text = "before :" + before + ",  after :" + after;


테스트 코어부분입니다...테스트를 위해 설정하는 코딩이 너무 많아서 생략하고 실제 LC를 통한 가비지 컬렉터를 실행하는 부분입니다.


* 중요 참고 
gc()에 의해 제거 될수 있는 대상은 사용이 끝난 불필요한 말그대로 쓰레기를 회수합니다. 따라서 제거하고자 하는 대상은 화면에 붙어있다면 지워진 상태이며 이름은 null이고 addEventListener를 통해 바라보고 있는 객체가 있으면 안됩니다...지우거나 null까지는 어떻게 해보겠지만 다른클래스에 있는 리스너까지 손보려면 좀 성가시죠....따라서 addEventListener의 useWeakReference를 활용합니다.

* addEventListener 이외에도 Dictionary클래스에도  WeakReference를 제공합니다. 가비지 컬렉션 시스템에서는 WeakReference(약한 참조)를 무시하므로, WeakReference만 있는 객체는 가비지 컬렉션의 대상이 됩니다.
신고
Posted by 정윤수 버터백통

어떠한 객체를 회전운동하고 싶을 때는 원의 자취를 구하는 식을 이용하면 된다.
이는 sin과 cos을 이용하여 기본적인 삼각비를 구한다.

사용자 삽입 이미지
각 면의 길이와 각도를 아는 경우에는 삼각함수를 통해 p1의 좌표를 구할 수 있다.
sin = b/c           ->          b = sin * c : y좌표를 구할 수 있다.
cos = a/c          ->          a = cos * c : x좌표를 구할 수 있다.
그림처럼 높이 b는 y축에 관한 값을 구할 수 있고 밑변 a는 x축의 값을 구할 수 있다.



var _square:Sprite = new Sprite();
var _angle:int = 0;


_square.graphics.lineStyle(2,0x000000);
_square.graphics.beginFill( 0xF79646 )
_square.graphics.drawCircle(0,0,20);
addEventListener( Event.ENTER_FRAME , onEnter )
addChild(_square)

 

function onEnter( e:Event ):void
{
//호도각으로 변환
 var a:Number = _angle * Math.PI/180
//밑변 구하기
 _square.x = Math.cos( a) * 100 + 550/2
//높이 구하기
 _square.y = Math.sin( a ) * 100 + 200
 _angle++
}










신고
Posted by 정윤수 버터백통