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

맵에 물리 법칙을 적용합니다. 물리 연산과 관련된 설정을 조절할 수 있습니다.

# Properties

[{"index":"Vector2 Gravity (Sync)","0":"물리 연산의 중력 값을 설정합니다."}]

[{"index":"boolean Paused (Sync)","0":"물리 연산의 일시정지 여부를 설정합니다."}]

[{"index":"Vector2 WorldBounds (Sync) (ReadOnly)","0":"물리 연산 범위를 설정합니다. 엔티티가 범위를 벗어나면 물리 연산을 하지 않습니다. 예를 들어, 값을 (100, 100)으로 설정하면 원점(0, 0)을 중심으로 가로 200, 세로 200 크기의 사각형 영역이 물리 연산 범위가 됩니다."}]

##### 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 SetPositionIteration(int32 count)","0":"물리 엔진의 위치 연산 반복 횟수를 설정합니다. 값이 클수록 물리 연산 결과가 정교해지며 더 많은 연산 시간이 소요됩니다. 최솟값은 1, 최댓값은 300입니다. 서버는 적용되지 않습니다."}]

[{"index":"void SetVelocityIteration(int32 count)","0":"물리 엔진의 속도 연산 반복 횟수를 설정합니다. 값이 클수록 물리 연산 결과가 정교해지며 더 많은 연산 시간이 소요됩니다. 최솟값은 1, 최댓값은 30입니다. 서버는 적용되지 않습니다."}]

##### inherited from Component:

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

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

# Examples

누르는 키에 따라 물리 시뮬레이션을 일시 정지시키거나, 중력 설정을 변경할 수 있는 예제입니다.
    
    
    @Component
    script PhysicsControl extends Component
        @ExecSpace("ServerOnly")
        @EventSender("Self")
        handler HandleTriggerEnterEvent(TriggerEnterEvent event)
        --------------- Native Event Sender Info ----------------
        -- Sender: InputService
        -- Space: Client
        ---------------------------------------------------------
    
        -- Parameters
        local inputValue = event.inputValue
        local key = event.key
        ---------------------------------------------------------
        if key == KeyboardKey.P then
        	self.Entity.CurrentMap.PhysicsSimulatorComponent.Paused = not self.Entity.CurrentMap.PhysicsSimulatorComponent.Paused
        elseif key == KeyboardKey.G then
        	self.Entity.CurrentMap.PhysicsSimulatorComponent.Gravity = Vector2(0, 0)
        end
        end
    end
    

# SeeAlso

  * KeyboardKey
  * [다양한 물리 joint 활용하기](/docs?postId=760)
  * [물리 사용하기](/docs?postId=757)
  * [엔티티에 물리 적용하기 ](/docs?postId=761)
GridViewComponent 활용법 알아보기

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

# GridViewComponent 활용법 알아보기

> GridViewComponent는 대량의 UI Entity를 효율적으로 관리하고 표시할 수 있는 기능을 제공합니다. 이 아티클에서는 GridViewComponent의 기본 개념과 실제 사용 예제를 통해 어떻게 활용할 수 있는지 알아보겠습니다.

## GridViewComponent란?

GridViewComponent는 UI를 `Grid` 형태로 표현하는 데 최적화된 컴포넌트입니다. 화면에 보이는 UI Entity만 생성하고 재사용함으로써 성능을 향상시킵니다. 이는 특히 대량의 Grid를 표현할 때 매우 유용합니다.

### 주요 속성 및 메서드

  * ItemEntity: 자식 UI Entity 생성 시 복제될 원본입니다.
  * TotalCount: GridView에 표시될 자식 UI Entity의 총 개수입니다.
  * OnClear: 자식 UI Entity가 사용되지 않을 때 호출되는 콜백입니다.
  * OnRefresh: 자식 UI Entity가 재사용될 때 호출되는 콜백입니다.



## GridViewComponent 사용 사례

GridViewComponent는 다양한 UI 레이아웃에서 활용될 수 있습니다. 예를 들어, 인벤토리 시스템에서 아이템 슬롯을 그리드 형태로 정렬하여 사용자에게 직관적인 인터페이스를 제공할 수 있습니다.

## GridViewComponent의 실제 사용 방법

