msw-ai-tf/maplestory-worlds-creator-docs huggingface dataset:
OverlayLightComponent

Overlay 광원을 출력합니다.

# Properties

[{"index":"Color Color (Sync)","0":"광원의 색상입니다."}]

[{"index":"float FalloffDistance (Sync)","0":"광원이 Freeform 타입일 때, 빛이 FreeformPoints로부터 얼마나 뻗어 나갈지 결정합니다. 값이 클수록 크기가 커집니다."}]

[{"index":"float FalloffIntensity (Sync)","0":"광원이 사라지는 곡선의 부드러움을 조절합니다. 값이 클수록 광원의 경계선이 흐릿하고 부드러워 보입니다. 값이 작을수록 광원의 경계선이 날카롭고 또렷하게 보입니다."}]

[{"index":"SyncList FreeformPoints (Sync)","0":"Freeform 타입의 광원 모양을 정의하는 점들입니다. 점의 개수는 2000개를 초과할 수 없습니다."}]

[{"index":"float InnerRadius (Sync)","0":"광원이 Spot 타입일 때 최대 밝기를 갖는 내부 광원 영역의 반경입니다. OuterRadius보다 큰 값을 가질 수 없습니다."}]

[{"index":"float Intensity (Sync)","0":"광원의 강도입니다."}]

[{"index":"int32 LightOrder (Sync)","0":"광원이 라이트 텍스처에 렌더링되는 순서를 결정합니다. 낮은 수의 광원이 먼저 렌더링되고, 높은 수의 광원이 그 위에 렌더링됩니다. OverlapOperation이 AlphaBlend일 때 동작합니다. Global 타입은 LightOrder를 사용하지 않습니다."}]

[{"index":"float OuterRadius (Sync)","0":"Spot 타입의 광원 크기를 결정하는 외부 반경입니다. InnerRadius의 끝에서부터 빛이 감쇠되기 시작하여 이 반지름에 도달하면 빛의 강도가 0%가 됩니다."}]

[{"index":"OverlayLightOverlapOperation OverlapOperation (Sync)","0":"광원의 연산 방식입니다. Global 타입은 OverlapOperation을 사용하지 않습니다."}]

[{"index":"float PlayRate (Sync)","0":"Sprite 타입의 광원일 때 사용하는 애니메이션 클립 리소스의 재생 속도입니다. 숫자가 클수록 재생 속도가 빨라집니다."}]

[{"index":"float SpotInnerAngle (Sync)","0":"Spot 타입 광원의 내부 각도입니다. 각도가 클수록 간격이 넓어집니다. 내부 각도에 있는 모든 픽셀은 빛의 강도가 100%로 적용됩니다. SpotOuterAngle보다 큰 값을 가질 수 없습니다."}]

[{"index":"float SpotOuterAngle (Sync)","0":"Spot 타입 광원의 외부 각도입니다. 값이 클수록 각도가 넓어집니다. SpotInnerAngle의 끝에서부터 빛이 감쇠되기 시작하여 SpotOuterAngle에 도달하면 빛의 강도는 0%가 됩니다."}]

[{"index":"string SpriteRUID (Sync)","0":"Sprite 타입의 광원이 그려낼 스프라이트의 RUID입니다."}]

[{"index":"OverlayLightType Type (Sync)","0":"광원의 종류입니다. Spot, Freeform, Global, Sprite 네 가지 광원을 사용할 수 있습니다."}]

##### 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

##### inherited from Component:

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

[{"index":"boolean IsServer()","0":"현재 실행 환경이 서버인지 아닌지의 여부를 반환합니다."}]
제작한 월드 불러오기 및 관리

# 학습 과정 소개

제작한 월드를 불러오고 관리하는 방법을 알아봅니다.

# 제작 중인 월드 불러오기

  1. 메뉴에서 [만들기] 버튼을 클릭합니다. [png](16654666396025c27dfec219f44d4855305b5b5bbb3fd)   

  2. 월드 목록에서 불러올 월드를 선택합니다. [png](1697688993495dab3281a7ede406f835f4373d835b71a)   

  3. 월드 정보에서 [이어서 만들기] 버튼을 클릭하면 제작 중인 월드를 불러옵니다. [png](169761419461164f8c0c53c4c49a8920f32be1fe8670d)



# 리비전 관리

월드를 제작할 때는 리비전을 기록하고 관리하는 과정이 필요합니다. 중요한 변경점이 발생했을 때마다 리비전을 기록해두면 필요한 순간에 예전 리비전으로 월드를 되돌릴 수 있어 안전합니다. 또한 이전 버전을 추적하고 관리할 때 편리합니다.

##### 리비전 기록하기

File - Revisions 메뉴로 들어가면 리비전을 기록할 수 있습니다. [png](16892261674937e4332ad952c4bfba92ca79c12271eb4)

