msw-ai-tf/maplestory-worlds-creator-docs huggingface dataset:
캐릭터를 특정 위치로 즉시 이동시키는 법

이 게시글은 기존 정보에 기반해 크리에이터에게 유용하도록 AI가 재구성한 내용입니다.

# 캐릭터를 특정 위치로 즉시 이동시키는 법

> 캐릭터를 특정 위치로 즉시 이동시키는 것은 게임 개발에서 중요한 기능입니다. 이 기능은 게임 플레이의 흐름을 원활하게 유지하고, 플레이어에게 보다 다양한 경험을 제공하는 데 필수적입니다. 이 아티클에서는 캐릭터를 다양한 방식으로 이동시키는 방법에 대해 살펴보겠습니다.

## 특정 위치로 즉시 이동시키기

특정 위치로 즉시 이동시키는 기능은 게임 내에서 캐릭터를 미리 지정된 위치로 순간 이동시키는 방법입니다. 이 방법은 주로 `TeleportService`를 사용하여 구현할 수 있습니다.

### 구현 방법

  * `TeleportToMapPosition` 메서드를 사용하여 엔티티를 특정 `Vector3` 위치로 이동시킵니다.
  * 필요에 따라 `ReserveTeleportToMapPosition`을 사용하여 이동을 예약한 후, `TeleportReservedEntities`로 실행할 수 있습니다.



## 현재 위치를 기준으로 상대적인 위치로 이동시키기

현재 위치를 기준으로 상대적인 위치로 이동시키는 방법은 캐릭터의 현재 위치에서 일정 거리만큼 이동시키는 것을 의미합니다.

### 구현 방법

  * `TransformComponent.Position` 값을 가져와 이동할 상대적 좌표를 계산합니다.
  * `TeleportToMapPosition` 메서드를 사용하여 계산된 위치로 이동합니다.
  * `Translate` 메서드를 활용하여 상대적 이동을 구현할 수 있습니다.



## 바라보는 방향으로 일정 거리만큼 이동시키기

이 방법은 캐릭터가 바라보는 방향으로 일정 거리만큼 이동시키는 것을 의미합니다.

### 구현 방법

  * `MovementComponent:IsFaceLeft()`를 통해 현재 방향을 확인합니다.
  * 이동할 거리 `N`을 설정하고, 방향에 따라 이동 거리를 조정합니다.
  * `TeleportToMapPosition` 메서드를 사용하여 조정된 위치로 이동합니다.
  * 필요에 따라 `Rotate` 메서드를 사용하여 방향 전환 후 이동할 수 있습니다.



## 코드 예제

아래 예제는 키 입력에 따라 캐릭터를 다양한 방식으로 이동시키는 방법을 보여줍니다.
    
    
    EventHandler:
    HandleKeyDownEvent (KeyDownEvent event)
    {
        local key = event.key
        
        -- 특정 위치(0,0)로 이동 시키는 방법
        if key == KeyboardKey.K then
            local pos = self.Entity.TransformComponent.Position
            _TeleportService:TeleportToMapPosition(self.Entity, Vector3(0,0,pos.z), self.Entity.CurrentMap.Name)
        end
        
        -- 현재 위치를 기준으로 상대적인 위치(cur.x + N, 0) 위치로 이동 시키는 방법
        if key == KeyboardKey.J then
            local pos = self.Entity.TransformComponent.Position
            _TeleportService:TeleportToMapPosition(self.Entity, Vector3(pos.x - 1, pos.y,pos.z), self.Entity.CurrentMap.Name)
        end
        
        -- 바라보는 방향으로 2만큼 이동하는 방법
        if key == KeyboardKey.H then
            local pos = self.Entity.TransformComponent.Position
            local isFacingLeft = self.Entity.MovementComponent:IsFaceLeft()
            local movingDistance = 2
            if isFacingLeft == false then
                movingDistance = movingDistance * -1
            end
            
            _TeleportService:TeleportToMapPosition(self.Entity, Vector3(pos.x - movingDistance, pos.y,pos.z), self.Entity.CurrentMap.Name)
        end
    }
    

## 잠재적 문제 및 해결책

이동 기능을 구현할 때 발생할 수 있는 문제로는 캐릭터가 의도치 않은 위치로 이동하거나, 이동 중 장애물에 막히는 경우가 있습니다. 이를 해결하기 위해서는 이동 전 위치를 검증하거나, 장애물 감지 로직을 추가하는 것이 좋습니다.

## 결론 및 추가 자료

캐릭터 이동은 게임 플레이의 핵심 요소 중 하나로, 다양한 방법을 통해 구현할 수 있습니다. 이를 통해 플레이어는 보다 다양한 게임 경험을 할 수 있습니다. 추가적으로 자세한 정보는 아래 링크를 참고하세요.

  * 
  *
DownJump 시 예상 착지 지점 찾기

이 게시글은 기존 정보에 기반해 크리에이터에게 유용하도록 AI가 재구성한 내용입니다.

# DownJump 시 예상 착지 지점 찾기

> 이 아티클은 DownJump 시도 시 캐릭터가 착지할 예상 지점을 찾고, 현재 위치와의 거리를 계산하는 방법에 대해 설명합니다. 이를 통해 플레이어는 보다 안전하고 정확한 점프를 수행할 수 있습니다.

## 주제의 중요성과 관련성

게임 개발에서 캐릭터의 이동과 착지 지점 예측은 중요한 요소입니다. 특히, DownJump와 같은 동작은 정확한 착지 지점을 예측하여 안전한 게임 플레이를 보장해야 합니다. 이 아티클은 그러한 예측을 돕기 위한 방법을 제공합니다.

## 핵심 개념 설명

DownJump 시 예상 착지 지점을 찾는 것은 `TransformComponent`, `GetNearestFootholdByPoint`, `Raycast`와 같은 스크립트 API를 활용하여 구현할 수 있습니다. TransformComponent는 캐릭터의 현재 위치를 제공하며, GetNearestFootholdByPoint는 특정 지점에서 가장 가까운 발판을 찾습니다. Raycast는 특정 방향으로 광선을 쏴서 충돌하는 첫 번째 발판을 찾아내는 방법입니다.

