비트맵 예제: 회전하는 달 애니메이션

Flash Player 9 이상, Adobe AIR 1.0 이상

회전하는 달 애니메이션 예제는 Bitmap 객체 및 비트맵 이미지 데이터(BitmapData 객체)를 사용하는 방법을 보여 줍니다. 이 예제에서는 평평한 달 표면의 이미지를 원시 이미지 데이터로 사용하여 회전하는 둥근 달의 애니메이션을 만듭니다. 다음과 같은 작업을 수행하는 방법을 볼 수 있습니다.

  • 외부 이미지를 로드하고 해당 이미지의 원시 이미지 데이터에 액세스

  • 소스 이미지의 다른 부분에서 픽셀을 반복적으로 복사하여 애니메이션 만들기

  • 픽셀 값을 설정하여 비트맵 이미지 만들기

이 샘플에 대한 응용 프로그램 파일을 가져오려면 www.adobe.com/go/learn_programmingAS3samples_flash_kr를 참조하십시오. 회전하는 달 애니메이션 응용 프로그램 파일은 Samples/SpinningMoon 폴더에 있습니다. 이 응용 프로그램은 다음과 같은 파일로 구성됩니다.

File

설명

SpinningMoon.mxml

또는

SpinningMoon.fla

Flex(MXML) 또는 Flash(FLA) 형식의 기본 응용 프로그램 파일입니다.

com/example/programmingas3/moon/MoonSphere.as

달의 로드, 표시 및 애니메이션 기능을 수행하는 클래스입니다.

moonMap.png

달 표면의 사진을 포함하는 이미지 파일로 이 파일이 로드되어 회전하는 달 애니메이션을 만드는 데 사용됩니다.

외부 이미지를 비트맵 데이터로 로드

이 샘플에서의 첫 번째 중요한 작업은 달 표면의 사진인 외부 이미지 파일을 로드하는 것입니다. 로드 작업은 MoonSphere 클래스의 두 메서드에 의해 처리되는데 하나는 로드 프로세스가 시작되는 MoonSphere() 생성자이고 다른 하나는 외부 이미지가 완전하게 로드되면 호출되는 imageLoadComplete() 메서드입니다.

외부 이미지를 로드하는 것은 외부 SWF를 로드하는 것과 비슷합니다. 둘 다 flash.display.Loader 클래스의 인스턴스를 사용하여 로드 작업을 수행합니다. 이미지를 로드하기 시작하는 MoonSphere() 메서드의 실제 코드는 다음과 같습니다.

var imageLoader:Loader = new Loader(); 
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoadComplete); 
imageLoader.load(new URLRequest("moonMap.png"));

첫 번째 행에서는 imageLoader라는 Loader 인스턴스를 선언합니다. 세 번째 행에서는 Loader 객체의 load() 메서드를 호출하고 로드할 이미지의 URL을 나타내는 URLRequest 인스턴스를 전달하여 로드 프로세스를 실제로 시작합니다. 두 번째 줄에서는 이미지가 완전히 로드되면 트리거될 이벤트 리스너를 설정합니다. addEventListener() 메서드는 Loader 인스턴스 자체에서 호출되지 않고 Loader 객체의 contentLoaderInfo 속성에서 호출됩니다. Loader 인스턴스 자체에서는 로드되는 내용과 관련된 이벤트를 전달하지 않습니다. 그러나 이 인스턴스의 contentLoaderInfo 속성에는 Loader 객체로 로드되는 내용(여기서는 외부 이미지)과 연결된 LoaderInfo 객체에 대한 참조가 들어 있습니다. LoaderInfo 객체는 외부 내용 로드의 진행과 완료에 관련된 여러 이벤트를 제공합니다. 이러한 이벤트에는 이미지가 완전하게 로드되면 imageLoadComplete() 메서드에 대한 호출을 트리거할 complete 이벤트(Event.COMPLETE) 등이 있습니다.