Revisions 창에서 [지금 기록하기] 버튼을 누르면 간단한 메모와 함께 리비전을 저장할 수 있습니다. [png](1689227369728d4ea35ebfb104ac48448359ff18c8f36)

##### 리비전 관리 기능

Revisions 창에서는 아래의 기능을 사용할 수 있습니다. [png](16892318009566f218c41f5bc4e98aa8c8db8d22b4971)

[{"번호":"[jpg](1634541272181b5c1a55fcf3d49b19734d25913c38583)","기능":"메모 수정","설명":"리비전 메모를 수정합니다."},{"번호":"[jpg](1634541300837cb541c2f44e046a79bb1901a885aa8ac)","기능":"다운로드","설명":"해당 리비전의 mod 파일을 다운로드합니다."},{"번호":"[jpg](163454131465069e090278448490f965207e9a4a10348)","기능":"되돌리기","설명":"해당 리비전으로 되돌립니다. 개인 월드는 바로 리비전을 되돌릴 수 있지만 그룹 월드는 복구 모드를 켠 뒤 리비전을 되돌릴 수 있습니다. 자세한 내용은 [공동 제작](\/docs\/?postId=670) 가이드의 복구 모드 내용을 참고합니다."},{"번호":"[jpg](1634541326353d8628c1473944497bf376acb7a65ca45)","기능":"제거","설명":"리비전을 제거합니다."}]

  
> **더 알아보기** > 월드 정보에서 **[⋯] - [리비전]** 버튼을 클릭해도 리비전 관리를 할 수 있습니다. > [png](16982844687277d91f57257414627911fa276d4652ea6) > [png](1697614268934a9692437551e43f49f5f383a8ccf5139) 

# 월드 삭제

출시하지 않은 월드만 삭제가 가능합니다. 출시한 월드는 삭제가 불가능합니다.

  1. 월드 목록에서 삭제할 월드를 선택합니다. [png](1697688993495dab3281a7ede406f835f4373d835b71a)   

  2. [⋯] 버튼을 클릭합니다. [png](1697614389339483bb4702a3b4b1597707aa6fecd1595)   

  3. 월드 관리 팝업 창에서 [월드 삭제] 버튼을 누릅니다. [png](16976144114251253358153f8432e862cc4fce67c4100)   




> 더 알아보기 이미 출시된 월드는 삭제할 수 없습니다. 출시된 월드의 월드 관리 팝업 창에는 [리비전], [크리티컬 리포트] 버튼만 보입니다.
그룹 생성과 멤버 관리

# 학습 과정 소개

월드를 함께 만들기 위해서는 그룹에 가입해야 합니다. 그룹을 만들어 팀원들과 함께 월드를 만들 수 있습니다. 협동한다면 내가 잘하는 것에 집중할 수 있고, 새로운 영감이나 번뜩이는 아이디어를 떠올릴 수도 있습니다. 세상에 선보이고 싶은, 아름답고 재미있는 월드를 함께 만들 사람을 찾아 그룹에 초대해 봅시다.

# 그룹 관리 소개

메이플스토리 월드 클라이언트와 에서 그룹을 생성하고, 멤버를 관리할 수 있습니다.

#### 그룹 생성

그룹장은 그룹을 10개까지 만들 수 있고, 그룹마다 인원 제한은 없습니다. 한번 생성된 그룹은 삭제할 수 없습니다.

  1. [월드 만들기] - [+그룹] 버튼을 클릭합니다.
  2. 그룹 이름을 입력하고 [다음] 버튼을 누릅니다. [png](1682650366279afe2a5bd22dc49cd85b1d4f485fdc2b4)



#### 멤버 등급 관리

  1. 그룹을 선택하고, [멤버관리] 메뉴로 들어갑니다. [png](1689813631553716bdb65929d493e8d5db006b48843a5)
  2. 원하는 멤버의 등급을 조정합니다. 등급을 변경하면 상단의 멤버 현황에 반영됩니다. [png](175308342240534475ca3483a4f9694dcc8b9e831a4af)



> 더 알아보기 멤버 등급 구분 및 권한에 대한 자세한 내용은 [공동 제작 그룹 멤버의 등급과 권한](/docs/?postId=1077) 가이드를 참고합니다.

#### 그룹장 양도

  1. [멤버관리] 메뉴에서 원하는 멤버를 선택하고 [⋮] 메뉴를 클릭합니다.
  2. [그룹장 양도] 버튼을 클릭합니다. [png](1689814837844a0ba1949e5424ecebdc1ad82546c8bf0)
  3. 팝업 창의 내용을 확인한 후 [양도] 버튼을 클릭하면 그룹장 권한 양도가 완료됩니다. [png](168981495670313bf8553e0c9446ca92284f80265d316)



#### 멤버 내보내기