## 사용 사례 및 필요성

게임 개발에서 캐릭터가 점프할 때 착지 지점을 미리 파악하는 것은 플레이어의 안전한 이동을 보장합니다. 예를 들어, 플랫폼 게임에서 캐릭터가 착지할 수 있는 발판을 미리 예측하여 추락을 방지하는 데 사용될 수 있습니다.

## 구체적인 사용 방법

  1. 현재 캐릭터 위치 가져오기

     * `TransformComponent`를 통해 캐릭터의 현재 위치를 `Vector2` 형식으로 가져옵니다.
  2. 가장 가까운 발판 찾기

     * `GetNearestFootholdByPoint`를 사용하여 현재 위치에서 가장 가까운 발판을 찾습니다.
  3. Raycast를 사용하여 착지 지점 예측

     * 아래 방향으로 `Raycast`를 수행하여 착지 지점을 예측합니다.
  4. 거리 계산

     * 현재 위치와 착지 지점 간의 거리를 계산합니다.


    
    
    -- 캐릭터의 현재 위치를 가져옵니다.
    local currentPosition = self.Entity.TransformComponent.Position:ToVector2()
    currentPosition.y = currentPosition.y - 0.01
    
    -- FootholdComponent를 가져옵니다.
    local footholdComponent = self.Entity.CurrentMap.FootholdComponent
    if footholdComponent == nil then
        log("FootholdComponent가 없습니다.")
        return
    end
    
    -- 가장 가까운 발판을 찾습니다.
    local nearestFoothold = footholdComponent:GetNearestFootholdByPoint(currentPosition, 10)
    if nearestFoothold == nil then
        log("가까운 발판이 없습니다.")
        return
    end
    
    -- Raycast를 사용하여 착지 지점을 예측합니다.
    local direction = Vector2(0, -1) -- 아래 방향
    local distance = 100 -- Raycast 거리
    local landingFoothold = footholdComponent:Raycast(currentPosition, direction, distance)
    if landingFoothold == nil then
        log("착지할 발판이 없습니다.")
        return
    end
    
    -- 착지 지점의 위치를 가져옵니다.
    local landingPosition = Vector2(currentPosition.x, landingFoothold:GetCenter().y)
    
    -- 현재 위치와 착지 지점 간의 거리를 계산합니다.
    local distanceToLanding = currentPosition:Distance(landingPosition)
    log("현재 위치와 착지 지점 간의 거리: " .. distanceToLanding)
    

## 잠재적 문제 및 해결책

  * 발판이 없는 경우: 발판이 없는 경우에는 로그를 통해 사용자에게 알리고 적절한 예외 처리를 수행합니다.
  * Raycast 거리 제한: Raycast의 거리가 충분하지 않으면 착지 지점을 예측할 수 없습니다. 적절한 거리 값을 설정해야 합니다.



## 결론 및 추가 자료

이 아티클에서는 DownJump 시 예상 착지 지점을 찾는 방법에 대해 설명하였습니다. 이 방법은 게임의 안전성을 높이고 플레이어에게 더 나은 경험을 제공합니다. 추가 자료는 를 참조하시기 바랍니다.
제작 가이드 활용법

메이플스토리 월드에서는 다양한 형식의 가이드를 제공하고 있습니다. 메이플스토리 월드가 생소한 크리에이터라면 기본 제작 가이드 - 시작하기 - [메이커 사용](/docs?postId=724)을 먼저 살펴보며 기본 기능 익히기를 권장합니다.

# 난이도

가이드를 살펴보기 전, 학습권장대상 배지를 확인하고 나에게 적절한 난이도인지 확인할 수 있습니다.

  * Lv.1: 메이커의 기본 기능과 컴포넌트의 기본 기능을 사용하고 싶은 크리에이터
  * Lv.2: MSW의 기본 문법을 알고, 간단한 동작을 직접 만들 수 있는 크리에이터
  * Lv.3: 서버와 클라이언트의 관계를 알고, 활용할 수 있는 크리에이터
  * Lv.4: 월드와 인스턴트를 알고, 월드 최적화와 보안을 고려하는 크리에이터



# 기본 제작 가이드

기본 제작 가이드에서는 메이플스토리 월드 메이커의 기본 기능부터 API의 개념과 개별 사용 방법을 상세히 소개합니다.

#### 메이커 사용

  * [Workspace](/docs?postId=121)
  * [Hierarchy](/docs?postId=453)
  * [컴포넌트 추가와 삭제](/docs?postId=58)
  * [게임 시작 위치 설정](/docs?postId=115)
  * [캐릭터 초기 속성 편집](/docs?postId=48)



#### 개념 이해

  * [모델](/docs?postId=55)
  * [맵 레이어](/docs?postId=53)
  * [Entity, Component, Property](/docs?postId=54)
  * [월드 인스턴스](/docs?postId=984)
  * [DataStorage 활용하기](/docs?postId=692)



#### 스크립트

  * [스크립트 에디터 오리엔테이션](/docs?postId=56)
  * [프로퍼티](/docs?postId=205)
  * [프로퍼티 동기화](/docs?postId=208)
  * [실행제어](/docs?postId=210)
  * [함수](/docs?postId=172)
  * [MSW 기본 이벤트 함수](/docs?postId=163)
  * [메이플스토리 월드 루아 기초](/docs/?postId=822)



#### 지형과 이동

  * [메이플 이동 개념 이해하기](/docs?postId=750)
  * [사다리와 로프 활용하기](/docs?postId=809)
  * [발판 만들기](/docs?postId=71)
  * [RectTileMap의 활용](/docs?postId=589)
  * [SideViewRectTile 모드로 맵 만들기](/docs?postId=758)