외부 이미지 로드를 시작하는 것도 프로세스에서 중요한 부분이지만 로드가 완료될 때 해야 할 작업에 대해 알고 있는 것도 똑같이 중요합니다. 위의 코드에서와 같이 이미지가 로드될 때 imageLoadComplete() 함수가 호출됩니다. 이 함수는 로드된 이미지 데이터를 사용하여 여러 작업을 수행하는데, 이 내용은 뒷부분에서 이어서 설명합니다. 이미지 데이터를 사용하려면 해당 데이터에 액세스해야 합니다. Loader 객체를 사용하여 외부 이미지를 로드하는 경우 로드된 이미지는 Bitmap 인스턴스가 되며 이 인스턴스는 Loader 객체의 자식 표시 객체로 연결됩니다. 이 경우에 Loader 인스턴스는 이벤트 리스너 메서드에 매개 변수로 전달되는 이벤트 객체에 포함되므로 이벤트 리스너 메서드에서 이 인스턴스를 사용할 수 있습니다. imageLoadComplete() 메서드의 첫 번째 줄은 다음과 같습니다.

private function imageLoadComplete(event:Event):void 
{ 
    textureMap = event.target.content.bitmapData; 
    ... 
}

이벤트 객체 매개 변수의 이름은 event이고 이는 Event 클래스의 인스턴스입니다. Event 클래스의 모든 인스턴스에는 target 속성이 있으며 이 속성은 이 이벤트를 트리거하는 객체(이 경우 앞에서 설명한 대로 addEventListener() 메서드가 호출된 LoaderInfo 인스턴스)를 참조합니다. 또한 LoaderInfo 객체에는 content 속성이 있는데 로드 프로세스가 완료되면 이 속성에는 로드된 비트맵 이미지가 들어 있는 Bitmap 인스턴스가 포함됩니다 . 이미지를 화면에 바로 표시하려면 이 Bitmap 인스턴스(event.target.content)를 표시 객체 컨테이너에 연결하면 됩니다. 또한 Loader 객체를 표시 객체 컨테이너에 연결할 수도 있습니다. 그러나 이 샘플에서는 로드된 내용이 화면에 표시되지 않고 원시 이미지 데이터의 소스로 사용됩니다. 결과적으로 imageLoadComplete() 메서드의 첫 번째 줄은 로드된 Bitmap 인스턴스의 bitmapData 속성(event.target.content.bitmapData)을 읽어 이를 textureMap이라는 인스턴스 변수에 저장합니다. 이 변수는 회전하는 달의 애니메이션을 만들기 위한 이미지 데이터의 소스로 사용됩니다. 이 내용에 대해서는 다음 단원에서 설명합니다.

픽셀을 복사하여 애니메이션 만들기

애니메이션의 기본 정의는 이미지를 시차를 두고 계속 바꾸어서 움직이거나 변화하는 듯한 효과를 주는 것입니다. 이 샘플의 목표는 세로 축을 중심으로 회전하는 둥근 달의 효과를 만드는 것입니다. 그러나 애니메이션의 목적을 위해 샘플의 구형 왜곡 측면은 무시할 수 있습니다. 달 이미지 데이터의 소스로 로드되고 사용된 실제 이미지를 살펴 보십시오.

보는 바와 같이 이미지는 한 개나 여러 개의 구가 아니라 사각형의 달 표면 사진입니다. 이 사진은 정확하게 달의 적도에서 촬영되었기 때문에 이미지의 맨 위쪽과 아래쪽으로 가까울수록 이미지가 확장되고 왜곡되어 있습니다. 이미지에서 왜곡 현상을 제거하고 구형으로 보이도록 하기 위해 뒷부분에 설명된 대로 위치 변경 맵 필터를 사용할 것입니다. 그러나 소스 이미지가 사각형이기 때문에 구가 회전하는 효과를 만들기 위해 코드는 단지 달 표면 사진을 가로로 움직이기만 하면 됩니다.

이미지에는 실제로 달 표면 사진의 복사본 두 개가 서로 나란히 포함되어 있습니다. 이 이미지는 움직이는 모양을 만들기 위해 이미지 데이터가 반복적으로 복사된 것의 소스 이미지입니다. 이미지의 복사본 두 개가 서로 나란히 있으면 끊기지 않는 연속적인 스크롤 효과를 쉽게 만들 수 있습니다. 애니메이션의 프로세스를 단계별로 진행하여 애니메이션이 어떻게 작동하는지 살펴보겠습니다.

이 프로세스에는 실제로 두 개의 별도 ActionScript 객체가 사용됩니다. 먼저 로드된 소스 이미지가 있는데 이 이미지는 코드에서 textureMap이라는 BitmapData 인스턴스로 표현됩니다. 앞에서 설명한 대로 textureMap은 외부 이미지가 로드되는 즉시 다음 코드를 사용하여 이미지 데이터로 채워집니다.