다음은 GridViewComponent를 활용한 간단한 예제입니다. 이 코드는 기본적인 인벤토리 시스템을 구성하는 방법을 보여줍니다.
    
    
    Property:
    [None]
    GridViewComponent Inventory = nil
    [None]
    Entity InventorySlot = nil
       
    Method:
    [client only]
    void OnBeginPlay ()
    {
        self.Inventory.ItemEntity = self.InventorySlot
        self.Inventory.OnRefresh = self.OnRefresh
        self.Inventory.OnClear = self.OnClear
        self.Inventory.TotalCount = 10
        self.Inventory:Refresh()
    }
      
    void OnRefresh (number index, Entity entity)
    {
        entity:GetChildByName("Name").TextComponent.Text = tostring(index)
    }
      
    void OnClear (number index, Entity entity)
    {
        entity:GetChildByName("Name").TextComponent.Text = ""
    }
    

### 코드 설명

  * `self.InventorySlot`에 복제될 원본을 정의합니다.
  * `TotalCount`를 10으로 설정하여 Grid에 표시될 엔티티의 수를 결정합니다.
  * `OnClear`와 `OnRefresh` 콜백을 통해 엔티티의 텍스트를 설정하거나 비웁니다.



## 잠재적 문제 및 해결책

GridViewComponent를 사용할 때 자주 발생하는 문제는 잘못된 인덱스 참조입니다. 이를 피하기 위해 항상 인덱스 범위를 확인하고, 콜백 함수에서 올바른 엔티티를 참조하도록 주의해야 합니다.

## 결론 및 추가 자료

GridViewComponent는 대량의 UI Entity를 효율적으로 관리할 수 있는 강력한 도구입니다. 이 아티클에서 제공한 예제를 기반으로 다양한 UI 구성에 적용해 보세요. 추가 자료는 아래 링크를 통해 확인할 수 있습니다.
MapleAvatarItemCategory

MapleStory 아바타 아이템 분류를 나타냅니다.

# Members

[{"이름":"Invalid","값":"0","설명":"미정의 상태입니다. 오류 검출에 사용됩니다."},{"이름":"Body","값":"1","설명":"아바타 몸통 슬롯에 장착하는 아이템입니다."},{"이름":"Head","값":"2","설명":"사용할 수 없는 아이템입니다. Body와 동일한 색상으로 자동 설정됩니다."},{"이름":"Hair","값":"3","설명":"아바타 헤어 슬롯에 장착하는 아이템입니다."},{"이름":"Face","값":"4","설명":"아바타 표정 슬롯에 장착하는 아이템입니다."},{"이름":"Cap","값":"5","설명":"아바타 모자 슬롯에 장착하는 아이템입니다."},{"이름":"Cape","값":"6","설명":"아바타 망토 슬롯에 장착하는 아이템입니다."},{"이름":"Coat","값":"7","설명":"아바타 상의 슬롯에 장착하는 아이템입니다."},{"이름":"Glove","값":"8","설명":"아바타 장갑 슬롯에 장착하는 아이템입니다."},{"이름":"Longcoat","값":"9","설명":"아바타 한벌 옷 슬롯에 장착하는 아이템입니다. 상의, 하의 슬롯을 사용합니다."},{"이름":"Pants","값":"10","설명":"아바타 하의 슬롯에 장착하는 아이템입니다."},{"이름":"Shield","값":"11","설명":"사용할 수 없는 아이템입니다. SubWeapon을 사용해 동일한 위치에 아이템을 장착할 수 있습니다."},{"이름":"Shoes","값":"12","설명":"아바타 신발 슬롯에 장착하는 아이템입니다."},{"이름":"OneHandedWeapon","값":"13","설명":"아바타의 한 손 슬롯에 장착하는 아이템입니다."},{"이름":"TwoHandedWeapon","값":"14","설명":"아바타 양손 슬롯에 장착하는 아이템입니다. 한 손과 보조무기 슬롯을 사용합니다."},{"이름":"SubWeapon","값":"15","설명":"아바타 보조 무기 슬롯에 장착하는 아이템입니다."},{"이름":"FaceAccessory","값":"16","설명":"아바타의 표정 액세서리 슬롯에 장착하는 아이템입니다."},{"이름":"EyeAccessory","값":"17","설명":"아바타의 눈 액세서리 슬롯에 장착하는 아이템입니다."},{"이름":"EarAccessory","값":"18","설명":"아바타의 귀 액세서리 슬롯에 장착하는 아이템입니다."},{"이름":"Ear","값":"19","설명":"아바타의 귀 슬롯에 장착하는 아이템입니다."}]

# Methods

[{"index":"MapleAvatarItemCategory CastFrom(number value) (Static)","0":"숫자를 해당 타입으로 변환합니다."}]

[{"index":"MapleAvatarItemCategory CastFrom(string value) (Static)","0":"문자열을 해당 타입으로 변환합니다."}]
SpawnService