#### 리소스 제작

  * [아바타 아이템 제작 기본 개념](/docs?postId=588)
  * [아바타 아이템 등록하기](/docs?postId=590)
  * [애니메이션 만들기](/docs?postId=595)



#### 보안 및 최적화

  * [프로파일러로 월드 성능 분석하기](/docs?postId=1078)
  * [TargetUserSync와 프로퍼티 동기화 최적화](/docs?postId=1119)
  * [효과적으로 DataStorage 사용하기](/docs?postId=1073)



# 응용 제작 가이드

응용 제작 가이드는 시스템 구현 예제와 게임 따라 만들기로 구분됩니다. 시스템 구현 가이드는 메이플스토리 월드에서 제공하는 여러 컴포넌트, 서비스를 활용 예제로 만들어 소개합니다. 가이드를 따라 하며 기능을 익히거나, 가이드의 내용을 참고해 크리에이터의 월드에 반영할 수 있습니다.

#### 게임 시스템 따라 만들기

  * [UI에서 아바타 애니메이션 재생하기](/docs?postId=1147)
  * [원거리 발사체로 몬스터 처치하기](/docs?postId=934)
  * [상점과 인벤토리](/docs?postId=1104)



#### 게임 따라 만들기

  * [플래피 피쉬 리메이크](/docs?postId=1100)
  * [슈피겔만 게임 리메이크](/docs?postId=1099)
SideViewRectTile모드로 맵 만들기

# 학습 과정 소개

RectTileMapComponent와 KinematicbodyComponent는 탑다운뷰 게임 제작에는 적합하지만 횡스크롤 게임 제작에는 적합하지 않습니다. SideViewRectTile 모드는 RectTileMap을 활용해 손쉽게 횡스크롤 게임을 제작할 수 있도록 횡스크롤 방식의 이동, 점프, 타일과의 충돌 등을 지원합니다. 이번 시간에는 SideViewRectTile 모드에 대해 알아보고 맵을 제작해봅시다.

> 더 알아보기 SideViewRectTile 모드는 RectTile 모드를 기반으로 합니다. 본 과정을 살펴보기 전에 먼저 [RectTileMap의 활용](/docs?postId=589)을 참고해보세요.

# SideViewRectTile 모드 변경

SideViewRectTile을 활용하려면 맵 타일 모드를 변경해야 합니다. 맵 타일 모드를 변경하는 첫 번째 방법은  Hierarchy에서 현재 편집 중인 맵 엔티티를 선택하고, 우클릭 메뉴에서 Switch To SideViewRectTileMap을 선택하는 것입니다. [png](1686212940229528039cf5e884de28be22ce0db30fcd2)

두 번째 방법은 상단 메뉴의 타일 에디터 버튼을 길게 눌러 타일 모드 선택 메뉴를 연 뒤, SideViewRectTile을 선택하는 것입니다. [png](1658472803827bec010dc49a346efbc96c900cbe8ca0a)

SideViewRectTile 모드를 선택하면 아래와 같이  Scene이 변경됩니다. [png](165847431530038c061258d764f4183969cb9c60201df)

# SideViewRectTile 맵 만들기

SideViewRectTile 모드로 맵을 만드는 것은 전반적으로 RectTileMap 제작 과정과 동일합니다. 이번 시간에는 아래와 같이 간단한 SideViewRectTile 맵을 만들어봅시다. [png](1658474735348794bdba4e80f40338aefc482a15595e0)

먼저 아래 4개의 이미지를 저장한 뒤, 예제를 살펴봅시다. [png](16584737735555de4cfef1e6846b881fb08dd974e18f1) [png](1658473786750f09028c3d7164a2694e9f0a099456a1c) [png](1658473808386f01655943b5f452a842aaf7f7ba3c4a6) [png](1658473825666f3080a29dece4ce685465b7018636cbe)

  1. 타일 모드를 SideViewRectTile로 변경합니다.   

  2. 위에서 저장했던 4개의 이미지를  Resource Storage - 내 리소스 - etc에 추가합니다. [png](1658475210960ed4d68009339425b894f180174bb7bd7)   

  3.  Preset List - Background에서 back-4를 검색한 뒤 선택하여 맵의 배경을 변경합니다. [png](1658475486669606fbfbe07024b8dad2697df10431fec)   

  4. 타일 셋 팔레트 좌측 상단의 "+" 버튼을 누르고 Create Empty TileSet을 선택합니다. 새 타일 셋의 이름을 TileSet으로 입력합니다. [png](1658475711945ea21f592fcdb4a90a3e75c8a22e34d85)   

  5. 타일 셋 팔레트 하단의  타일 추가 버튼을 누른 뒤 Add ResourceStorage Image를 선택합니다. [png](1658476061494e0157e24c4f94541828910e14356cc6f)   

  6. Resource Picker에서 미리 추가해두었던 이미지를 선택합니다. [png](1681090546377990fe7a74f8944eba5c211259fed8919)   

  7. 타일 셋에서 타일을 선택해 원하는 대로 맵을 꾸며줍니다. 맵에 어울리는 오브젝트도 배치합니다. [png](16584776165678f4bf1e92d9845bcb7a0745d3802952d)   

  8. 타일 위에 캐릭터가 설 수 있도록 타일을 이동 불가로 설정합니다. [gif](1658477949218d34942db72a14aaaac72a17787948e87)   

  9.  시작 버튼을 눌러 횡스크롤 이동이 잘 되는지 확인해봅시다. [gif](1658478611789db5a20547f4f40a5bec1c0b961ad97a7)



> 더 알아보기 SideViewRectTile에서의 이동은 [SideViewRectTileMap에서 캐릭터 이동 제어](/docs?postId=759)를 참고해주세요.
말풍선 만들기

# 학습 과정 소개

엔티티와 플레이어 아바타에 말풍선을 간단하게 붙일 수 있습니다. ChatBalloonComponent 사용 방법과 활용 예시를 소개합니다.