textureMap = event.target.content.bitmapData;

textureMap의 내용은 사각형 달 이미지입니다. 또한 회전 애니메이션을 만들기 위해 코드에서는 sphere라는 Bitmap 인스턴스를 사용하는데 이는 달 이미지를 화면에 보여 주는 실제 표시 객체입니다. textureMap처럼 sphere 객체는 imageLoadComplete() 메서드에서 다음 코드를 사용하여 만들어지고 초기 이미지 데이터로 채워집니다.

sphere = new Bitmap(); 
sphere.bitmapData = new BitmapData(textureMap.width / 2, textureMap.height); 
sphere.bitmapData.copyPixels(textureMap, 
                         new Rectangle(0, 0, sphere.width, sphere.height), 
                         new Point(0, 0));

코드에 표시된 대로 sphere가 인스턴스화됩니다. sphere에 의해 표시되는 원시 이미지 데이터인 bitmapData 속성은 textureMap과 같은 높이에 절반의 너비로 생성됩니다. 즉, textureMap 이미지에는 두 개의 달 사진이 나란히 있으므로 sphere의 내용은 한 장의 달 사진 크기가 됩니다. 다음으로 bitmapData 속성은 copyPixels() 메서드를 사용하여 이미지 데이터로 채워집니다. copyPixels() 메서드 호출에서 매개 변수는 다음과 같은 사항을 나타냅니다.

  • 첫 번째 매개 변수는 이미지 데이터가 textureMap에서 복사된다는 것을 나타냅니다.

  • 두 번째 매개 변수인 새 Rectangle 인스턴스는 textureMap의 어느 부분에서 이미지 스냅샷을 가져올 지 지정합니다. 이 경우에 스냅샷은 textureMap의 왼쪽 위 모서리(Rectangle()의 처음 두 매개 변수인 0, 0으로 표시됨)에서 시작하는 사각형이고, 사각형 스냅샷의 폭과 높이는 spherewidthheight 속성과 일치합니다.

  • 세 번째 매개 변수인 새 Point 인스턴스는 x와 y 값이 0이며 픽셀 데이터의 대상을 정의합니다. 이 경우에 대상은 sphere.bitmapData의 왼쪽 위 모서리 (0, 0)입니다.

시각적으로 표시하면 코드에서는 다음 이미지에서 외곽선이 표시된 textureMap에서 픽셀을 복사하여 sphere로 붙여 넣습니다. 즉, sphere의 BitmapData 내용은 다음에서 강조 표시된 textureMap의 일부분입니다.

그러나 이것은 sphere의 초기 상태, 즉 sphere로 복사된 첫 번째 이미지 내용일 뿐입니다.

소스 이미지가 로드되고 sphere가 만들어지면 imageLoadComplete() 메서드가 수행하는 마지막 작업은 애니메이션을 설정하는 것입니다. 애니메이션은 rotationTimer라는 Timer 인스턴스에 의해 작동되는데 이는 다음 코드에 의해 만들어지고 시작됩니다.

var rotationTimer:Timer = new Timer(15); 
rotationTimer.addEventListener(TimerEvent.TIMER, rotateMoon); 
rotationTimer.start();

코드에서는 먼저 rotationTimer라는 Timer 인스턴스를 만듭니다. Timer() 생성자로 전달되는 매개 변수는 rotationTimer가 15밀리초마다 자신의 timer 이벤트를 트리거해야 한다는 것을 나타냅니다. 다음으로 timer 이벤트(TimerEvent.TIMER)가 발생하면 rotateMoon() 메서드를 호출하도록 지정하여 addEventListener() 메서드를 호출합니다. 마지막으로 start() 메서드를 호출하여 타이머가 실제로 시작됩니다.

rotationTimer가 정의된 방식으로 인해 약 15밀리초마다 Flash Player가 MoonSphere 클래스의 rotateMoon() 메서드를 호출하며 여기에서 달의 애니메이션이 발생합니다. rotateMoon() 메서드의 소스 코드는 다음과 같습니다.

private function rotateMoon(event:TimerEvent):void 
{ 
    sourceX += 1; 
    if (sourceX > textureMap.width / 2) 
    { 
        sourceX = 0; 
    } 
     
    sphere.Data.copyPixels(textureMap, 
                                    new Rectangle(sourceX, 0, sphere.width, sphere.height), 
                                    new Point(0, 0)); 
     
    event.updateAfterEvent(); 
}