엔티티 스폰 관련 기능을 제공합니다.

# Methods

[{"index":"Entity Clone(string name, Entity original, Entity parent = nil, boolean posOffset = true, boolean dynamic = true) (Deprecated)","0":"더는 사용하지 않는 함수입니다. SpawnByEntity(Entity, string, Vector3, Entity, boolean) 함수를 사용하세요."}]

[{"index":"Entity SpawnByEntity(Entity entity, string name, Vector3 spawnPosition, Entity parent = nil, boolean includeChild = true)","0":"entity를 바탕으로 새로운 엔티티를 스폰합니다. name은 스폰할 엔티티의 이름, spawnPosition은 위치, parent는 부모 엔티티입니다. nil이면 entity의 부모 엔티티를 부모로 지정합니다. includeChild가 false면 entity의 자식 엔티티는 스폰되지 않습니다."}]

[{"index":"Entity SpawnByEntityTemplate(Entity entityTemplate, string name, Vector3 spawnPosition, boolean includeChild = true, boolean dynamic = true, boolean needSync = true, boolean nameEditable = true) (Deprecated)","0":"더는 사용하지 않는 함수입니다. SpawnByEntity(Entity, string, Vector3, Entity, boolean) 함수를 사용하세요."}]

[{"index":"Entity SpawnByModelId(string id, string name, Vector3 spawnPosition, Entity parent)","0":"id에 해당하는 모델을 바탕으로 새로운 엔티티를 스폰합니다. name는 스폰할 모델의 이름, spawnPosition은 위치, parent는 부모 엔티티입니다."}]

[{"index":"Entity SpawnByModelId(string id, string name, Vector3 spawnPosition, Entity parent, string ownerId, boolean dynamic = true, boolean needSync = true, boolean nameEditable = true) (Deprecated)","0":"더는 사용하지 않는 함수입니다. SpawnByModelId(string, string, Vector3, Entity) 함수를 사용하세요."}]

##### 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 HierarchicalSpawner extends Component
        @ExecSpace("ServerOnly")
        method void OnBeginPlay()
        local entity = _EntityService:GetEntityByPath("Entity Path")
        local clone1 = _SpawnService:SpawnByEntity(entity, "clone1", Vector3(1, 0, 0))
    
        local modelId = "Model Entry Id"
        local clone2 = _SpawnService:SpawnByModelId(modelId, "clone2", Vector3(0, 1, 0), clone1)
        end
    end
    

# SeeAlso

  * EntityService
이동 발판 만들기

# 학습 과정 소개

움직이는 발판을 만들어 이동에 재미를 더해보세요. CustomFootholdComponent의 IsDynamicFoothold 프로퍼티를 이용해 나만의 움직이는 발판을 만들 수 있습니다. [발판 만들기](/docs/?postId=71%7B%22target%22:%22_self%22%7D)에서 기본 발판 제작 방법을 배울 수 있습니다.

# 이동 발판 만들기

이동 발판은 CustomFootholdComponent를 활용해 크리에이터가 직접 만들어야 합니다. 발판의 움직임을 만드는 방식은 다르지만, 기본 CustomFootholdComponent를 움직이게 만들기 위해선 IsDynamicFoothold, RigidbodyMovementOption 프로퍼티를 설정해야 합니다.

[{"프로퍼티 명":"IsDynamicFoothold","설명":"움직이는 발판을 만들기 위해 활성화합니다."},{"프로퍼티 명":"RigidbodyMovementOption","설명":"움직이는 발판 위의 플레이어 엔티티가 어떤 관성을 받을 것인지 방식을 적용합니다.RelativeX: x축 관성은 적용하고, y축 관성은 적용하지 않습니다. 플레이어가 발판의 이동 방향과 반대로 움직이면 속도가 감속하고, 같은 방향으로 움직이면 가속합니다. Absolute: 플레이어가 어느 방향으로 움직여도 속도가 동일합니다."}]

[{"index":"RelativeX","0":"[gif](16466307010962640bc0dca2b4ba28d72e8138ee4a5cf)"},{"index":"Absolute","0":"[gif](1646633877812d9fd5ab7b34d468abc8018984875cdf5)"}]

#### 활용 예시

  1. 발판으로 사용할 오브젝트에 CustomFootholdComponent를 추가하고, 발판을 만듭니다.
  2. CumstomFootholdComponent - IsDynamicFoothold를 활성화합니다.
  3. CumstomFootholdComponent - RigidbodyMovementOption을 RelativeX로 설정합니다.  