# 말풍선 붙이기

  1. 말풍선을 붙일 엔티티를 선택하고 ChatBalloonComponent를 추가합니다.
  2. 프로퍼티 값을 변경해 원하는 말풍선을 만듭니다. [png](1635730184988c95467b0dd9f4613abf9ba85d68914d9) 주요 프로퍼티 값은 다음과 같습니다.



[{"프로퍼티 명":"ChatBalloonRUID","설명":"다양한 말풍선 스프라이트를 이용할 수 있습니다."},{"프로퍼티 명":"BalloonScale","설명":"말풍선 크기를 설정합니다. 입력한 값이 클수록 크기가 양옆으로 늘어납니다."},{"프로퍼티 명":"ArrowChatEnabled","설명":"말풍선 꼬리 이미지 붙이거나 뗄 수 있습니다. 꼬리가 붙은 상태가 기본 활성 상태입니다."},{"프로퍼티 명":"AutoShowEnabled","설명":"말풍선을 자동으로 표시할지 정합니다.Player의 ChatBalloonComponent의 경우 true일 때 동작하지 않습니다."},{"프로퍼티 명":"Font Offset","설명":"말풍선 내의 글자의 위치를 상하좌우로 조정합니다."},{"프로퍼티 명":"Offset","설명":"말풍선 위치를 정할 수 있습니다. 원점 값은 0, 기준 축은 Y 축입니다. 값이 0이면 원점에 이름표가 위치합니다. 음수를 입력하면 아래로, 양수면 위에 위치합니다."},{"프로퍼티 명":"HideDuration","설명":"말풍선이 화면에 보이지 않는 시간을 초 단위로 입력합니다.값이 0이면 화면에 항상 보입니다."},{"프로퍼티 명":"ShowDuration","설명":"말풍선이 화면에 보이는 시간을 초 단위로 입력합니다.1 이상의 수를 입력해야 말풍선이 보입니다."},{"프로퍼티 명":"Message","설명":"말풍선으로 보일 문구를 작성합니다.다른 설정이 활성 상태여도 문구가 없으면 말풍선이 보이지 않습니다."},{"프로퍼티 명":"FontSize","설명":"말풍선 문구 크기를 변경합니다.기본값은 1이며, 숫자가 커질수록 글자 크기가 커집니다."},{"프로퍼티 명":"FontColor","설명":"말풍선 문구 색상을 변경합니다.색상 변경은 스프라이트 색상 조정을 참고하세요."},{"프로퍼티 명":"IsRichText","설명":"말풍선에서 리치 텍스트를 사용할지를 설정합니다."},{"프로퍼티 명":"ChatModeEnabled","설명":"활성 시, 채팅창에 입력한 메시지가 말풍선으로 동시에 나타납니다. Player의 ChatBalloonComponent에서 사용할 때만 동작하며, 활성 상태가 기본입니다."},{"프로퍼티 명":"AutoShowEnabled","설명":"말풍선이 자동으로 나타나게 할지 여부를 설정합니다. 값이 true일 경우 ShowDuration 동안 말풍선이 보이고 HideDuration 동안 말풍선이 사라지는 동작을 반복합니다. 플레이어의 ChatModeEnabled 값이 true일 경우 자동 말풍선 기능이 동작하지 않습니다."}]

#### 활용 예시

물개 엔티티 오브젝트에 말풍선을 만드는 예제입니다. [png](1655963930366197ddcce272b435d9633958b4b3fdbff)

다음과 같이 값을 입력해 봅시다.

[{"Property":"ArrowChatEnabled","value":"true"},{"Property":"AutoShowEnabled","value":"true"},{"Property":"BalloonScale","value":"3"},{"Property":"ChatBalloonRUID","value":"0548325d3d4d40649acad12fde2359d4"},{"Property":"ChatModeEnabled","value":"false"},{"Property":"FontColor","value":"#000000"},{"Property":"FontSize","value":"1.5"},{"Property":"HideDuration","value":"5"},{"Property":"Message","value":"Is it a seal? Or a ture seal?"},{"Property":"Offset","value":"1"},{"Property":"ShowDuration","value":"5"}]
Sprite GUI Renderer Component로 스프라이트 크기 조정하는 법

이 게시글은 기존 정보에 기반해 크리에이터에게 유용하도록 AI가 재구성한 내용입니다.

# Sprite GUI Renderer Component로 스프라이트 크기 조정하는 법

> SpriteGUIRendererComponent를 활용해 스프라이트의 크기를 부모 엔티티의 크기에 맞게 조정하는 방법을 알아봅니다.

## SpriteGUIRendererComponent의 중요성

SpriteGUIRendererComponent는 UI에서 이미지 리소스를 표시하는 데 사용되는 중요한 `컴포넌트`입니다. 이를 통해 UI에 표시할 이미지의 형태와 내용을 설정할 수 있습니다. 특히, 스프라이트를 부모 `엔티티`의 크기에 맞게 조정하는 것은 UI 디자인에서 매우 중요합니다. 이러한 조정은 화면 해상도나 레이아웃 변화에 따라 스프라이트가 일관되게 표시되도록 돕습니다.

## 스프라이트 크기 조정의 기본 개념

스프라이트의 크기를 부모 엔티티의 크기에 맞추기 위해서는 몇 가지 핵심 개념을 이해해야 합니다:

  * UITransformComponent: 스프라이트의 위치와 크기를 조정하는 데 사용됩니다.
  * PreserveSprite 옵션: 스프라이트의 비율을 유지하면서 크기를 조정하는 옵션입니다.
  * AspectOnly 설정: 스프라이트의 원본 비율을 유지하면서 부모 엔티티의 크기에 맞게 조정합니다.



## 다양한 사용 사례

스프라이트의 크기를 부모 엔티티에 맞추는 것은 다양한 UI 디자인 상황에서 사용됩니다. 예를 들어:

  * 게임의 HUD에서 스프라이트 아이콘을 균일하게 배치해야 할 때
  * 다양한 화면 크기에서 일관된 사용자 경험을 제공하고자 할 때
  * UI 요소의 크기를 동적으로 조정해야 하는 경우