이 코드는 다음과 같은 세 가지 작업을 수행합니다.

  1. 처음에 0으로 설정된 변수 sourceX의 값이 1씩 증가합니다.

    sourceX += 1;

    sourceXsphere로 픽셀을 복사할 textureMap 내부의 위치를 결정하는 데 사용되므로 이 코드는 textureMap에서 사각형을 한 픽셀만큼 오른쪽으로 이동하는 효과가 있습니다. 시각적 표현으로 돌아가면, 애니메이션 주기를 몇 번 거친 후 소스 사각형은 다음과 같이 오른쪽으로 몇 픽셀만큼 이동하게 됩니다.

    주기가 몇 번 더 지나면 사각형은 더 멀리 이동하게 됩니다.

    이렇게 픽셀이 복사되는 위치가 조금씩 일정하게 이동하는 것이 이 애니메이션의 핵심입니다. 소스 위치를 천천히 계속해서 오른쪽으로 이동함으로써 sphere에서 화면에 표시되는 이미지는 계속 미끄러지듯이 왼쪽으로 이동하는 것처럼 보입니다. 소스 이미지(textureMap)에 두 개의 달 표면 사진 복사본이 필요한 이유가 여기에 있습니다. 사각형이 계속 오른쪽으로 이동하므로 대부분 사각형이 한 개의 달 사진이 아니라 두 개의 달 사진에 걸쳐 있게 됩니다.

  2. 소스 사각형이 오른쪽으로 천천히 이동함에 따라 한 가지 문제가 발생합니다. 결국 사각형이 textureMap의 오른쪽 가장자리에 도달하면 sphere로 복사할 달 사진 픽셀이 부족하게 됩니다.

    다음 코드 줄이 이 문제를 해결합니다.

    if (sourceX >= textureMap.width / 2) 
    { 
        sourceX = 0; 
    }

    코드에서는 sourceX(사각형의 왼쪽 가장자리)가 textureMap의 한가운데에 도달했는지 확인합니다. 한가운데에 도달한 경우 sourceX가 0으로 다시 설정되므로 textureMap의 왼쪽 가장자리로 돌아가서 주기가 다시 시작됩니다.

  3. 적절한 sourceX 값이 계산되면 애니메이션 만들기의 마지막 단계는 새 소스 사각형 픽셀을 실제로 sphere에 복사하는 것입니다. 이 작업을 수행하는 코드는 앞에서 설명한 sphere를 처음 채우는 코드와 비슷합니다. 이 경우 유일한 차이점은 new Rectangle() 생성자 호출에서 사각형의 왼쪽 가장자리가 sourceX에 위치하는 것뿐입니다.

    sphere.bitmapData.copyPixels(textureMap, 
                                new Rectangle(sourceX, 0, sphere.width, sphere.height), 
                                new Point(0, 0));

이 코드는 15밀리초마다 반복해서 호출된다는 점에 유의하십시오. 소스 사각형의 위치가 계속 이동하고 픽셀이 sphere로 복사됨에 따라 화면에는 sphere가 나타내는 달 사진 이미지가 미끄러지듯 계속 이동하는 것으로 나타납니다. 즉, 달이 계속해서 회전하는 것처럼 보입니다.

구형 만들기

달은 당연히 구형이며 사각형이 아닙니다. 따라서 샘플에서는 지속적으로 움직이는 사각형 달 표면 사진을 가져와서 구형으로 변환해야 합니다. 이 작업은 별도의 두 단계로 이루어집니다. 마스크를 사용하여 달 표면 사진의 원형 영역을 제외한 모든 내용을 숨기고, 위치 변경 맵 필터를 사용하여 3차원으로 보이도록 달 사진의 모양을 왜곡합니다.

먼저 원형 마스크를 사용하여 필터에 의해 생성된 구를 제외한 MoonSphere 객체의 내용을 모두 숨깁니다. 다음 코드는 마스크를 Shape 인스턴스로 만들어서 MoonSphere 인스턴스의 마스크로 적용합니다.

moonMask = new Shape(); 
moonMask.graphics.beginFill(0); 
moonMask.graphics.drawCircle(0, 0, radius); 
this.addChild(moonMask); 
this.mask = moonMask;