그룹장은 멤버를 그룹에서 탈퇴시킬 수 있습니다. 탈퇴 멤버는 그룹의 모든 월드에서 편집 권한을 박탈당합니다.

  1. [멤버관리] 메뉴에서 삭제할 멤버를 선택하고 [⋮] 메뉴를 클릭합니다.
  2. [내보내기] 버튼을 클릭합니다. [png](168981578441839ce171ee1274aecb99ec61e54291fb8)



# 그룹 가입 신청

가입하고 싶은 그룹을 발견했다면 먼저 그룹 가입 신청을 할 수도 있습니다. 가입 신청을 하면 그룹장이나 매니저가 가입 허가 여부를 결정할 수 있습니다.

  1. 가입을 원하는 그룹 이름을 클릭합니다. [png](1689826803097e6c4deea9be145f5a5ae56a7e0ca96b0)
  2. 그룹 정보 페이지에서 [가입 신청] 버튼을 클릭합니다. [png](1689821977348304ef0c631114129b13e0a84b86e08e6)



# 접속 중인 멤버 확인

함께 제작하는 그룹 월드에서 Panels - Cooperation을 누릅니다. 해당 월드에 함께 접속 중인 사람들의 닉네임과 메이커 아이디가 보입니다. [png](1656652152957d88e3a917e4a44b984a825324ca881f1)
DamageSkinService

대미지 스킨 관련 기능을 제공합니다.

# Methods

[{"index":"void Play(Entity targetEntity, string skinId, float delayPerAttack, table damages, DamageSkinTweenType tweenType, boolean bCritical, Vector2 offset = Vector2(0, 0), Vector2 scale = Vector2(0, 0), float playRate = 1, float alpha = 1, LitMode litMode = LitMode.Default)","0":"대미지 스킨을 재생합니다. scale을 (0, 0)을 지정하거나 생략하면 (1, 1)로 사용됩니다. damages에 들어갈 타입은 integer, DamageSkinTextType입니다. DamageSkinTextType은 지정한 크리티컬 여부가 반영되지 않습니다. playRate가 0보다 작거나 같을 경우 1로 대체됩니다 대미지 스킨 재생 함수에 LitMode를 설정할 수 있습니다. 기본값은 LitMode.Default 입니다."}]

[{"index":"void Play(Entity targetEntity, string skinId, float delayPerAttack, table damages, DamageSkinTweenType tweenType, table criticals, Vector2 offset = Vector2(0, 0), Vector2 scale = Vector2(0, 0), float playRate = 1, float alpha = 1, LitMode litMode = LitMode.Default)","0":"대미지 스킨을 크리티컬 여부에 맞춰 재생합니다. scale을 (0, 0)을 지정하거나 생략하면 (1, 1)로 사용됩니다. damages 테이블과 criticals 테이블은 반드시 길이가 같아야 합니다. damages에 들어갈 타입은 integer, DamageSkinTextType입니다. DamageSkinTextType은 지정한 크리티컬 여부가 반영되지 않습니다. playRate가 0보다 작거나 같을 경우 1로 대체됩니다. 대미지 스킨 재생 함수에 LitMode를 설정할 수 있습니다. 기본값은 LitMode.Default 입니다."}]

[{"index":"void PlayTextDamage(Entity targetEntity, string skinId, DamageSkinTextType textType, DamageSkinTweenType tweenType, Vector2 offset = Vector2(0, 0), Vector2 scale = Vector2(0, 0), float playRate = 1, float alpha = 1, LitMode litMode = LitMode.Default)","0":"DamageSkinTextType에 맞는 대미지 스킨이 출력됩니다. scale을 (0, 0)을 지정하거나 생략하면 (1, 1)로 사용됩니다. playRate가 0보다 작거나 같을 경우 1로 대체됩니다. 대미지 스킨 재생 함수에 LitMode를 설정할 수 있습니다. 기본값은 LitMode.Default 입니다."}]

[{"index":"void PreloadAsync(string skinId, func completeCallback) (ClientOnly)","0":"skinId에 맞는 대미지 스킨을 미리 불러옵니다. 이 함수는 비동기로 실행되며 completeCallback을 통해 작업 완료를 통지받을 수 있습니다."}]

##### inherited from Service:

[{"index":"EventHandlerBase ConnectEvent(string key, IScriptFunction eventHandler)","0":"이벤트를 연결합니다. 이 서비스에서 타입의 이름이 key인 이벤트가 발생하면, 핸들러로 통지받습니다. 핸들러는 event 매개 변수를 전달받습니다."}]

[{"index":"EventHandlerBase ConnectEvent(Type eventType, IScriptFunction eventHandler)","0":"이벤트를 연결합니다. 이 서비스에서 타입이 eventType인 이벤트가 발생하면, 핸들러로 통지받습니다. 핸들러는 event 매개 변수를 전달받습니다."}]

[{"index":"boolean DisconnectEvent(string key, EventHandlerBase eventHandler)","0":"타입의 이름이 key인 이벤트와 핸들러와의 이벤트 연결을 끊습니다."}]