[png](16820538852880d9d1813790d4636b5b483c6f0b7e885)
  4. 새로운 컴포넌트를 생성하고 발판 오브젝트에 추가합니다.
  5. 새로운 컴포넌트의 스크립트 에디터 창을 열고, 발판의 이동 시간과 범위를 아래와 같이 작성합니다. `TransformComponent:Translate(0,0)`의 x 값만 입력할 경우 좌우로 이동하고, y 값만 입력할 경우 상하로 움직입니다. 두 값을 모두 입력하면 대각선으로 움직입니다.


    
    
    @Component
    script VerticalCyclicMovement extends Component
        @Sync
        property number totalTime = 0
    
        @ExecSpace("ServerOnly")
        method void OnUpdate(number delta)
        self.totalTime = self.totalTime + delta
        if self.totalTime > 0 and self.totalTime <= 5.0 then
            self.Entity.TransformComponent:Translate(0,0.009)
        elseif self.totalTime > 5.0 and self.totalTime <= 10.0 then
            self.Entity.TransformComponent:Translate(0,-0.009)
        elseif self.totalTime > 10 then
            self.totalTime = 0
        end
        end
    end
14강 플랫폼 외부 광고 정책

[png](172908737195587536219c563451ba8fbbe833660df7a)   
  
제작한 CGC를 플랫폼 외부에 광고. 홍보 등을 하고 싶을 때 사전에 어떤 내용을 참고하는 것이 좋을까요? 이번 가이드에서는 플랫폼 외부 광고를 하기 전 어떤 내용을 참고하면 좋을지 알아보도록 하겠습니다.

  
# 플랫폼 외부 광고 정책 

CGC를 플랫폼 외부에서 광고, 홍보 등을 목적으로 사용하고자 하는 경우에 대한 내용은 에서 확인할 수 있으며, 해당 이용약관에서 명시하고 있는 내용은 다음과 같습니다.   
<플랫폼 외부 광고 정책 관련 이용약관 명시 내용> 크리에이터가 CGC를 플랫폼 외부에서 광고, 홍보 등 목적으로 사용하고자 하는 경우,

  * 크리에이터는 사전에 Toben이 지정한 방식에 따라 사용 허락을 받아야 합니다.
  * Toben은 이 경우 플랫폼 외부에서 사용을 위한 별도의 조건을 부과할 수 있으며, 크리에이터가 해당 조건을 위반하는 경우 CGC 사용 허락은 즉시 취소되거나 종료될 수 있습니다.
  * 원칙적으로 크리에이터의 플랫폼 외부에서 CGC를 사용한 영리적인 수익 행위는 금지됩니다.

  
이 외에도 아래와 같은 내용을 유의 깊게 보고 사전에 점검해 보시는 것을 추천 드립니다.   
# 유의 깊게 봐야 하는 내용 

CGC를 플랫폼 외부에서 광고, 홍보 등을 희망하는 경우 기본적으로 에서 제공하고 있는 이용약관 및 운영정책에 대한 내용을 유의 깊게 살펴보고, 이를 위반하지 않기 위해 노력하는 것이 중요합니다.

CGC를 플랫폼 외부에 광고, 홍보 등을 하고자 할 때는 부정적인 영향을 줄 수 있는 내용이나 이미지 등이 포함되지 않도록 유의가 필요하며, 이를 점검하기 위해 플랫폼에서 CGC 관련해 금지하고 있는 행위가 무엇인지 참고하는 것을 추천 드립니다.   
CGC 관련 금지 행위는 선정적, 음란성, 잔인함, 혐오감, 폭력적, 자극적, 사기, 사행, 타인의 권리 침해, 개인정보 침해 및 사회적 통념상 비정상적이거나 일반적이지 않은 의도를 가진 내용이나 행위를 의미합니다. 상세 내용은 에서 확인할 수 있습니다.

  
또한, 및 등 관련 법령을 위반하지 않도록 미리 관련 법률을 참고해 주시기 바랍니다.   
  
발행일 : 2025.03.21 / 발행버전: v1.1
SyncTable<,>의 원소 수를 확인하는 법

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

# SyncTable<,>의 원소 수를 확인하는 법

> 이 글에서는 메이플스토리 월드에서 `SyncTable<,>`의 원소 수를 구하는 방법을 단계별로 설명합니다. SyncTable의 개념과 동기화의 중요성을 이해하고, 이를 활용한 실용적인 예제를 통해 게임 개발에 응용할 수 있는 방법을 알아봅니다.

## SyncTable<,> 소개