Sprite 클래스에 기반을 둔 MoonSphere는 표시 객체이므로 상속된 mask 속성을 사용하여 마스크를 MoonSphere 인스턴스에 직접 적용할 수 있습니다.

원형 마스크를 사용하여 사진의 일부를 숨기는 것만으로는 실제처럼 보이는 회전하는 구의 효과를 충분히 낼 수 없습니다. 달 표면 사진의 촬영 방식으로 인해 사진의 치수가 비례적이지 않으며 적도 부분과 비교해 이미지의 맨 위쪽이나 아래쪽으로 갈수록 이미지가 더욱 왜곡되고 늘어납니다. 달 사진의 모양을 왜곡하여 3차원으로 보이도록 하기 위해 위치 변경 맵 필터를 사용합니다.

위치 변경 맵 필터는 이미지를 왜곡하는 데 사용하는 필터 유형입니다. 이 경우 달 사진이 좀 더 사실적으로 보이도록 이미지의 가운데 부분은 바꾸지 않고 그대로 둔 채 맨 위쪽과 맨 아래쪽을 가로로 눌러서 달 사진을 "왜곡"합니다. 필터가 사진의 사각형 부분에 작동한다고 가정하고 가운데를 제외하고 맨 위쪽과 아래쪽을 누르면 사각형이 원형으로 변합니다. 이렇게 왜곡된 이미지에 애니메이션 효과를 적용하면 이미지의 가운데 부분이 맨 위쪽과 아래쪽에 가까운 부분보다 실제 픽셀 거리에서 더 멀리 이동하는 것처럼 보이므로 원이 실제로 3차원 객체(구)처럼 보이게 됩니다.

다음 코드는 displaceFilter라고 하는 위치 변경 맵 필터를 만드는 데 사용됩니다.

var displaceFilter:DisplacementMapFilter; 
displaceFilter = new DisplacementMapFilter(fisheyeLens, 
                                new Point(radius, 0),  
                                BitmapDataChannel.RED, 
                                BitmapDataChannel.GREEN, 
                                radius, 0);

첫 번째 매개 변수인 fisheyeLens는 맵 이미지로 알려져 있습니다. 이 경우에는 프로그래밍 방식으로 작성되는 BitmapData 객체입니다. 해당 이미지를 만드는 방법은 픽셀 값을 설정하여 비트맵 이미지 만들기에서 설명합니다. 다른 매개 변수는 필터링된 이미지에서 필터가 적용될 위치, 위치 변경 효과를 조정하는 데 사용될 색상 채널 및 색상 채널이 위치 변경에 미치는 영향의 정도에 대해 설명합니다. 위치 변경 맵 필터가 만들어지면 이 필터는 imageLoadComplete() 메서드 내부에서 sphere에 적용됩니다.

sphere.filters = [displaceFilter];

마스크 및 위치 변경 맵 필터가 적용된 최종 이미지는 다음과 같은 모양입니다.

회전하는 달 애니메이션의 매 주기마다 소스 이미지 데이터의 새로운 스냅샷이 구의 BitmapData 내용을 덮어씁니다. 그러나 필터는 매번 다시 적용되지 않아도 됩니다. 필터가 비트맵 데이터(원시 픽셀 정보)에 적용되지 않고 Bitmap 인스턴스(표시 객체)에 적용되기 때문입니다. Bitmap 인스턴스는 실제 비트맵 데이터가 아니라 비트맵 데이터를 화면에 표시하는 표시 객체라는 것에 유의하십시오. 비유하자면 Bitmap 인스턴스는 화면에 사진 슬라이드를 표시하는 데 사용되는 슬라이드 프로젝터와 비슷하고 BitmapData 객체는 슬라이드 프로젝터를 통해 나타낼 수 있는 실제 사진 슬라이드와 비슷합니다. 필터는 BitmapData 객체에 직접 적용할 수 있는데 이는 이미지를 변경하기 위해 사진 슬라이드에 직접 그림을 그리는 것과 비슷합니다. 필터를 Bitmap 인스턴스 등의 모든 표시 객체에 적용할 수도 있는데 이는 원래 슬라이드를 전혀 변경하지 않고 화면에 보여 주는 출력을 왜곡하기 위해 슬라이드 프로젝터의 렌즈 앞에 필터를 두는 것과 같습니다. 원시 비트맵 데이터는 Bitmap 인스턴스의 bitmapData 속성을 통해 액세스할 수 있으므로 필터를 원시 비트맵 데이터에 직접 적용했을 수도 있습니다. 그러나 이 경우 필터를 비트맵 데이터에 적용하지 않고 Bitmap 표시 객체에 적용하는 것이 더 좋습니다.