[{"index":"boolean DisconnectEvent(Type eventType, EventHandlerBase eventHandler)","0":"타입이 eventType인 이벤트와 핸들러와의 연결을 끊습니다."}]

[{"index":"void SendEvent(EventType sendEvent)","0":"이벤트를 발생시킵니다."}]

# Examples
    
    
    @Component
    script TriggerDamageSkinApplier extends Component
        @EventSender("Self")
        handler HandleTriggerEnterEvent(TriggerEnterEvent event)
        --------------- Native Event Sender Info ----------------
        -- Sender: TriggerComponent
        -- Space: Server, Client
        ---------------------------------------------------------
    
        -- Parameters
        local TriggerBodyEntity = event.TriggerBodyEntity
        ---------------------------------------------------------
        _DamageSkinService:Play(TriggerBodyEntity, "000000", 0.05, {1, 2, 3}, DamageSkinTweenType.Default, false)
        end
    end
화면 기준으로 카메라 설정하기

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

# 화면 기준으로 카메라 설정하기

> 이 아티클에서는 `CameraComponent`와 `CameraService`를 활용하여 카메라를 캐릭터가 아닌 화면 기준으로 설정하는 방법을 알아봅니다. 화면 기준 카메라는 게임 플레이의 유연성을 높이고, 특정 화면 위치를 중심으로 더 나은 사용자 경험을 제공합니다.

## 화면 기준의 카메라 설정 이해

화면 기준의 카메라 설정은 게임 개발에서 중요한 요소입니다. 이는 카메라가 캐릭터 대신 화면의 특정 위치를 따라 이동하도록 하여 보다 유연한 시점을 제공합니다. 이러한 설정은 특히 UI 중심의 게임이나 특정 이벤트를 강조할 때 유용합니다.

## CameraComponent와 CameraService 활용

`CameraComponent`는 카메라의 다양한 속성을 설정할 수 있는 컴포넌트입니다. 주요 프로퍼티로는 `CameraOffset`, `ConfineCameraArea`, `ScreenOffset` 등이 있으며, 이들은 화면 기준 설정에 기여합니다.

  * CameraOffset: 카메라의 위치를 월드 좌표 기준으로 설정합니다.
  * ScreenOffset: 화면의 중심을 기준으로 카메라가 위치할 비율을 조정합니다.
  * ConfineCameraArea: 카메라가 비추는 범위를 맵의 발판 영역으로 제한합니다.



`CameraService`는 카메라 전환을 위한 메소드를 제공합니다. `SwitchCameraTo` 메소드를 사용하여 특정 `CameraComponent`로 카메라를 전환할 수 있습니다.

## 로직 구현을 통한 실습

카메라 설정을 위한 로직을 구현하려면 `Logic`을 활용합니다. 다음은 `SwitchCameraToTargetEntity` 함수를 구현하고, 버튼 클릭 이벤트를 통해 카메라 전환을 트리거하는 예제입니다.
    
    
    Property:
    Component targetCamera = "b701ace9-481e-4849-996e-45b4bb69b043:CameraComponent"
    boolean custom = "false"
    
    Method:
    void SwitchCameraToTargetEntity()
    {
        log("switch camera")
        if self.custom then
            self.custom = false
            _CameraService:SwitchCameraTo(_UserService.LocalPlayer.CameraComponent, _UserService.LocalPlayer)
        elseif self.targetCamera then
            log("TargetCamera"..tostring(self.targetCamera))
            _CameraService:SwitchCameraTo(self.targetCamera, _UserService.LocalPlayer)
            self.custom = true
        end
    }
    
    EventHandler:
    HandleButtonClickEvent (ButtonClickEvent event)
    {
        self:SwitchCameraToTargetEntity()
    }
    

위 코드는 버튼 클릭 시 카메라를 전환하며, 두 번 클릭하면 다시 플레이어로 돌아옵니다.

## 테스트 및 최적화

작성한 로직을 테스트하면서 `Damping`과 `SoftZone` 등의 프로퍼티를 조정하여 최적의 카메라 움직임을 설정할 수 있습니다. `TransitionBlendTime`과 `TransitionBlendType`을 활용하여 부드러운 전환을 구현하는 것도 중요합니다.

## 추가 기능 및 고급 설정

카메라 줌 기능을 활용하여 화면을 확대/축소할 수 있습니다. `ZoomTo` 및 `ZoomReset` 메소드를 사용하여 줌 효과를 구현할 수 있습니다. 또한, `DutchAngle`을 통해 화면에 회전 효과를 추가하여 사용자 경험을 향상시킬 수 있습니다.

## 결론 및 추가 자료

화면 기준 카메라 설정은 게임의 시각적 표현을 크게 향상시킬 수 있습니다. 이 아티클에서 소개한 방법을 통해 카메라를 보다 유연하게 제어할 수 있으며, 추가적인 설정을 통해 사용자 경험을 극대화할 수 있습니다.

