스크린샷과 동적 스프라이트

# 학습 과정 소개

월드를 제작할 때 스프라이트가 필요하면 메이플스토리 월드에서 제공하는 것을 선택하거나, 크리에이터가 직접 Import 한 것을 사용할 수 있습니다. 이러한 방법 외에도 월드 플레이 도중 생성된 이미지를 월드에 업로드하고 다른 유저와 공유할 수도 있습니다. 이처럼 메이플스토리 월드에서 플레이 도중 생성되는 이미지를 동적 스프라이트라고 합니다. 동적 스프라이트는 RawImage라는 데이터 타입에 담아서 월드에 업로드하고 RUID를 발급받아 사용할 수 있습니다.   
이번 과정에서는 [ScreenshotService](/apiReference/Services/ScreenshotService)의 `CaptureFullScreenAsPixelDataAndWait()` 함수를 사용해 캡처 결과를 RawImage 형태로 반환하는 예제를 살펴보겠습니다. 이 예제를 통해 동적 스프라이트의 활용 방법을 이해할 수 있습니다.

# 월드에 스크린샷 보여주기

특정 키를 눌러 스크린샷을 찍은 뒤 월드의 특정 위치에 보이도록 하는 예제를 살펴봅시다.

  1. Hierarchy - Create Entity - Create Empty를 클릭해 EmptyEntity를 생성합니다. EmptyEntity의 이름을 Frame으로 지정합니다. [png](1668661121252c9d0293976864189952c8b9700eb8368)

  2. Frame 엔티티의 프로퍼티 에디터에서 TransformComponent, SpriteRendererComponent를 추가합니다. [png](1679371574207593d86d4363d41f990a861fb084b13b7)

  3. Frame 엔티티의 프로퍼티 에디터에서 SpriteRendererComponent - SpriteRUID에 원하는 스프라이트를 설정합니다. 예) SpriteRUID : 93c2673261874c76b55459a4add2c382 [png](16685976953935f7b707c48a74bd8bf90747904f83a34)

  4. Hierarchy - Frame의 콘텍스트 메뉴에서 Create Entity as Child - Create Empty를 클릭하여 하위 엔티티를 생성합니다. [png](16862000936226739727d0fd544f681d63208b2fcd4e7) EmptyEntity의 이름을 Canvas로 지정합니다. [png](16686612052390bc3806fb1234ebfbd94ca85473612bc)

  5. Canvas 엔티티의 프로퍼티 에디터에서 TransformComponent, SpriteRendererComponent를 추가합니다.

  6. Scene에서 Canvas 엔티티를 드래그하여 Frame의 가운데 위치로 이동합니다. [png](1668598281353fa2830c39674415282afcba0cf2f041f)

  7. 새 스크립트 컴포넌트를 생성하고 이름을 SpriteUploadTest로 설정합니다.

  8. Hierarchy - Common을 선택한 뒤, 프로퍼티 에디터에서 SpriteUploadTest 컴포넌트를 추가합니다.

  9. SpriteUploadTest를 열고 스크립트 에디터에서 아래와 같이 Property를 추가합니다.
         
         @Component
         script Map01DisplayReferences extends Component
         property Entity FrameEntity = "/maps/map01/Frame"
         property Entity CanvasEntity = "/maps/map01/Frame/Canvas"
         end
         



    
    
    10. `OnBeginPlay()` 함수를 추가하고 아래와 같이 작성합니다.
        `SetSpriteUploadValidationCallback()` 함수는 유저가 업로드 요청을 보냈을 때 허용 여부를 설정합니다. 허용하려면 **true**를, 그렇지 않으면 **false**를 반환하도록 코드를 작성합니다. 이 예제에서는 업로드를 허용해야 하므로 **true**를 반환하도록 합니다.
        ```lua
    @Component
    script SpriteUploadEnabler extends Component
        method void OnBeginPlay()
        if self:IsServer() then
            -- 유저가 업로드 요청을 보냈을 때 이를 허용하기 위해 true로 설정합니다.
            _ResourceService:SetSpriteUploadValidationCallback(function(userId)
                return true
            end)
    
            return
        end
        end
    end
    

  11. `CaptureAndUpload()` 함수를 추가하고 아래와 같이 작성합니다. 
         
         @Component
         script ScreenshotEmbedder extends Component
         @ExecSpace("ClientOnly")
         method void CaptureAndUpload()
         local frameRUID = self.FrameEntity.SpriteRendererComponent.SpriteRUID
         
         local sprite = _ResourceService:LoadSpriteAndWait(frameRUID)
         -- frame 엔티티 스프라이트의 가로, 세로 픽셀을 확인합니다.
         local frameWidth = sprite.Width
         local frameHeight = sprite.Height
         
         -- 촬영한 스크린샷 이미지를 받습니다.
         local error, screenshot = _ScreenshotService:CaptureFullScreenAsPixelDataAndWait()
         
         -- 스크린샷의 가로, 세로 픽셀을 확인합니다.
         local screenshotWidth = screenshot.Width
         local screenshotHeight = screenshot.Height
         
         -- 스크린샷의 크기를 변경할 비율을 계산합니다.
         -- Frame 안에 스크린샷이 들어가도록 비율을 살짝 작게 조절합니다.
         local horizontalRatio = frameWidth / screenshotWidth * 0.96
         local verticalRatio = frameHeight / screenshotHeight * 0.67
         
         -- 스크린샷 이미지를 스프라이트 형태로 업로드 합니다.
         _ResourceService:RequestSpriteUploadAsync(screenshot, function(error, ruid)
             self.CanvasEntity.SpriteRendererComponent.SpriteRUID = ruid
             -- 위에서 계산한 비율을 넣어 Canvas의 Scale을 조절합니다.	
             self.CanvasEntity.TransformComponent.Scale = Vector3(horizontalRatio, verticalRatio, 1)
         end) 
         end
         end
         



    
    
    12. **Event Handler**에 아래와 같이 **KeyDownEvent**를 추가합니다.
        ```lua
    @Component
    script ScreenshotHotkeyHandler extends Component
        @EventSender("Self")
        handler HandleKeyDownEvent(KeyDownEvent event)
        -- Parameters
        local key = event.key
        --------------------------------------------------------
        -- 키보드에서 1을 누르면 스크린샷을 촬영합니다.
        if key == KeyboardKey.Alpha1 then 
         self:CaptureAndUpload()
        end
        end
    end
    

  13.  [시작] 버튼을 누른 뒤 테스트해 봅시다. 1을 눌러 스크린샷을 찍으면 Frame 안에 스크린샷이 나오는 것을 확인합니다. [gif](16686484619418af80fe87df5450b86bea39286b9186c)



> 더 알아보기
> 
>   * 업로드하는 리소스는 3MB를 초과할 수 없습니다.
>   * 업로드는 한 번에 하나만 요청할 수 있습니다. 이전 요청이 완료되기 전에 다시 요청하면 업로드 실패합니다.
>   * 메이커 플레이 중 생성한 스프라이트는 임시 리소스로서, 플레이를 종료하면 사라집니다.
>   * 업로드는 월드 기준 1분 당 5회로 제한됩니다. 월드에 너무 많은 요청이 들어오면 업로드에 실패할 수 있습니다. 여러 클라이언트에서 동시에 요청을 보내지 않도록 주의해야 합니다.
>   * 메이커에서 테스트할 때 가상의 플레이어를 추가하거나 인스턴스 룸을 갔다 오면 경우에 따라 업로드한 스크린샷이 보이지 않을 수 있습니다. 실제 출시된 게임에서는 정상적으로 보입니다.
>