ActionScript의 위치 변경 맵 필터 사용에 대한 자세한 내용은 표시 객체 필터링을 참조하십시오.

픽셀 값을 설정하여 비트맵 이미지 만들기

위치 변경 맵 필터의 한 가지 중요한 점은 실제로는 두 개의 이미지가 사용된다는 것입니다. 한 이미지는 소스 이미지로 필터에 의해 실제로 변경되는 이미지입니다. 이 샘플에서 소스 이미지는 sphere라는 Bitmap 인스턴스입니다. 필터에서 사용하는 다른 이미지는 맵 이미지라고 합니다. 맵 이미지는 실제로 화면에는 표시되지 않습니다. 그 대신 각 픽셀의 색상은 위치 변경 함수의 입력으로 사용됩니다. 즉, 맵 이미지에서 특정 x, y 좌표에 있는 픽셀의 색상은 위치 변경(물리적 위치 이동)이 소스 이미지에서 해당 x, y 좌표에 있는 픽셀에 얼마나 적용되는지 결정합니다.

결과적으로 구 효과를 만드는 데 위치 변경 맵 필터를 사용하려면 샘플에 적절한 맵 이미지가 있어야 합니다. 이 이미지에는 다음과 같이 회색 배경과 어두운 색에서 밝은 색으로 가로로 나타나는 단색(빨강)의 그래디언트로 채워진 원이 있습니다.

이 샘플에서는 단 한 개의 맵 이미지와 필터를 사용하므로 맵 이미지는 외부 이미지의 로드가 완료될 때 imageLoadComplete() 메서드에서 한 번만 만들어집니다. fisheyeLens라는 맵 이미지는 MoonSphere 클래스의 createFisheyeMap() 메서드를 호출하여 만들어집니다.

var fisheyeLens:BitmapData = createFisheyeMap(radius);

createFisheyeMap() 메서드에서 맵 이미지는 BitmapData 클래스의 setPixel() 메서드를 사용하여 실제로 한 번에 한 픽셀씩 그려진 것입니다. createFisheyeMap() 메서드의 전체 코드는 다음과 같습니다. 그 다음에는 이 코드의 작동에 대해 단계별로 설명합니다.

private function createFisheyeMap(radius:int):BitmapData 
{ 
    var diameter:int = 2 * radius; 
     
    var result:BitmapData = new BitmapData(diameter, 
                                        diameter, 
                                        false, 
                                        0x808080); 
     
    // Loop through the pixels in the image one by one 
    for (var i:int = 0; i < diameter; i++) 
    { 
        for (var j:int = 0; j < diameter; j++) 
        { 
            // Calculate the x and y distances of this pixel from 
            // the center of the circle (as a percentage of the radius). 
            var pctX:Number = (i - radius) / radius; 
            var pctY:Number = (j - radius) / radius; 
             
            // Calculate the linear distance of this pixel from 
            // the center of the circle (as a percentage of the radius). 
            var pctDistance:Number = Math.sqrt(pctX * pctX + pctY * pctY); 
             
            // If the current pixel is inside the circle, 
            // set its color. 
            if (pctDistance < 1) 
            { 
                // Calculate the appropriate color depending on the 
                // distance of this pixel from the center of the circle. 
                var red:int; 
                var green:int; 
                var blue:int; 
                var rgb:uint; 
                red = 128 * (1 + 0.75 * pctX * pctX * pctX / (1 - pctY * pctY)); 
                green = 0; 
                blue = 0; 
                rgb = (red << 16 | green << 8 | blue); 
                // Set the pixel to the calculated color. 
                result.setPixel(i, j, rgb); 
            } 
        } 
    } 
    return result; 
}

먼저 메서드가 호출되면 만들 원 모양 이미지의 반지름을 나타내는 radius라는 매개 변수를 받습니다. 다음으로 코드는 원이 그려질 BitmapData 객체를 만듭니다. result라는 이름의 이 객체는 결국 메서드의 반환 값으로 다시 전달됩니다. 다음 코드와 같이 result BitmapData 인스턴스는 원지름과 같은 크기의 너비와 높이로 투명하지 않게(세 번째 매개 변수에 false가 설정됨) 만들어지며 0x808080(중간 회색) 색상으로 미리 채워집니다.