`SyncTable<,>`은 메이플스토리 월드에서 데이터 동기화를 위해 사용되는 특별한 형태의 테이블입니다. 일반적인 `table`과 달리 `key`와 `value`에 각각 정해진 타입만 설정할 수 있으며, 서버와 클라이언트 간의 데이터 동기화를 지원합니다. 이는 게임 내에서 실시간 데이터 관리를 가능하게 하며, 데이터의 일관성을 유지하는 데 중요한 역할을 합니다.

## 프로퍼티와 동기화의 개념 이해

프로퍼티는 메이플스토리 월드의 컴포넌트 멤버 변수로, 엔티티 별로 다른 값을 가질 수 있습니다. 동기화는 이러한 프로퍼티를 서버와 클라이언트 간에 일치시키는 과정으로, `SyncTable<,>`에서 중요한 기능입니다. 이를 통해 게임 내 데이터가 모든 플레이어에게 동일하게 유지됩니다.

## SyncTable<,>의 원소 수 구하는 방법

`SyncTable<,>`의 원소 수를 구하기 위해서는 `Lua` 스크립트의 `pairs`와 `for` 루프를 사용할 수 있습니다. 아래는 이를 구현한 예제 코드입니다:
    
    
    Method:
    integer GetSyncTableLength(SyncTable table)
    {
        local length = 0
        for _ in pairs(table) do
            length += 1
        end
     
        return length
    }
    

이 함수는 `SyncTable`을 인자로 받아, `for` 루프를 통해 각 원소를 순회하며 길이를 계산합니다.

## SyncTable<,> 원소 수 구하기의 실용적 응용

원소 수를 구하는 기능은 게임 개발에서 다양한 방식으로 활용될 수 있습니다. 예를 들어, 동기화된 데이터를 기반으로 실시간 게임 로직을 구현하거나, 플레이어의 인벤토리 관리, 리더보드 업데이트 등에 활용할 수 있습니다. 메이플스토리 월드에서는 이러한 기능이 동기화된 환경에서의 데이터 관리에 특히 유용합니다.

## 결론 및 추가 자료

이 글에서는 `SyncTable<,>`의 원소 수를 구하는 방법과 그 실용적 응용에 대해 알아보았습니다. 이 개념을 이해하고 적용함으로써, 메이플스토리 월드에서 더욱 일관되고 안정적인 게임 환경을 구축할 수 있습니다.

추가 학습을 원하신다면  문서를 참조하시기 바랍니다.
AvatarRendererComponent

아바타 형태의 엔티티를 렌더링합니다.

# Properties

[{"index":"boolean IgnoreMapLayerCheck (Sync)","0":"SortingLayer에 Map Layer 이름을 지정했을 때 자동 치환을 수행하지 않습니다."}]

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

[{"index":"int32 OrderInLayer","0":"같은 Layer 내의 우선순위를 결정합니다. 수가 클수록 앞에 보입니다."}]

[{"index":"float PlayRate (Sync)","0":"아바타 애니메이션의 재생 속도입니다."}]

[{"index":"boolean ShowDefaultWeaponEffects (Sync)","0":"무기의 기본 이펙트 애니메이션과 기본 사운드 재생 여부를 설정합니다."}]

[{"index":"string SortingLayer (Sync)","0":"Avatar의 SortingLayer를 설정합니다. 2개 이상의 엔티티가 겹쳤을 때 Sorting Layer에 따라 보이는 우선순위가 결정됩니다."}]

##### 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":"Entity GetAvatarRootEntity() (ClientOnly)","0":"아바타를 구성하는 최상위 엔티티를 가져옵니다."}]

[{"index":"Entity GetBodyEntity() (ClientOnly)","0":"아바타의 몸통에 해당하는 엔티티를 가져옵니다."}]

[{"index":"Entity GetFaceEntity() (ClientOnly)","0":"아바타의 얼굴에 해당하는 엔티티를 가져옵니다."}]

[{"index":"void PlayEmotion(EmotionalType emotionalType, float duration, string targetUserId = nil) (Client)","0":"감정 표현을 재생합니다."}]

[{"index":"void SetAlpha(float alpha, string targetUserId = nil) (Client)","0":"아바타의 Alpha 값을 설정합니다."}]

[{"index":"void SetAvatarPartColor(MapleAvatarItemCategory category, float r, float g, float b, float a, string targetUserId = nil) (Client)","0":"아바타의 category에 해당하는 파츠의 Color 값을 설정합니다. RGB 값을 사용합니다."}]