이러한 상황에서 적절한 스프라이트 크기 조정은 사용자 경험을 향상시키는 데 필수적입니다.

## 단계별 스프라이트 크기 조정 방법

스프라이트의 크기를 부모 엔티티에 맞추기 위한 구체적인 방법은 다음과 같습니다:

  1. 부모 엔티티의 크기 설정: 부모 엔티티의 Width와 Height를 설정합니다. 예를 들어, 300x300으로 설정할 수 있습니다.

  2. SpriteGUIRendererComponent 추가: 부모 엔티티 아래에 SpriteGUIRendererComponent를 추가하여, 스프라이트가 부모의 크기에 맞게 자동으로 조정되도록 합니다.

  3. UITransformComponent 설정: 자식 엔티티의 UITransformComponent를 설정하여 부모 엔티티의 크기에 맞게 스프라이트를 조정합니다.

  4. PreserveSprite 옵션 사용: 자식 엔티티의 SpriteGUIRendererComponent에서 PreserveSprite 옵션을 AspectOnly로 설정하여 스프라이트의 실제 이미지 비율을 유지합니다.

  5. 스프라이트 피봇 및 중심점 정렬: 자식 엔티티의 중심점과 스프라이트 피봇을 일치시켜, 스프라이트가 부모의 Rect 사이즈에서 벗어나지 않도록 합니다.




## 잠재적 문제 및 해결책

스프라이트 크기 조정 시 발생할 수 있는 문제는 다음과 같습니다:

  * 비율 왜곡: PreserveSprite 옵션을 잘못 설정하면 스프라이트 이미지가 왜곡될 수 있습니다. 이를 방지하기 위해 AspectOnly 설정을 사용합니다.
  * 위치 불일치: 스프라이트의 중심점과 피봇이 일치하지 않으면 위치가 어긋날 수 있습니다. 이를 해결하기 위해 중심점과 피봇을 정확히 설정합니다.



## 결론 및 추가 자료

스프라이트 크기 조정은 UI 디자인에서 필수적인 기술 중 하나입니다. 위의 방법을 통해 스프라이트를 부모 엔티티에 맞게 조정함으로써, 다양한 화면 크기와 해상도에서 일관된 UI를 제공할 수 있습니다.

추가적으로, 를 참조하여 더 많은 정보를 얻을 수 있습니다.
CameraComponent

Entity를 바라보는 카메라 기능을 제공합니다. 카메라 간 화면 전환은 CameraService를 이용하세요.

# Properties

[{"index":"Vector2 CameraOffset","0":"카메라의 위치를 설정합니다. 월드 좌표 기준입니다."}]

[{"index":"boolean ConfineCameraArea","0":"카메라가 비추는 범위를 맵의 발판 영역으로만 제한합니다."}]

[{"index":"Vector2 Damping","0":"카메라가 대상을 추적하는 동안 대상이 SoftZone에 들어갈 때 카메라가 반응하는 속도를 조정합니다. 값이 작을수록 더욱 더 빠르게 반응합니다."}]

[{"index":"Vector2 DeadZone","0":"DeadZone 영역을 설정합니다. 카메라가 타겟을 유지하는 프레임 영역입니다."}]

[{"index":"float DutchAngle","0":"카메라의 회전 값을 설정합니다."}]

[{"index":"boolean IsAllowZoomInOut","0":"줌 기능 사용 여부를 설정합니다."}]

[{"index":"Vector2 LeftBottom (Sync)","0":"카메라 제한 영역의 좌하단 값입니다."}]

[{"index":"string MaterialId (Sync)","0":"렌더러에 적용할 머티리얼 Id를 지정합니다."}]

[{"index":"Vector2 RightTop (Sync)","0":"카메라 제한 영역의 우상단 값입니다."}]

[{"index":"Vector2 ScreenOffset","0":"대상을 기준으로 한 전체 스크린의 비율 값입니다. 0부터 1 사이의 값을 사용할 수 있고, 값이 0.5일 경우 카메라가 중앙에 위치합니다. ConfineCameraArea가 false인 경우 사용 가능합니다."}]

[{"index":"Vector2 SoftZone","0":"SoftZone 영역을 설정합니다. 대상이 프레임의 영역에 들어오면 카메라가 방향을 바꾸어 DeadZone으로 되돌립니다."}]

[{"index":"boolean UseCustomBound (Sync)","0":"카메라 제한 영역을 직접 정의해 사용할지 여부를 나타냅니다. LeftBottom, RightTop 프로퍼티를 사용해 정의할 수 있습니다. false일 시 속해있는 맵의 맵 영역을 사용합니다. 맵 영역이 기본이라면 그 영역을 바탕으로 보정된 영역을 카메라 제한 영역으로 사용합니다."}]

[{"index":"float ZoomRatio","0":"줌 비율을 설정합니다. 값은 ZoomRatioMin 이상, ZoomRationmax 이하로만 설정할 수 있습니다. 단위는 백분율입니다."}]

[{"index":"float ZoomRatioMax","0":"카메라의 줌 비율의 최댓값을 설정합니다. 500보다 큰 값으로 설정할 수 없습니다. 단위는 백분율입니다."}]

[{"index":"float ZoomRatioMin","0":"카메라의 줌 비율의 최소값을 설정합니다. 30보다 작은 값으로 설정할 수 없습니다. 단위는 백분율입니다."}]

##### inherited from Component:

[{"index":"boolean Enable (Sync)","0":"컴포넌트 활성화 여부를 확인합니다."}]

[{"index":"boolean EnableInHierarchy (ReadOnly) (HideFromInspector)","0":"계층 구조상에서 이 컴포넌트가 Enable 상태인지를 반환합니다. Enable이 true일지라도 엔티티의 Enable이 false라면 false를 반환합니다."}]

[{"index":"Entity Entity (ReadOnly)","0":"이 컴포넌트를 소유한 엔티티입니다."}]

# Methods