관련 자료:

  * 
  * 
  *
ButtonComponent의 버튼 상태를 비활성화(disable) 하는 법

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

# ButtonComponent의 버튼 상태를 비활성화(disable) 하는 법

> 이 글에서는 `ButtonComponent`의 버튼 상태를 비활성화하는 방법에 대해 알아봅니다. `ButtonComponent`는 UI에서 버튼의 기능을 제공하며, 다양한 상태 전환과 이벤트 처리를 지원합니다. 이 글을 통해 ButtonComponent의 기능을 이해하고, 비활성화를 구현하는 방법을 배워보세요.

## ButtonComponent 이해하기

`ButtonComponent`는 UI에서 버튼의 기능을 제공하는 컴포넌트입니다. 다양한 상태 전환 효과와 이벤트를 통해 사용자와 상호작용할 수 있습니다. 주요 프로퍼티로는 `Enable`, `TransitionColorSet`, `TransitionType` 등이 있으며, 이러한 프로퍼티를 통해 버튼의 상태와 스타일을 정의할 수 있습니다. 이 컴포넌트는 엔티티 내에서 UI 요소로 작동하며, 프로퍼티 에디터와 스크립트를 통해 제어할 수 있습니다.

## 프로퍼티 에디터를 통한 상태 변경

`ButtonComponent`의 상태를 비활성화하려면, `프로퍼티 에디터` 창에서 `Enable` 프로퍼티를 조정해야 합니다. `Enable` 프로퍼티는 컴포넌트의 활성화 여부를 결정하며, 체크박스를 통해 쉽게 변경할 수 있습니다. 또한, 동기화(Synchronization)와 계층 구조(Hierarchy)에서의 동작 방식을 이해하면, 보다 효과적으로 컴포넌트를 제어할 수 있습니다.

## 스크립트를 사용하여 상태 변경

스크립트를 통해 `ButtonComponent`의 `Enable` 프로퍼티를 제어하는 방법도 있습니다. `Script API`를 활용하여 동적으로 버튼 상태를 변경할 수 있습니다. 아래는 스크립트를 사용한 코드 예제입니다:
    
    
    Property:
    boolean isEnabled = true
    
    Method:
    [server]
    void toggleButtonState()
    {
        self.Entity.ButtonComponent.Enable = not self.isEnabled
        self.isEnabled = not self.isEnabled
    }
    

이 코드는 버튼의 활성화 상태를 토글하는 간단한 예제입니다. `Script Editor`를 사용하여 스크립트를 작성하고 테스트할 수 있습니다.

## 이벤트 핸들러를 통한 버튼 상태 관리

`ButtonStateChangeEvent`를 활용하면 버튼 상태가 변경될 때 이벤트를 처리할 수 있습니다. `이벤트 핸들러`를 설정하여 상태 변경 시 추가적인 로직을 구현할 수 있습니다. 예를 들어, 동적 스프라이트(Dynamic Sprite)를 활용하여 상태 변경 시 시각적 피드백을 제공할 수 있습니다.
    
    
    EventHandler:
    HandleButtonStateChangeEvent(ButtonStateChangeEvent event)
    {
        if event.state == ButtonState.Disabled then
            -- 비활성화 상태일 때의 로직
        end
    }
    

## 테스트 및 최적화

작성한 스크립트와 설정을 `테스트 플레이 상태`에서 검증해보세요. 버튼 상태 변경이 `월드 인스턴스`에 미치는 영향을 분석하고, 최적화(Optimization)를 통해 성능을 향상시킬 수 있습니다. `프로파일러(Profiler)`를 사용하면 최적화 작업을 손쉽게 진행할 수 있습니다.

## 결론 및 추가 자료

이 글에서는 `ButtonComponent`의 버튼 상태를 비활성화하는 방법에 대해 알아보았습니다. 프로퍼티 에디터와 스크립트를 활용하여 버튼의 상태를 제어할 수 있으며, 이벤트 핸들러를 통해 다양한 로직을 구현할 수 있습니다. 더 자세한 정보는 아래 링크를 참고하세요.
메이플스토리 월드에서 기본 아바타 변경하는 법

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

# 메이플스토리 월드에서 기본 아바타 변경하는 법

> 메이플스토리 월드에서 기본적으로 제공되는 메이플 아바타 대신 자신만의 독특한 캐릭터로 게임을 시작하고 싶다면, 이 가이드를 참고하세요.

## 개념 설명

메이플스토리 월드에서는 기본적으로 `DefaultPlayer` 모델을 사용하여 캐릭터를 생성합니다. 이 모델은 게임에 접속할 때 자동으로 사용되며, 기본 메이플 아바타로 설정되어 있습니다. 그러나, 게임의 독창성을 높이고 싶다면 다른 모델로 변경할 수 있습니다. 이때 중요한 요소는 `DefaultUserEnterLeaveLogic`의 `PlayerUri` 속성입니다. 이 속성을 통해 사용할 모델의 ID를 설정할 수 있습니다.