[{"index":"void SetColor(float r, float g, float b, float a, string targetUserId = nil) (Client)","0":"아바타의 Color 값을 설정합니다. RGB 값을 사용합니다."}]

##### inherited from Component:

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

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

# Events

[{"index":"OrderInLayerChangedEvent","0":"Component의 OrderInLayer가 변경되었을 때 발생하는 이벤트입니다."}]

[{"index":"SortingLayerChangedEvent","0":"컴포넌트의 SortingLayer가 변경되었을 때 발생하는 이벤트입니다."}]
StateAnimationComponent

상태 변화에 따라 재생될 애니메이션을 지정합니다.

# Properties

[{"index":"SyncDictionary ActionSheet (Sync)","0":"애니메이션의 이름과 AnimationClip이 매핑된 table입니다. IsLegacy의 값이 true일 때 사용됩니다."}]

##### 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 ReceiveStateChangeEvent(IEventSender sender, StateChangeEvent stateEvent) (ScriptOverridable)","0":"StateChangeEvent를 받았을 때 처리하는 함수입니다. 기본적으로 State에 매핑된 AnimationClip을 재생하는 AnimationClipEvent를 발생시킵니다."}]

[{"index":"void RemoveActionSheet(string key)","0":"StateToAvatarBodyActionSheet에서 key에 해당하는 요소를 제거합니다. IsLegacy 값이 true면 ActionSheet에서 요소를 제거합니다."}]

[{"index":"void SetActionSheet(string key, string animationClipRuid)","0":"StateToAvatarBodyActionSheet에 요소를 추가합니다. 요소로 추가되는 AvatarBodyActionElement 객체의 AvatarBodyActionStateName 프로퍼티 값은 animationClipRuid, PlayerRate 프로퍼티 값은 1이 됩니다. IsLegacy의 값이 true면 ActionSheet에 요소를 추가합니다."}]

[{"index":"string StateStringToAnimationKey(string stateName) (ScriptOverridable)","0":"State에 매핑된 Animation의 이름을 반환합니다."}]

##### inherited from Component:

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

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

# Events

[{"index":"AnimationClipEvent","0":"AnimationClip 변경이 필요할 때 발생하는 이벤트입니다."}]

# Examples

몬스터가 무작위 피격 애니메이션을 출력하도록 하는 예제입니다. 몬스터의 기본 `StateAnimationComponent`을 삭제하고, `StateAnimationComponent`를 확장한 아래 Component를 추가합니다. 몬스터를 공격 시 다양한 주황버섯의 피격 애니메이션을 확인할 수 있습니다.