[{"index":"void ChangeMaterial(string materialId)","0":"렌더러에 적용할 머티리얼을 교체합니다."}]

[{"index":"Vector2, Vector2 GetBound()","0":"LeftBottom, RightTop으로 구성된 카메라 제한 영역을 가져옵니다."}]

[{"index":"void SetZoomTo(float percent, float duration, string targetUserId = nil) (Client)","0":"주어진 시간(초)동안 카메라를 확대합니다."}]

[{"index":"void ShakeCamera(float intensity, float duration, string targetUserId = nil) (Client)","0":"주어진 시간 동안 카메라를 진동시킵니다. 초 단위를 사용합니다."}]

##### inherited from Component:

[{"index":"boolean IsClient()","0":"현재 실행 환경이 클라이언트인지 아닌지의 여부를 반환합니다."}]

[{"index":"boolean IsServer()","0":"현재 실행 환경이 서버인지 아닌지의 여부를 반환합니다."}]

# Examples

4초 뒤에 줌 배율을 300%로 설정하는 코드입니다.
    
    
    @Component
    script DelayedCameraZoom extends Component
        @ExecSpace("ServerOnly")
        method void OnBeginPlay()
        local zoom = function()
            self.Entity.CameraComponent:SetZoomTo(300, 2)
        end
        _TimerService:SetTimerOnce(zoom, 4)
        end
    end
    

# SeeAlso

  * TimerService
  * [CameraService를 활용한 카메라 제어](/docs?postId=118)
뒤통수를 덮는 모자

# 학습 과정 소개

뒤통수를 덮는 모자의 제작 시트를 소개합니다. [아바타 아이템 제작의 기본 개념](/docs?postId=588%7B%22target%22:%22_self%22%7D)을 참고해 아바타의 기본 개념을 먼저 숙지하길 바랍니다.

# 사전 준비

아이템 제작을 위해선 Adobe Photoshop이 필요합니다. 해당 소프트웨어를 설치한 후 아래 파일을 받아 엽니다. $$attachFile {"name":"Avatar_Cap_B.psd","url":"https://mod-file.dn.nexoncdn.co.kr/storage/Avatar_psd/version4_230221/Avatar_Cap_B.psd"} $$

> Tip. 모자는 아바타 발을 기준으로 최대 120x120 안에서 제작을 권장합니다. [png](16769485559327fc72cf03aca4128998b423540c3e049)

# 제작 시트 설명

모자 제작 시트는 회색, 빨간색, 노란색 레이어로 구분되어 있습니다. 회색 레이어는 이미지를 데이터화하기 위한 data 폴더, 이미지 제작에 도움을 줄 아바타 body 레이어, 가이드용 선 레이어가 있습니다. 회색 레이어는 모두 잠겨있고, 작업 중에 수정은 필요하지 않습니다. 노란색 레이어는 크리에이터가 실제 아이템을 그릴 수 있는 곳입니다. 빨간색 레이어는 모자와 헤어의 우선순위를 결정하는 역할을 합니다.

> Tip. 모든 레이어의 이름을 수정하거나 삭제할 경우 아이템을 제작할 수 없습니다. 절대 이름을 변경하지 마세요.

### 회색 레이어/빨간색 레이어

  1. data 폴더: data 폴더는 아이템을 데이터화하기 위해 필요한 폴더입니다. 이미지 제작에는 영향을 주지 않습니다. 
     * data:origin: 빨간색 점으로 데이터의 중심을 표시합니다.
     * data:type:Cap: 어떤 종류의 데이터인지 알 수 있습니다.
     * data:use_zmap_preset1: 아바타를 구성하는 이미지는 층층이 쌓여 만들어집니다. 아바타의 다양한 몸동작을 만들기 위해 몸을 바탕으로 옷, 방패, 무기 순으로 이미지가 층층이 위에 쌓이는 구조입니다.  
아이템에 따라 분리된 각 Sprite의 높이가 순서대로 정리된 파일이 zmap입니다.
  2. guide_ 레이어: 아바타의 샘플 body입니다. 레이어 이름 뒤에 붙은 숫자가 클수록 아래에 배치되는 내부적인 규칙입니다.  

     * guide_backHairBelowCapWide_samples_94, guide_backHairBelowCapNarrow_samples_95는 모자 모양에 따른 넓은 헤어와 좁은 헤어의 샘플입니다.  
[png](16457811937535becc03a37664135889302106c115bff)
  3. (빨간색 레이어) data:vslot:CpH1H4 : 빨간색 레이어는 모자에만 있는 개념입니다. 모자 제작 파일에서의 vslot 레이어는 머리카락과 모자가 겹칠 경우 보이는 우선순위를 결정하는 역할을 합니다. [png](1677032543121310bc61208a34d33b830aba8862f51c4)



### 노란색 레이어

노란색 레이어에 크리에이터가 제작할 모자를 그릴 수 있습니다.

  1. case1.front: 모자의 앞모습을 그릴 레이어와 앞모습의 일반 헤어와 눌린 헤어 샘플이 포함되어 있습니다. 
     * edithere:cap_cap_34: 모자의 앞모습을 그릴 수 있는 레이어입니다.
  2. case2.back: 모자의 뒷모습을 그릴 레이어와 뒷모습의 일반 헤어와 눌린 헤어 샘플이 포함되어 있습니다. 
     * edithere:cap_backCap_92: 모자의 뒷모습을 그릴 수 있는 레이어입니다.



[png](1677033338202aa1833624a264a098601f346edc6fc3f)

> 더 알아보기 뒤통수를 덮는 모자(Avatar_Cap_B)를 작업할 때는 guide_backHairBelowCapWide_samples_94, guide_backHairBelowCapNarrow_samples_95의 헤어 샘플에서 Wide와 Narrow 이미지가 다른 002번 샘플을 사용합니다.
12강 플레이어 정보의 안전한 관리

[png](1729097657351560300b457014a2fa0dbdd8bcc534e25)   
  


# 플레이어 정보 취급 시 유의사항