## 사용 사례 및 필요성

게임 개발자는 종종 기본 아바타 대신 자신만의 캐릭터를 사용하고자 합니다. 이는 게임의 테마나 스타일에 맞게 캐릭터를 커스터마이징하여 독창성을 부여하기 위함입니다. 예를 들어, 판타지 테마의 게임에서는 메이플 아바타 대신 드래곤이나 기사 캐릭터를 사용할 수 있습니다. 이러한 변경은 게임의 사용자 경험을 크게 향상시키고, 플레이어에게 새로운 재미를 제공합니다.

## 구체적인 사용 방법

  1. 캐릭터 초기 속성 편집

     * `Workspace`에서 `BaseEnvironment - NativeModel - Player`를 선택하고 기본 속성을 조정합니다.
  2. DefaultUserEnterLeaveLogic 설정

     * `PlayerUri` 속성을 수정하여 사용할 모델의 ID를 설정합니다. 모델의 `Entry ID`는 `Copy Model ID` 기능을 사용하여 가져올 수 있습니다.
  3. 모델 생성 및 적용

     * 새로운 모델을 생성하고 `Workspace`에 추가합니다. 생성된 모델의 `Entry ID`를 복사하여 `PlayerUri`에 적용합니다. 서버 영역에서 변경 사항을 적용해야 합니다.
  4. 스크립트 작성 및 테스트

     * `스크립트 에디터`를 사용하여 `PlayerUri`를 변경하는 스크립트를 작성합니다. 아래 예제를 참고하세요:
    
    Method:
    void OnBeginPlay()
    {
        _DefaultUserEnterLeaveLogic.PlayerUri = "model://418071d6-458a-446b-bce1-6e7b91198379"
    }
    

     * 이 스크립트를 서버에서 실행하여 변경 사항을 테스트합니다.
  5. 최종 검토 및 배포

     * 모든 변경 사항을 검토하고 테스트 플레이를 통해 정상 작동을 확인합니다.



## 잠재적 문제 및 해결책

  * 문제: `PlayerUri`가 잘못 설정되어 캐릭터가 나타나지 않을 수 있습니다.

    * 해결책: `Copy Model ID`를 사용하여 올바른 `Entry ID`를 가져와야 합니다.
  * 문제: 서버 영역에서 변경 사항이 반영되지 않을 수 있습니다.

    * 해결책: 반드시 서버에서 스크립트를 실행하고 변경 사항을 적용해야 합니다.



## 결론 및 추가 자료

메이플스토리 월드에서 기본 아바타를 변경하는 방법을 알아보았습니다. 이를 통해 게임의 독창성을 높이고, 플레이어에게 새로운 경험을 제공할 수 있습니다. 추가로 모델 생성 및 활용에 대한 자세한 내용은 을 참고하시기 바랍니다.

참조 링크:

  * 
  *
TweenFloatingComponent

Entity가 위 아래로 왕복 이동합니다.

# Properties

[{"index":"float Amplitude (Sync)","0":"최저점에서 최고점까지의 거리를 설정합니다. 값이 1인 경우 시작 위치에서 최고\/최저점까지의 거리는 0.5가 됩니다."}]

[{"index":"float OneCycleTime (Sync)","0":"최저점에서 최고점까지 이동하는데 걸리는 시간을 설정합니다. 초 단위입니다.예를 들어, 값이 1인 경우 한 이동 주기는 2초가 소요됩니다."}]

[{"index":"EaseType TweenType (Sync)","0":"움직임 효과를 설정합니다."}]

##### inherited from TweenBaseComponent:

[{"index":"boolean AutoDestroy (Sync)","0":"true일 경우, 트윈이 목적지에 도달하여 끝나거나 직접 Stop()을 호출했을 때 이 컴포넌트를 엔티티에서 제거합니다."}]

[{"index":"boolean AutoStart (Sync)","0":"값이 true일 경우, 게임이 시작되면 트윈이 자동으로 재생합니다."}]

[{"index":"TweenState CurrentState (Sync) (ReadOnly) (HideFromInspector)","0":"현재 재생 상태입니다."}]

[{"index":"Vector3 OriginPosition (Sync) (ReadOnly) (HideFromInspector)","0":"트윈의 시작 위치입니다."}]

[{"index":"Quaternion OriginRotation (Sync) (ReadOnly) (HideFromInspector)","0":"트윈의 시작 회전값입니다."}]

[{"index":"Vector3 OriginScale (Sync) (ReadOnly) (HideFromInspector)","0":"트윈의 시작 크기입니다."}]

[{"index":"TweenSyncType SyncType (ReadOnly)","0":"재생 주체를 설정합니다. 기본값은 Default입니다. 서버와 클라이언트에서 함수로 트윈을 제어할 수 있습니다. 서버 상태는 클라이언트로 항상 동기화됩니다. 실행 공간 제어를 client only로 설정하면 클라이언트에서만 트윈을 제어하도록 제한하고, 서버로 동기화하지 않습니다.트윈 제어 함수: Play, Pause, Stop, Destroy, RestartFromCurrentPosition"}]