애니메이션 재생이 필요할 때 `StateStringToAnimationKey()` 함수가 호출되기 때문에 `SetRandomHitAnimation`을 미리 호출합니다. `hit` 애니메이션 키에 무작위 애니메이션 클립을 설정함으로써, `hit` 애니메이션을 재생할 때 설정된 애니메이션 클립이 재생됩니다.
    
    
    @Component
    script HitAnimationRandomizer extends Component
        property table HitAnimations = {}
    
        method void OnBeginPlay()
        table.insert(self.HitAnimations, "000000")
        table.insert(self.HitAnimations, "000000")
        table.insert(self.HitAnimations, "000000")
        table.insert(self.HitAnimations, "000000")
        end
    
        method void SetRandomHitAnimation()
        self:SetActionSheet("hit", self.HitAnimations[_UtilLogic:RandomIntegerRange(1, #self.HitAnimations)])
        end
    
        override method string StateStringToAnimationKey(string stateName)
        if stateName == "HIT" then
        	self:SetRandomHitAnimation()
        end
    
        return __base:StateStringToAnimationKey(stateName)
        end
    end
    

# SeeAlso

  * UtilLogic
  * table
UserService로 사용자 목록 관리하기: 모든 사용자를 한눈에 파악하는 방법

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

# UserService로 사용자 목록 관리하기: 모든 사용자를 한눈에 파악하는 방법

> 게임 개발에서 사용자 목록을 관리하는 것은 필수적입니다. 특히, 여러 `월드 인스턴스`가 존재하는 환경에서는 더욱 그렇습니다. 이 글에서는 `UserService`를 활용해 사용자 목록을 효과적으로 조회하는 방법을 소개합니다.

## UserService란 무엇인가요?

`UserService`는 게임 서버와 클라이언트에서 사용자 목록을 관리하는 핵심 서비스입니다. 서버에서는 `Room` 기준으로, 클라이언트에서는 `Map` 기준으로 작동합니다. 이 서비스는 `UserEntities`와 `Users`라는 두 가지 주요 데이터를 제공합니다.

  * UserEntities: 사용자 엔티티 정보를 담고 있습니다.
  * Users: 사용자 ID, 닉네임, 프로필 코드 등의 정보를 제공합니다.



## 월드 인스턴스와 Room의 이해

`월드 인스턴스`는 최대 10명의 사용자를 수용할 수 있으며, 이를 초과하면 새로운 인스턴스가 생성됩니다. 각 `월드 인스턴스`는 `정적 룸`과 `인스턴스 룸`을 포함할 수 있습니다. 여러 인스턴스에 걸쳐 사용자 목록을 통합하려면 각 인스턴스의 사용자 정보를 집계해야 합니다.

## 사용자 목록 조회 코드

사용자 목록을 조회하는 코드는 다음과 같습니다. 이 코드는 `UserEntities`와 `Users`를 로그로 출력하여 사용자 정보를 확인할 수 있습니다.
    
    
    -- 사용자 Entity를 가져옵니다.
    log("UserEntities", _UserService.UserEntities.Count)
    for k, v in pairs(_UserService.UserEntities) do
        log(k)
        log(v)
    end
    
    -- 사용자 정보를 가져옵니다.
    log("Users", _UserService.Users.Count)
    for k, v in pairs(_UserService.Users) do
        log(k)
        log(v)
        log(v.UserId)
        log(v.Nickname)
        log(v.ProfileCode)
    end
    

## DataStorage 활용 및 주의사항

`DataStorage`를 활용하여 사용자 데이터를 비동기적으로 집계할 수 있습니다. 그러나 이 작업은 비동기적으로 이루어지므로, 정확한 데이터를 얻기 위해서는 일정 시간마다 데이터를 취합해야 합니다.

  * 주의사항: `DataStorage` 사용량에는 제한이 있으며, 이를 초과하지 않도록 관리해야 합니다.



## 월드 인스턴스 간 통신 최적화

`WorldInstanceSharedMemory`와 `DataStorage`를 활용하면 `월드 인스턴스` 간의 통신을 최적화할 수 있습니다. 비동기 데이터 전송과 `동기화`는 정확한 사용자 목록을 유지하는 데 중요합니다.

## 결론 및 추가 자료

`UserService`를 활용하여 사용자 목록을 관리하는 방법을 이해하면, 게임 내 사용자 경험을 크게 향상시킬 수 있습니다. 추가로 학습할 수 있는 자료는 다음 링크를 참고하세요:

  * 
  * 



이 정보를 통해 사용자 목록을 관리하는 데 있어 더욱 효율적인 방법을 찾을 수 있기를 바랍니다.
배경 설정하기

# 학습 과정 소개

Preset List와 BackgroundComponent를 활용하여 맵의 배경을 설정해봅시다.

# 템플릿 배경 설정

Preset List - Background에서 메이플스토리의 다양한 배경을 선택할 수 있습니다. [png](1660872151969aea4b5e0f90c4c2ab1c556a2ea900127)

이와 같이 배경 템플릿을 선택하면 배경이 움직이는 속도, 즉 ScrollRate를 조절할 수 있습니다. [png](1676524214491fd465cd70f484b7baa55a9c7cceb1a78)

ScrollRate 값이 커지면 배경이 움직이는 속도가 빨라지며, 음수를 입력하면 반대 방향으로 이동합니다.

[{"ScrollRate":"1","Image":"[gif](1676524614371f682d76a305e4987aa04507430a3f891)"},{"ScrollRate":"10","Image":"[gif](1676524628557d5e56dce60f74ab59a962793a594b408)"},{"ScrollRate":"-10","Image":"[gif](16765246400798c2f36ddf63a47bc92883f9d493b22d6)"}]

# 단색 배경 설정

Preset List - Solid Background에서 단색 배경을 설정할 수 있습니다. [png](1660872533050bd027ce1934b47669a0f3d3f82994180)

프리셋으로 제공되는 것 외의 다른 색상을 설정하고 싶다면 [+] 버튼을 눌러 컬러 팔레트를 연 뒤 원하는 색상을 설정할 수 있습니다. [png](1660872694830338c5a59114a46aa9d41eeecbfae1203)

# 그라데이션 배경 설정

Hierarchy - 현재 맵 - Background 선택 후 프로퍼티 에디터의 BackgroundComponent에서 Type을 Gradient로 변경하면 그라데이션 배경을 설정할 수 있습니다. [png](1675686701848d25aebc9b2b645519a894cb17489b07a) 그라데이션의 최상단, 중상단, 중하단, 최하단 색상을 컬러 팔레트에서 선택합니다. 또한 MiddleTopRatio, MiddleBottomRatio 프로퍼티로 중상단, 중하단 색상의 위치를 설정합니다. 이처럼 Gradient 타입을 활용하면 손쉽게 크리에이터가 원하는 형태의 그라데이션 배경을 만들 수 있습니다.

# 이미지 배경 설정

## 저장된 이미지로 배경 설정

Preset List - Image Background에서 크리에이터가 저장하고 있던 이미지를 배경으로 설정할 수 있습니다. [png](1660874114096e52157d7c9fa444c8c5b1c3173ee0d7d)

## 웹 이미지로 배경 설정

웹상의 이미지를 배경으로 설정할 수 있습니다.

  1. 배경으로 설정하려는 이미지 링크를 복사합니다. [png](1662419003792c23005e9e1de42d4972dd217aacb1bae)   

  2. BackgroundComponent의 Type을 Web으로 설정한 뒤, WebURL에 복사한 주소를 붙여 넣습니다. [png](1662419129189d4b5d5fb2028458baa10f740ecfbac45)   

  3.  시작을 누른 뒤 테스트해 봅시다. 아래와 같이 웹상의 이미지가 배경으로 설정된 것을 확인할 수 있습니다. [gif](166241921017719b68e8cb4674133892283180eb6a3e2)
`---@type` 어노테이션으로 함수 타입 지정하기

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

# `---@type` 어노테이션으로 함수 타입 지정하기

> 함수에 `---@type` 어노테이션을 사용하여 타입을 지정하는 방법을 알아봅니다. 이를 통해 코드의 가독성과 유지보수성을 높일 수 있습니다.

## 어노테이션과 `---@type`의 역할

어노테이션(Annotation)은 코드에 메타데이터를 추가하여 스크립트 어시스트 기능을 활용할 수 있게 합니다. `---@type` 어노테이션은 함수나 변수의 타입을 명시적으로 지정하여 퀵 인포나 시그니처 헬퍼의 도움을 받을 수 있습니다. 이는 코드의 문법 강조와 코드 컴플리션을 더욱 효과적으로 만들어 줍니다.

## 함수 타입 지정 방법

함수의 타입을 지정할 때는 다음과 같은 기본 문법을 사용합니다:
    
    
    ---@type function(param_name: PARAM_TYPE):RETURN_TYPE
    

이 문법을 사용하면 매개 변수와 반환 타입을 명확하게 정의할 수 있습니다.

### 사용 예시
    
    
    ---@type function()
    local testFunction = function() end
    
    ---@type function(testParamA: string, testParamB: Entity)
    local testFunction = function(testParamA, testParamB) end
    
    ---@type function(testParamA: string, testParamB: Entity): AttackComponent
    local testFunction = function(testParamA, testParamB) return atkComponent end
    
    ---@type function(testParamA: string, testParamB: Entity): AttackComponent, string
    local testFunction = function(testParamA, testParamB) return atkComponent, "strValue" end
    

## 다양한 함수 타입 지정 예시

### 여러 매개 변수와 반환 타입

여러 매개 변수를 가지는 함수나 여러 값을 반환하는 함수의 타입을 지정할 때는 아래와 같이 작성할 수 있습니다:
    
    
    ---@type (function(testParamA: string, testParamB: Entity): AttackComponent, string), Entity
    local testFunction, testEntity = function(testParamA, testParamB) return atkComponent, "strValue" end, self.Entity
    

## 어노테이션의 활용 이점

스크립트 에디터에서 `---@type` 어노테이션을 사용하면 시그니처 헬퍼와 퀵 인포의 도움을 받아 코드 작성이 훨씬 수월해집니다. 이는 코드 검사와 코드 컴플리션 기능과 통합되어, 보다 정확하고 효율적인 코딩을 가능하게 합니다.

## 메이플스토리 월드에서의 실제 사용 사례

메이플스토리 월드의 스크립트 에디터에서는 `---@type` 어노테이션을 사용하여 스크립트 어시스트 기능을 극대화할 수 있습니다. 이는 Workspace나 UI 에디터에서 다양한 스크립트 작업을 할 때 유용하게 활용됩니다.

## 결론 및 추가 자료

`---@type` 어노테이션을 사용하면 함수의 타입을 명확히 정의할 수 있어 코드의 가독성과 유지보수성을 높일 수 있습니다. 이를 통해 보다 효율적인 개발 환경을 구축할 수 있습니다.

  *