var result:BitmapData = new BitmapData(diameter, 
                                    diameter, 
                                    false, 
                                    0x808080);

다음으로 코드는 두 개의 루프를 사용하여 이미지의 각 픽셀을 반복 실행합니다. 바깥쪽 루프가 이미지의 각 열을 왼쪽에서 오른쪽으로 이동하는(i 변수를 사용하여 현재 처리 중인 픽셀의 가로 위치 표시) 반면 안쪽 루프는 현재 열의 각 픽셀을 맨 위쪽에서 아래쪽으로(j 변수를 사용하여 현재 픽셀의 세로 위치 표시) 이동합니다. 이 루프의 코드는 다음과 같습니다(안쪽 루프의 내용 생략).

for (var i:int = 0; i < diameter; i++) 
{ 
    for (var j:int = 0; j < diameter; j++) 
    { 
        ... 
    } 
}

루프가 픽셀을 하나씩 차례로 이동하면 각 픽셀에서 값(맵 이미지에서 해당 픽셀의 색상 값)이 계산됩니다. 이 프로세스는 4단계로 이루어집니다.

  1. 코드가 x축을 따라 원의 중심에서부터 현재 픽셀의 거리를 계산합니다(i - radius). 이 값을 반지름으로 나누어 절대적인 거리가 아닌 반지름의 백분율((i - radius) / radius)로 만듭니다. 다음 코드에서와 같이 이 백분율 값은 pctX라는 변수에 저장되고 y축에 해당하는 값은 계산되어 pctY 변수에 저장됩니다.

    var pctX:Number = (i - radius) / radius; 
    var pctY:Number = (j - radius) / radius;
  2. 피타고라스의 원리인 표준 삼각법 공식을 사용하여 원의 중심에서 현재 지점 간의 직선 거리가 pctXpctY에서 계산됩니다. 이 값은 다음과 같이 pctDistance 라는 변수에 저장됩니다.

    var pctDistance:Number = Math.sqrt(pctX * pctX + pctY * pctY);
  3. 다음으로 거리 백분율이 1보다 작은지 확인합니다. 1은 반지름의 100%라는 뜻이므로 검토 중인 픽셀이 원의 반지름 내에 있는지 확인하는 것과 같습니다. 픽셀이 원 내부에 있는 경우 계산된 색상 값(여기서는 생략되었지만 4단계에서 설명함)이 지정됩니다. 픽셀이 원 밖에 있는 경우에는 픽셀은 더 이상 변경되지 않으며 기본값인 중간 회색으로 유지됩니다.

    if (pctDistance < 1) 
    { 
        ... 
    }
  4. 원의 내부에 있는 픽셀의 경우 픽셀에 대한 색상 값이 계산됩니다. 최종 색상은 원 왼쪽 가장자리의 검정(빨강 0%)에서 원 오른쪽 가장자리의 밝은 빨강(100%) 사이의 빨강 음영이 됩니다. 색상 값은 처음에는 다음과 같이 빨강, 녹색 및 파랑의 세 부분으로 계산됩니다.

    red = 128 * (1 + 0.75 * pctX * pctX * pctX / (1 - pctY * pctY)); 
    green = 0; 
    blue = 0;

    색상의 빨강 부분(red 변수)만 실제로 값을 가지고 있습니다. 명확성을 위해 여기에서 녹색 및 파랑 값(greenblue 변수)을 표시했지만 해당 값은 생략할 수 있습니다. 이 메서드의 목적은 빨강 음영을 포함하는 원을 만드는 것이므로 녹색이나 파랑 변수는 필요하지 않습니다.

    세 가지 개별 색상 값이 각각 결정되면 이들은 다음 코드와 같이 표준 비트 이동 알고리즘을 사용하여 단일 정수 색상 값으로 통합됩니다.

    rgb = (red << 16 | green << 8 | blue);

    마지막으로 색상 값이 계산되면 이 값은 다음과 같이 result BitmapData 객체의 setPixel() 메서드를 사용하여 실제로 현재 픽셀에 지정됩니다.

    result.setPixel(i, j, rgb);