[{"index":"number TweenTime (ReadOnly) (HideFromInspector)","0":"트윈이 시작된 후 경과한 시간입니다. 초 단위입니다."}]

##### 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

##### inherited from TweenBaseComponent:

[{"index":"void Destroy()","0":"컴포넌트를 제거합니다. CurrentState를 Destroying으로 변경합니다."}]

[{"index":"void Pause()","0":"트윈을 일시정지합니다. CurrentState를 Pausing으로 변경합니다."}]

[{"index":"void Play()","0":"트윈을 재생합니다. CurrentState를 Playing으로 변경합니다."}]

[{"index":"void RestartFromCurrentPosition()","0":"현재 위치에서 재시작합니다."}]

[{"index":"void Stop(boolean reset)","0":"트윈을 중지합니다. CurrentState를 Idle로 변경합니다. reset에 true를 지정할 경우 트윈의 위치와 진행도를 초기 상태로 되돌립니다."}]

##### inherited from Component:

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

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

# Examples

Entity가 부유하는 듯한 효과를 주는 예제입니다.
    
    
    @Component
    script FloatTweenConfig extends Component
        @ExecSpace("ServerOnly")
        method void OnBeginPlay()
            local tween = self.Entity.TweenFloatingComponent
            
            -- 이동 거리 0.1
            tween.Amplitude = 0.1
            -- 주기 1초
            tween.OneCycleTime = 1
            -- 서서히 느려지다가 다시 빨라지는 효과
            tween.TweenType = EaseType.QuadEaseInOut
        end
    end
    

# SeeAlso

  * EaseType
CostumeManagerComponent

플레이어가 장착한 의상, 무기 등의 정보를 관리합니다.

# Properties

[{"index":"string CustomBodyEquip (Sync)","0":"피부"}]

[{"index":"string CustomCapeEquip (Sync)","0":"망토"}]

[{"index":"string CustomCapEquip (Sync)","0":"모자"}]

[{"index":"string CustomCoatEquip (Sync)","0":"코트"}]

[{"index":"string CustomEarAccessoryEquip (Sync)","0":"귀 장식"}]

[{"index":"string CustomEarEquip (Sync)","0":"귀"}]

[{"index":"string CustomEyeAccessoryEquip (Sync)","0":"눈 장식"}]

[{"index":"string CustomFaceAccessoryEquip (Sync)","0":"얼굴 장식"}]

[{"index":"string CustomFaceEquip (Sync)","0":"얼굴"}]

[{"index":"string CustomGloveEquip (Sync)","0":"장갑"}]

[{"index":"string CustomHairEquip (Sync)","0":"헤어스타일"}]

[{"index":"string CustomLongcoatEquip (Sync)","0":"롱코트"}]

[{"index":"string CustomOneHandedWeaponEquip (Sync)","0":"한손무기"}]

[{"index":"string CustomPantsEquip (Sync)","0":"하의"}]

[{"index":"string CustomShoesEquip (Sync)","0":"신발"}]

[{"index":"string CustomSubWeaponEquip (Sync)","0":"보조무기"}]

[{"index":"string CustomTwoHandedWeaponEquip (Sync)","0":"두손무기"}]

[{"index":"string DefaultEquipUserId (Sync) (HideFromInspector)","0":"대상 유저의 장비를 복제한 이후 커스텀 장비들이 적용됩니다. 접속 중이지 않은 유저도 지정할 수 있으며, 지정 후 대상 유저의 장비가 변경된 경우는 반영되지 않습니다."}]

[{"index":"ReadOnlyList EquippedItems (ReadOnly) (HideFromInspector)","0":"현재 착용 중인 장비들의 정보입니다. 스크립트에서 수정할 수 없습니다."}]

[{"index":"boolean UseCustomEquipOnly (Sync)","0":"유저가 장착한 기본 의상을 사용하지 않고, 스크립트를 이용해 지정한 의상만을 사용합니다."}]

##### 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":"string GetEquip(MapleAvatarItemCategory category) (ClientOnly)","0":"현재 장착 중인 itemRUID를 반환합니다. 프로퍼티를 이용한 접근이 가능합니다."}]

[{"index":"void SetEquip(MapleAvatarItemCategory category, string itemRUID)","0":"입력한 itemRUID에 해당하는 아이템을 장착합니다. 장비를 해제하려면 빈 문자열을 입력합니다. 프로퍼티를 이용한 변경이 가능합니다."}]

##### inherited from Component:

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

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

# Events

[{"index":"DestroyMapleCostumeEvent","0":"CostumeManagerComponent가 삭제될 때 발생하는 이벤트입니다."}]