크리에이터님께서는 플레이어의 개인정보를 요구하지 않아야 하며, 콘텐츠를 운영함에 있어 개인정보 보호법 등 관련 법령상의 개인정보 보호 규정을 준수하여야 합니다. 플레이어의 개인정보를 임의로 수집 및 저장하거나 유출할 경우, 관련 방침에 의거해 별도 조치될 수 있는 만큼 각별한 주의가 필요한데요. 만약 월드 운영 중 불가피하게 일부 플레이어 정보 확인이 필요하거나 개인정보와 관련된 삭제 요청이 유입될 경우 어떻게 처리가 가능할지 살펴보겠습니다.

  
**첫번째, 월드 운영상 목적으로 필요한 경우에만 계정번호를 활용해 주세요.** 

크리에이터는 상품 환불 처리 등 월드 운영상 사용 목적으로 플레이어의 계정번호 확인이 가능합니다. 다만, 반드시 필요한 경우에만 활용해야 하며, 월드 내 또는 커뮤니티 등을 통해 노출하지 않도록 주의해 주시기 바랍니다.

> Q. 공지에 플레이어 정보 노출이 필요할 때는 어떻게 안내해야 하나요❔ A. 공지사항 등에 플레이어 정보를 포함하여 안내해야 한다면 플레이어 정보는 마스킹(가림처리) 후 공개해야 합니다.

[{"@cols=2:메이플스토리 월드 플레이어 정보 마스킹 방법 - 뒤에서부터 전체 글자의 50% 이상을 대체 문자로 변경":"프로필 이름(또는 월드 닉네임)","Unnamed: 1":"계정코드"},{"@cols=2:메이플스토리 월드 플레이어 정보 마스킹 방법 - 뒤에서부터 전체 글자의 50% 이상을 대체 문자로 변경":"(마스킹 전) 메이플스토리월드(마스킹 후) 메이플스****","Unnamed: 1":"(마스킹 전) #ABCDE(마스킹 후) #AB***"}]

  
**두번째, 개인정보 수집 및 이용이 필요한 경우에는 해당 목적에 필요한 최소한의 개인정보만을 적법하고 정당하게 수집해 주세요.** 

플레이어가 제보한 버그/건의 사항을 자세히 확인해야 하거나 문의 대응, 이벤트 진행의 목적으로 개인정보를 수집해야 하는 상황이 발생할 경우, 플랫폼 외부에서 행위라고 하더라도 해당 목적에 필요한 최소한의 개인정보만을 적법하고 정당하게 수집하여야 합니다. 또한 플레이어에게 동의를 받아 개인정보를 수집하는 경우에 아래의 내용을 명확하게 안내해야 합니다   
< 개인정보 수집 동의를 받을 때 안내해야 하는 사항>

  1. 개인정보의 수집 및 이용 목적
  2. 수집하려는 개인정보의 항목
  3. 개인정보의 보유 및 이용 기간
  4. 동의를 거부할 권리가 있다는 사실 및 동의 거부에 따른 불이익이 있는 경우, 해당 불이익의 내용

  
**세번째, 탈퇴로 인한 데이터 삭제 요청에 대응해 주세요.** 

플레이어로부터 계정 탈퇴 사유로 데이터 삭제 요청이 유입될 경우, 월드 내 저장 및 노출되는 해당 계정 정보(프로필, 랭킹 정보 등)는 삭제 또는 플레이어를 알아볼 수 없도록 변경이 필요합니다.

> ※ 주의사항 플랫폼에서 타인의 개인정보를 수집/저장/유포 또는 게시하는 행위는 이용약관 및 운영정책 상 금지하고 있습니다. 플랫폼 외부에서 개인정보 보호법에 따라 수집한 개인정보라 할지라도, 목적 달성 시 복구가 불가능한 방법으로 반드시 개인정보를 파기하여 주시기 바랍니다.

  
  
발행일 : 2024.10.18 / 발행버전: v1.0
로컬화된 Entity

# 학습 과정 소개

클라이언트에서만 생성되는 로컬화된 엔티티에 대해 알아봅시다.

##### 참고 가이드

[서버와 클라이언트](/docs?postId=207%7B%22target%22:%22_blank%22%7D) [예시로 알아보는 서버 검증](/docs?postId=1084%7B%22target%22:%22_blank%22%7D) [패킷 변조 대비하기](/docs?postId=1102%7B%22target%22:%22_blank%22%7D) [Effective MSW 2](/docs/?postId=560%7B%22target%22:%22_blank%22%7D)

# 로컬화된 엔티티

로컬화된 엔티티(Localized Entity)란 클라이언트에서만 생성되는 엔티티를 의미합니다. Hierarchy 창에서는 [png](1744353390721e6e7eb37353d4042aabf7d24c432ba27)가 표시된 엔티티로 구분되어 표시됩니다. 메이플스토리 월드의 엔티티는 기본적으로 서버와 클라이언트에서 각각 생성됩니다. 이는 쉬운 멀티 플레이 월드 제작을 돕기 위함입니다. 그러나 서버에 생성되는 엔티티가 많아질수록 서버의 부담이 늘어나게 됩니다. 만약 서버에서 관리할 필요가 없는 엔티티라면 클라이언트에서만 생성되도록 로컬화된 엔티티로 제작할 수 있습니다. 월드의 꾸미기 요소로 사용하는 엔티티나 데이터를 저장하지 않아도 되는 엔티티를 로컬화하면, 서버-클라이언트 간의 동기화와 통신을 적게 사용함으로써 더욱 효율적으로 월드를 만들 수 있습니다.

로컬화된 엔티티를 사용할 때는 4가지 유의 사항을 염두에 두고 사용해야 합니다.

  1. 부모-자식 관계에 영향을 받습니다. 부모 엔티티를 로컬화된 엔티티로 변경하면 자식 엔티티 모두 동일하게 변경됩니다.
  2. 서버 실행제어 함수를 사용할 수 없습니다.
  3. 서버에서 검증 작업을 할 수 없으므로 변조, 해킹에 취약합니다. 월드 생태계에서 중요한 역할을 하는 엔티티의 경우 로컬화된 엔티티로 사용하지 않도록 주의해야 합니다.
  4. PortalComponent의 경우 로컬화된 엔티티에서 사용할 수 없습니다. 또한 서버 기능을 사용하는 컴포넌트의 경우 일부 기능이 정상적으로 동작하지 않을 수 있습니다.



# 로컬화된 엔티티 만들기

서버와 동기화되는 기본 엔티티를 로컬화된 엔티티로 사용하는 방법은 3가지입니다.

#### Localize 프로퍼티 활성화

Localize 프로퍼티를 활용해 엔티티를 로컬화할 수 있습니다. 이 프로퍼티는 World 하위에 생성하는 엔티티에서만 활성화됩니다. 이 기능을 활성화하면 Scene에 직접 엔티티를 배치했더라도 클라이언트에서만 생성됩니다. Hierarchy - World - maps 하위에 배치한 엔티티를 프로퍼티 창 - 모델 프로퍼티에서 `Localize` 활성화합니다. [png](174433695073900c80e0cc0604735bd090b707991c89b)

#### UI 엔티티로 생성

ui - UI Group에 생성되는 UI엔티티는 클라이언트에서만 생성이 됩니다. UI 엔티티의 경우 기본값이 로컬화된 상태이므로 프로퍼티 에디터 창에 Localize 프로퍼티가 없습니다. [png](1744354007080d2ad5568bf8c4085889573254f82f4ea)

#### SpawnService 활용한 동적 생성

클라이언트 공간에서 `SpawnService`를 호출해 로컬화된 엔티티를 동적으로 생성할 수 있습니다. 동적으로 엔티티를 생성할 때는 생성할 엔티티의 수만큼 SpawnService를 호출해야 합니다. 이는 월드 제작 효율성을 저하시킬 수 있으므로 필요할 때만 사용하는 것이 좋습니다.
비정상 거래 대응 가이드

월드가 성장하고 다수의 유료 상품이 추가되면 더욱 다양한 형태의 거래 및 결제 행위가 발생할 수 있으며 이러한 거래 행위가 올바르게 관리될 수 있도록 본 가이드를 마련하였습니다. 비정상 거래로 인한 피해로부터 크리에이터님의 콘텐츠를 보호할 수 있도록 안내드리는 가이드에 맞춰 사전 예방하시는 것을 권장해 드립니다.

# 비정상 거래 대응의 필요성

크리에이터는 크리에이터가 제작한 월드에서 운영정책 위반 행위가 발생하지 않도록 플레이어 간의 거래 방식과 거래 시스템에 대해 긴밀한 관리가 필요합니다.   


  * 플랫폼에서 금지하고 있는 비정상 거래의 기준에 따른 관리가 이루어지지 않을 경우 월드 내 시장 경제에 피해를 줄 수 있으며, 결제 도용 등을 비롯한 비정상 거래로 인해 선량한 플레이어에게 추가 피해를 줄 수 있습니다.
  * 비정상 거래로 인한 피해 발생 시, 플랫폼에서의 관리 조치에 따라 판매 수익이 차감되거나 마이너스 수익이 발생할 수 있습니다.



# 비정상 거래의 기준

이용약관 및 운영정책을 통해 플랫폼에서 금지하고 있는 비정상 거래의 기준을 확인할 수 있으며, 각 문서에 명시되어 있지 않더라도 관련 법령에서 금지되는 불법적인 거래 등이 확인된 경우 플랫폼에서의 관리 조치가 진행될 수 있습니다. 자세한 내용은 플랫폼 운영정책을 확인해주시기 바랍니다.    


  1. 재화(유료/무료 재화, 아이템 등)를 현금 획득을 목적으로 거래하거나 거래 시도 혹은 유사한 행위를 하는 경우
  2. 아이템 이동 등 현금 거래에 도움을 주는 직접적인 행위나 이를 시도하는 경우
  3. 타인의 개인정보나 결제정보 등을 도용하여 이득을 취하는 경우



> 참고 이러한 거래는 플레이어 간의 1:1 거래 뿐만 아니라 불특정 다수와 거래할 수 있는 거래소 콘텐츠, 우편 발송, 획득한 재화 드랍 등 전반에 걸쳐 적용될 수 있습니다.

# 비정상 거래의 사전 예방

크리에이터는 유료 상품 및 거래 시스템 추가 시 이하 내용을 참고하여 월드 내 콘텐츠를 기획하시는 것을 권장해 드립니다.

  1. 플레이어 간의 거래를 제한하기 
     * 거래 콘텐츠가 없다면 월드 내 계정, 재화를 현금 획득 목적으로 거래하거나 이동하는 등 직접적인 행위 자체를 원천적으로 차단할 수 있습니다. 만약, 월드 설계상 거래 제한이 불가피할 경우 이하의 방법으로 비정상 거래를 효과적으로 지연시킬 수 있습니다.   

  2. 거래 이용을 위한 선제 조건 추가하기 
     * 비정상 거래를 목적으로 유입된 비정상 플레이어가 단기간에 거래를 진행할 수 없도록 다양한 조건을 설정해 보시기 바랍니다.
     * 예시: 레벨 제한, 선행 퀘스트 완료, 특정 업적 달성 등   

  3. 거래 이용 시 대기 시간 추가하기 
     * 비정상 거래를 목적으로 구매/생성된 재화가 월드 내 시장 경제에 영향을 미치는 시간을 저하시킬 수 있습니다. (단, 이 경우 거래의 투명성을 위해 각 재화의 설명에 거래 제한 기간을 함께 명시해 주셔야 합니다.)   

  4. 거래 후 판매 대금 획득 시 대기 시간 추가하기 
     * 거래가 완전히 종료되기 전까지 비정상 거래를 확인하고 선제적인 대응을 할 수 있는 시간이 추가될 수 있습니다.