[{"index":"InitMapleCostumeEvent","0":"장비 착용 상태에 변화가 있을 때 발생하는 이벤트입니다."}]

# Examples

다음 예제는 플레이어와 다른 Entity가 닿았을 때 플레이어의 헤어를 변경하고 RUID를 출력합니다.
    
    
    @Component
    script HairClearTrigger extends Component
        @EventSender("Self")
        handler HandleTriggerEnterEvent(TriggerEnterEvent event)
        --Parameters
        local TriggerBodyEntity = event.TriggerBodyEntity
        --------------------------------------------------------
        if self:IsServer() == true then
            return
        end
    
        local costumeManager = TriggerBodyEntity.CostumeManagerComponent
        costumeManager:SetEquip(MapleAvatarItemCategory.Hair, "000000")
        log (costumeManager:GetEquip(MapleAvatarItemCategory.Hair))
        end
    end
    

# SeeAlso

  * TriggerEnterEvent
다각형 그리기

# 학습 과정 안내

PolygonRendererComponent를 활용해 다각형을 월드에 자유롭게 그릴 수 있습니다.

# PolygonRendererComponent

`PolygonRendererComponent`는 점을 이어 월드에 다각형을 그릴 수 있습니다. 추가된 점의 순서를 따라 다각형이 그려집니다. 만약 점을 이을 때 선이 교차하면 다각형은 그려지지 않습니다. 다각형이 그려지는지 확인이 필요할 때는 `IsDrawable()` 함수를 사용해 확인할 수 있습니다.

아래와 같이 점들의 좌표를 입력하면 (0,0) (3,2)를 연결한 선과 (1,0) (2,2)를 연결한 선이 교차하기 때문에 다각형이 그려지지 않습니다. [png](1692247765816f43f2f51cd72421fa5b6b38c8f1a1b4e)

선끼리 교차하지 않게 점들의 좌표를 입력하면 다각형이 그려집니다. [png](16922477424456fa94597546b46dfb64ac2eed48916c7)

`PolygonRendererComponent`의 주요 프로퍼티는 아래와 같습니다.

  * Points Edit: [Edit] 버튼을 눌러 편집을 활성화 할 수 있습니다. Scene에서 Point 위치를 수정 및 추가, 삭제할 수 있습니다.
  * Color: 다각형의 색상을 지정합니다.
  * Points: 선을 구성하는 정점들의 집합입니다. 
    * Size: 선을 연결하는 점의 개수를 의미합니다. 0부터 시작하며, Size에 입력한 값만큼 점이 추가됩니다.
    * [숫자]: 몇 번째 점인지를 의미합니다. X, Y 값은 점의 좌표입니다.



# 활용 예제

#### 다각형 그리기

  1. 새로운  EmptyEntity를 생성하고, TransformComponent, PolygonRendererComponent를 추가합니다.
  2. PolygonRendererComponent의 Points를 선택하고, Size에 수를 입력합니다.
  3. 점의 좌표를 입력하고, Color를 지정합니다. [png](16944121241288615fed41bbe4d32bc36b4eea6e4b651)



> Tip. Points가 2,000개를 초과하면 이후 Points는 그려지지 않습니다. 서로 다른 변을 교차하게 Points를 배치하면 다각형이 그려지지 않습니다.

#### 머티리얼로 다각형 그리기

머티리얼의 PolygonSprite 셰이더를 활용해 다각형을 칠할 수 있습니다. 머티리얼 활용 방법은 [머티리얼 활용하기](docs/?postId=828)를 참고하세요. PolygonRendererComponent에 활용하는 머티리얼의 스프라이트로는 유저 리소스와 복제한 MSW 리소스를 사용할 수 있습니다. MSW 리소스 복제 방법은 [리소스 관리](docs/?postId=690)를 참고하세요.

  1. Workspace - MyDesk - Create Material을 선택해 새로운 Material을 만듭니다.
  2. 생성한 머티리얼의 프로퍼티 창에서 Shader - PolygonRenderer - PolygonSprite를 선택합니다.
  3. SpriteRUID에 사용할 이미지를 선택합니다. 필요한 경우 Offset, Scale 값을 조정합니다.
  4.  EmptyEntity를 생성하고, PolygonRendererComponent를 추가합니다.
  5. PolygonRendererComponent의 MaterialId에서 을 눌러 머티리얼을 지정합니다. [png](1694413381584443e343db0c5476daf441bf8017867cf)



> Tip. 유저 리소스와 복제한 MSW 리소스 모두 랩 모드를 Repeat로 설정해야 합니다. [png](168422631874542cfe7bb765e4d659b113e430d223b99)

> Tip. 머티리얼이 적용된 다각형의 크기를 키우면 머티리얼도 따라 커집니다. 다각형의 Rotate 값이 변경되면, 머티리얼의 스프라이트도 따라 변경됩니다. [png](169225197319446744ec0a8594315ade9ee52da40ac70)