msw-ai-tf/maplestory-worlds-creator-docs huggingface dataset:
유저 피드백 설정하기

# 학습 과정 소개

크리에이터는 유저 피드백 알림을 통해 주기적으로 본인이 제작한 월드의 긍정적인 피드백을 전달받을 수 있습니다. 이번 과정에서는 유저 피드백 알림 설정 방법을 알아보겠습니다.

# 유저 피드백 알림

## 알림 설정

유저 피드백 알림은 프로 모드, 디자인 모드에서 모두 설정할 수 있습니다.

[{"index":"프로 모드","0":"File - User Feedback Setting[png](1684311904185def4420d2f0e48c18facb47c8e4771b3)"},{"index":"디자인 모드","0":"메뉴 - 유저 피드백 설정[png](1684312020039e61a7feb1cba49ab9426f57c6e30016f)"}]

  
유저 피드백 알림 설정 창은 아래와 같이 구성되어 있습니다. [png](16843123885594cb3963439af4913a08f45b4814029c1) 

[{"항목":"플레이","설명":"플레이한 유저 및 인원수를 보여줍니다."},{"항목":"좋아요","설명":"\"좋아요\"를 누른 유저 및 인원수를 보여줍니다"},{"항목":"즐겨찾기","설명":"즐겨찾기를 누른 유저 및 인원수를 보여줍니다."},{"항목":"알림 발송 주기","설명":"알림 주기를 설정합니다.알림 발송 주기는 적용 버튼을 누른 시점부터 계산됩니다."}]

## 알림 출력

유저 피드백 알림은 PC 및 모바일 환경에서 모두 출력됩니다. 예를 들어 모바일에서 메이플스토리 월드 실행 중일 때 알림은 아래와 같이 출력됩니다. [gif](16843874714860fd65aedc9fb425ca6d030881d8b0d72)

> 더 알아보기 모바일에서 메이플스토리 월드 앱을 비활성화한 상태일 때 발생한 유저 피드백 알림은 백그라운드 푸시로 전달됩니다.
NameTagComponent

엔티티 이름표를 표시하고 관련 정보들을 설정합니다.

# Properties

[{"index":"boolean Bold (Sync)","0":"굵은 텍스트 사용 여부를 설정합니다."}]

[{"index":"Color FontColor (Sync)","0":"글자색을 변경합니다."}]

[{"index":"Vector2 FontOffset (Sync)","0":"이름표 내 글자 위치를 상하좌우로 조정합니다."}]

[{"index":"float FontSize (Sync)","0":"글자 크기를 설정합니다."}]

[{"index":"string Name (Sync)","0":"이름표에 표시할 이름을 설정합니다."}]

[{"index":"DataRef NameTagRUID","0":"이름표 형태를 변경 할 수 있습니다."}]

[{"index":"float OffsetY (Sync)","0":"이름표의 위치 Offset을 설정합니다."}]

##### 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":"현재 실행 환경이 서버인지 아닌지의 여부를 반환합니다."}]

# Examples

다음은 유저가 서로의 닉네임을 알 수 없도록 `NameTag`를 변경하는 예제입니다. 유저가 입장하면 UserId에 따라 정해진 단어와 색상으로 `NamgTag`를 설정합니다.
    
    
    @Component
    script UserRoleNametagSetter extends Component
        @ExecSpace("ServerOnly")
        @EventSender("Service", "UserService")
        handler HandleUserEnterEvent(UserEnterEvent event)
        -- Parameters
        local UserId = event.UserId
        --------------------------------------------------------
    
        local userEntity = _UserService:GetUserEntityByUserId(UserId)
        local nametag = userEntity.NameTagComponent
    
        if UserId == "000000" then
        	nametag.Name = "Admin"
        	nametag.FontColor = Color.magenta
        else
        	nametag.Name = "Player"
        	nametag.FontColor = Color.cyan
        end
        end
    end
    

# SeeAlso

  * UserEnterEvent
  * UserService
  * [엔티티에 이름표 붙이기](/docs?postId=29)
엔티티에 이름표 붙이기

# 학습 과정 소개

사물을 구분하는 효과적인 방법은 이름을 붙이는 것입니다. 이름표를 이용해 오브젝트와 NPC를 구분하거나, 유저를 구분할 수 있습니다. NameTagComponent 사용 방법과 활용 예시를 소개합니다.

# 이름표 붙이기

엔티티를 선택하고 NameTagComponent를 추가합니다. 프로퍼티 값을 변경해 원하는 이름표를 만듭니다. [png](1633505174925b7f918183b8d46d996e32b3e84b3c15d)

NameTagComponent 프로퍼티 구성은 다음과 같습니다.

[{"이름":"FontColor","설명":"글씨 색상을 변경합니다. 색상 변경은 스프라이트 색상 조정을 참고하세요."},{"이름":"FontSize","설명":"이름과 이름표 크기를 변경합니다. 초깃값은 1이며, 숫자가 커질수록 이름표 크기가 커집니다."},{"이름":"Name","설명":"이름표의 이름을 변경합니다. 초깃값은 Null이며, 원하는 이름으로 변경할 수 있습니다."},{"이름":"NameTagRUID","설명":"다양한 이름표 스프라이트를 이용할 수 있습니다.[png](1682065127446a1289f492f38401abbff1b9f791dbd13)"},{"이름":"OffsetY","설명":"이름표 위치를 정합니다. 원점 값은 0, 기준 축은 Y 축입니다. 값이 0이면 원점에 이름표가 달립니다. 음수를 입력하면 아래로, 양수면 위에 위치합니다."}]

# Name Tag 활용

오브젝트에 이름표를 붙여 NPC로 연출하는 예시입니다. 동일한 스프라이트의 몬스터나 NPC를 사용하고 싶다면, 이름표를 붙여 구분할 수 있습니다. 예를 들어, 고양이 오브젝트를 여러 개 배치하고, 그 사이에 고양이 이름표를 단 NPC 고양이를 대장으로 보이게 할 수 있습니다.

아래의 값을 입력해 연습할 수 있습니다.

  * FontColor: f5e38b
  * FontSize: 1
  * Name: 길을 잃은 고양이
  * NameTagRUID: ac88638649c3479bbb754e4b34bb3eac
  * OffsetY: 0



[jpg](16335077322494677e24b07a34e5ab5aa8943233fa37c)
table

# Functions

[{"index":"string concat(table table, string sep = \"\", integer i = 1, integer j = #table) (Static)","0":"테이블의 요소를 연결하여 문자열을 만듭니다. 각 요소 사이에 배치되는 구분 기호를 지정할 수 있고 범위를 지정할 수 있습니다."}]

[{"index":"void insert(table table, any value) (Static)","0":"table 끝에 값을 추가합니다"}]

[{"index":"void insert(table table, integer pos, any value) (Static)","0":"지정한 위치에 값을 추가합니다."}]

[{"index":"any remove(table table, integer pos = #table) (Static)","0":"테이블에서 값을 제거하고 제거된 요소의 값을 반환합니다. pos를 함께 전달하면 특정 위치의 값을 제거합니다."}]

[{"index":"void sort(table table, func comp) (Static)","0":"테이블을 정렬합니다. comp에 따라 테이블이 정렬됩니다."}]

[{"index":"void sort(table table) (Static)","0":"테이블을 정렬합니다."}]

[{"index":"table move(table a1, integer f, integer e, integer t, table a2 = a1) (Static)","0":"테이블 a1에서 테이블 a2로 요소를 이동시킵니다. a2[t], · · · = a1[f], · · · , a1[e]과 같은 다중 할당과 동일한 작업을 수행합니다. 요소 이동 후 a2를 반환합니다."}]

[{"index":"table pack(any... args) (Static)","0":"모든 인수가 숫자 키에 순서대로 저장되고 필드 \"n\"에 모든 인수 개수가 포함된 새로운 테이블을 반환합니다."}]

[{"index":"any... unpack(table table, integer i = 1, integer j = #table) (Static)","0":"t에서 각 요소를 반환합니다. i에 시작 인덱스, j에 마지막 인덱스를 지정할 수 있습니다."}]

[{"index":"table keys(table table) (Static)","0":"지정한 테이블의 키 목록을 반환합니다."}]

[{"index":"table values(table table) (Static)","0":"지정한 테이블의 값 목록을 반환합니다."}]

[{"index":"void clear(table table) (Static)","0":"지정한 테이블 내의 모든 키 값을 nil로 설정합니다."}]

[{"index":"void initialize(table t1, table t2) (Static)","0":"t1을 t2의 요소로 초기화합니다."}]

[{"index":"table create(integer size, any value = nil) (Static)","0":"입력한 size로 배열 테이블을 생성합니다. value로 테이블의 값을 초기화 할 수 있습니다."}]
JoystickComponent

모바일 환경에서 플레이어의 이동을 제어할 수 있는 가상의 조작키 기능을 지원해주는 Component입니다.

# Properties

[{"index":"AxisType Axis","0":"조작키가 움직일 수 있는 축 타입을 설정합니다."}]

[{"index":"KeyboardKey DownArrow","0":"조작키가 아래로 이동했을 때 입력되는 키입니다."}]

[{"index":"boolean DynamicStick","0":"플레이 시 조작키의 위치가 유저가 터치한 곳으로 이동합니다."}]

[{"index":"KeyboardKey LeftArrow","0":"조작키가 왼쪽으로 이동했을 때 입력되는 키입니다."}]

[{"index":"KeyboardKey RightArrow","0":"조작키가 오른쪽로 이동했을 때 입력되는 키입니다."}]

[{"index":"KeyboardKey UpArrow","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 Component:

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

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

# Examples

조이스틱을 아래로 당겼을 때 키보드 E키를 누른 것럼 동작하게 설정하는 예제입니다. 이동은 클라이언트 공간에서 동작하므로 키 또한 클라이언트에서 변경되어야 합니다.
    
    
    @Component
    script JoystickMappingTrigger extends Component
        @ExecSpace("ClientOnly")
        method void SetJoystickDownArrow()
        local joystick = _EntityService:GetEntityByPath("/ui/DefaultGroup/UIJoystick")
        joystick.JoystickComponent.DownArrow = KeyboardKey.E
        end
    
        @ExecSpace("ClientOnly")
        @EventSender("Self")
        handler HandleTriggerEnterEvent(TriggerEnterEvent event)
        -- Parameters
        local TriggerBodyEntity = event.TriggerBodyEntity
        --------------------------------------------------------
        self:SetJoystickDownArrow()
        end
    end
    

# SeeAlso

  * TriggerEnterEvent
  * EntityService
서버 전용 엔트리 설정하기

# 학습 과정 소개

크리에이터가 월드를 제작할 때 보안 상의 이슈로 게임을 플레이하는 유저들에게 공개하고 싶지 않은 DataSet이나 스크립트 내 함수가 존재할 수 있습니다. 이번 시간에는 DataSet이나 함수를 서버 전용으로 설정하는 방법에 대해 알아봅시다.

# 서버 전용 엔트리의 필요성

월드를 제작할 때, 예를 들어 쿠폰 코드나 게임상에서 활용되는 중요한 키, 대미지 공식이나 내부 로직 등의 정보는 서버에서만 처리되도록 하는 것이 안전합니다. 만약 이러한 중요 정보가 서버와 클라이언트 모두에 존재한다면 클라이언트에서도 중요 정보에 접근할 수 있으므로 보안에 취약할 수 있습니다. 이런 경우에는 중요한 DataSet이나 스크립트 내 함수의 구현부를 클라이언트로 전달되지 않도록 설정하여 보안 이슈를 해결해야 합니다.

# 서버 전용 DataSet 설정

DataSet의  Property에서 ServerOnly 체크 박스에 체크하면 해당 게임 월드를 플레이할 때 DataSet의 내용이 클라이언트로 전달되지 않도록 처리할 수 있습니다. [png](1661169318239863cf967cd4a46d3b1467ddcf4659ddc) ServerOnly로 설정한 DataSet에는 클라이언트가 접근할 수 없으므로 크리에이터는 이 점을 감안하여 스크립트를 작성해야 합니다. 해당 DataSet의 일부 데이터가 특정 타이밍에 필요한 경우, 실행 제어나 동기화 등으로 클라이언트에 전달해야 합니다.

# 함수의 실행 공간 설정

스크립트 내 함수의 실행 공간을 ServerOnly 또는 Server로 설정하면 해당 함수의 구현부는 클라이언트에 전달되지 않습니다.

  1. 함수 설정 버튼을 클릭한 뒤, Execution Space Setting 메뉴를 선택합니다. [png](1661216740609c9bbe61a337e4b62ba90e21ab21e65e2)
  2. 실행 공간을 Server 또는 ServerOnly로 설정합니다. [png](16612169670630c1a142634e6421b8c693d1f83c9e811) 이렇게 설정된 함수의 구현부는 클라이언트에 전달되지 않습니다. [png](166117015841552bb10e2fffd476b82770fe72c0a5787)
AlignmentType

앵커의 참조 포인트를 나타냅니다.

# Members

[{"이름":"Center","값":"0","설명":"기준 위치가 부모 중앙입니다."},{"이름":"Left","값":"1","설명":"기준 위치가 부모 왼쪽 중앙입니다."},{"이름":"Right","값":"2","설명":"기준 위치가 부모 오른쪽 중앙입니다."},{"이름":"TopCenter","값":"3","설명":"기준 위치가 부모 상단 중앙입니다."},{"이름":"TopLeft","값":"4","설명":"기준 위치가 부모 왼쪽 상단입니다."},{"이름":"TopRight","값":"5","설명":"기준 위치가 부모 오른쪽 상단입니다."},{"이름":"BottomCenter","값":"6","설명":"기준 위치가 부모 하단 중앙입니다."},{"이름":"BottomLeft","값":"7","설명":"기준 위치가 부모 왼쪽 하단입니다."},{"이름":"BottomRight","값":"8","설명":"기준 위치가 부모 오른쪽 하단입니다."},{"이름":"HorizontalTop","값":"9","설명":"기준 위치가 상단입니다. 가로 길이가 부모의 가로 길이와 함께 늘어납니다."},{"이름":"HorizontalCenter","값":"10","설명":"기준 위치가 중앙입니다. 가로 길이가 부모의 가로 길이와 함께 늘어납니다."},{"이름":"HorizontalBottom","값":"11","설명":"기준 위치가 하단입니다. 가로 길이가 부모의 가로 길이와 함께 늘어납니다."},{"이름":"VerticalLeft","값":"12","설명":"기준 위치가 왼쪽입니다. 세로 길이가 부모의 세로 길이와 함께 늘어납니다."},{"이름":"VerticalCenter","값":"13","설명":"기준 위치가 중앙입니다. 세로 길이가 부모의 세로 길이와 함께 늘어납니다."},{"이름":"VerticalRight","값":"14","설명":"기준 위치가 오른쪽입니다. 세로 길이가 부모의 세로 길이와 함께 늘어납니다."},{"이름":"StretchAll","값":"15","설명":"가로, 세로 길이가 부모의 크기와 동일하게 늘어납니다."}]

# Methods

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

[{"index":"AlignmentType CastFrom(string value) (Static)","0":"문자열을 해당 타입으로 변환합니다."}]
DataStorage 사용량 제한 활용하기 2

# 학습 과정 소개

DataStorage를 효율적으로 활용하지 않으면 사용량 제한에 도달해 데이터 저장, 조회에 실패해 데이터를 관리에 어려움을 겪을 수 있습니다. DataStorage의 사용량을 효과적으로 관리하는 방법에 대해 알아봅시다.

##### 가이드

  * 
  * 
  * 



# 데이터 저장하지 않기

저장하고자 하는 신규 데이터와 이전 데이터가 동일할 때, `SetAndWait`, `SetAsync` 와 같은 `Set` 함수들을 호출하면 Credit을 소모하게 됩니다. 값이 변경될 때만 DataStorage로 변경 요청을 보내면 Credit을 절약하는데 도움이 됩니다. 예를 들어 특정 유저가 여러 인스턴스에 동시에 접속해서 데이터를 변경하는 경우가 발생하지 않는다면, UserDataStorage에 이 방식을 활용할 수 있습니다.

> Tip 다른 월드 인스턴스에서 변경할 가능성이 없는 데이터에 대해서만 월드 인스턴스의 Lua Table에 데이터를 저장하기를 권장합니다.
    
    
    @Component
    script CachedProfileDataSetter extends Component
        property table cache = {}
    
        @ExecSpace("ServerOnly")
        method void TestAndSetData(string key, string value)
        local profileCode = self.Entity.PlayerComponent.ProfileCode
        if self.cache[profileCode] ~= nil and self.cache[profileCode][key] == value then
          return
        end
    
        local userDataStorage = _DataStorageService:GetUserDataStorage(profileCode)
        if userDataStorage == nil then
           return
        end
    
        local errorCode = userDataStorage:SetAndWait(key, value)
        if errorCode ~= 0 then
            log("ErrorCode : "..errorCode)
        else
            if self.cache[profileCode] == nil then
                self.cache[profileCode] = {}
            end
            self.cache[profileCode][key] = value
        end
        end
    end
    

> 더 알아보기 유저가 최초 접속했을 때 `GetAndWait`을 활용해 데이터를 미리 불러와서 `self.cache`에 넣어둘 수도 있습니다. 읽기와 쓰기 패턴에 따라 어떤 방식이 유리할지 크리에이터의 월드 특성에 맞게 선택해 사용해야 합니다. 만약, value 자체가 긴 문자열이라면 비교에도 많은 CPU 자원이 필요하므로 비교적 데이터가 작은 경우에 사용하는 것이 유리합니다. 모든 데이터에 캐싱을 적용하면 월드 인스턴스의 메모리가 부족할 수 있으니 읽기와 쓰기가 잦은 핫 데이터에서만 캐싱을 적용하기를 권장합니다.
Quaternion

회전을 표현하는 사원수(쿼터니언)입니다.

# Properties

[{"index":"float w","0":"쿼터니언의 w 원소입니다."}]

[{"index":"float x","0":"쿼터니언의 x 원소입니다."}]

[{"index":"float y","0":"쿼터니언의 y 원소입니다."}]

[{"index":"float z","0":"쿼터니언의 z 원소입니다."}]

# Constructors

[{"index":"Quaternion(float x, float y, float z, float w)","0":"지정한 값으로 Quaternion을 초기화합니다."}]

# Methods

[{"index":"float Angle(Quaternion b)","0":"두 쿼터니언 사이의 각도를 구합니다. 0부터 180 사이의 값을 반환합니다."}]

[{"index":"Quaternion Clone()","0":"복사본을 생성합니다."}]

[{"index":"float Dot(Quaternion b)","0":"두 쿼터니언의 내적을 구합니다."}]

[{"index":"Quaternion Normalize()","0":"크기가 1이 되도록 정규화한 Quaternion 객체를 생성해 반환합니다."}]

[{"index":"float Angle(Quaternion a, Quaternion b) (Static)","0":"두 쿼터니언 사이의 각도를 구합니다. 0부터 180 사이의 값을 반환합니다."}]

[{"index":"float Dot(Quaternion a, Quaternion b) (Static)","0":"두 쿼터니언의 내적을 구합니다."}]

[{"index":"Quaternion Euler(Vector3 euler) (Static)","0":"오일러 각을 쿼터니언으로 변환한 Quaternion 객체를 생성해 반환합니다."}]

[{"index":"Quaternion Normalize(Quaternion q) (Static)","0":"크기가 1이 되도록 정규화한 Quaternion 객체를 생성해 반환합니다."}]

# Operators

[{"index":"boolean Equality(Quaternion left, Quaternion right) (Static)","0":"두 쿼터니언이 같은 회전을 나타내는지 확인합니다. 같은 회전을 나타내면 true, 그렇지 않으면 false를 반환합니다. 정확한 비교를 위해서는 두 쿼터니언이 정규화된 상태여야 합니다."}]

[{"index":"boolean Inequality(Quaternion left, Quaternion right) (Static)","0":"두 쿼터니언이 다른 회전을 나타내는지 확인합니다. 같은 회전을 나타내면 false, 그렇지 않으면 true를 반환합니다. 정확한 비교를 위해서는 두 쿼터니언이 정규화된 상태여야 합니다."}]

[{"index":"Quaternion Multiply(Quaternion left, Quaternion right) (Static)","0":"두 쿼터니언을 곱한 Quaternion 객체를 생성해 반환합니다."}]

[{"index":"Vector3 Multiply(Quaternion left, Vector3 right) (Static)","0":"벡터를 회전시킨 Vector3 객체를 생성해 반환합니다."}]
SpriteTypeOverlayLightInfo

맵에 스폰할 Sprite 타입의 광원 정보입니다.

# Properties

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

[{"index":"Entity Instigator","0":"광원이 생성될 맵에 소속된 엔티티입니다."}]

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

[{"index":"float Lifetime","0":"광원이 표시될 시간입니다. 적혀있는 시간을 경과하면 생성되었던 광원이 자동으로 사라집니다. 단, 0 이하의 값을 입력할 경우에는 아무리 시간이 지나도 사라지지 않습니다."}]

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

[{"index":"boolean Loop","0":"스프라이트의 반복 재생 여부입니다. 스프라이트가 단일 프레임인 경우 false면 즉시 사라집니다."}]

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

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

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

[{"index":"Vector3 WorldPosition","0":"광원이 위치할 월드 공간 상의 좌표입니다."}]

[{"index":"Vector3 WorldScale","0":"광원에 적용될 월드 공간 상의 스케일입니다."}]

[{"index":"float WorldZRotation","0":"광원에 적용될 월드 공간 상의 Z축 기준 회전값입니다."}]

# Constructors

[{"index":"SpriteTypeOverlayLightInfo(Entity instigator)","0":"지정한 값으로 SpriteTypeOverlayLightInfo를 초기화합니다."}]

[{"index":"SpriteTypeOverlayLightInfo(Entity instigator, float lifetime, Vector3 worldPosition, float worldZRotation, Vector3 worldScale, Color color, float intensity, OverlayLightOverlapOperation overlapOperation, int32 lightOrder, string spriteRUID, float playRate, boolean loop)","0":"지정한 값으로 SpriteTypeOverlayLightInfo를 초기화합니다."}]
MaterialService

머티리얼 프로퍼티를 제어하는 기능을 제공합니다.

# Methods

[{"index":"void ChangeMaterialProperty(string entryId, Dictionary changeProperty) (ClientOnly)","0":"entryId에 해당하는 머티리얼의 프로퍼티를 변경합니다. changeProperty의 key는 프로퍼티 이름, value는 프로퍼티 값입니다."}]

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

플레이어를 따라다니는 조명 효과를 구현하는 예제입니다. `TestMaterial` 머티리얼은 vigette 셰이더를 사용합니다. `TestMaterial`의 `CenterPos` 프로퍼티를 변경합니다. 활성화된 `CameraComponent`가 `TestMaterial`을 사용해야 예제가 정상 동작합니다.
    
    
    @Component
    script PlayerScreenMaterialUpdater extends Component
        property string materialId = ""
    
        @ExecSpace("ClientOnly")
        method void OnBeginPlay()
        self.materialId = _EntryService:GetMaterialIdByName("TestMaterial")
        end
    
        @ExecSpace("ClientOnly")
        method void OnUpdate(number delta)
        local playerWorldPosition = _UserService.LocalPlayer.TransformComponent.WorldPosition
    
        local targetScreenPos = _UILogic:WorldToScreenPosition(Vector2(playerWorldPosition.x, playerWorldPosition.y))
        targetScreenPos.x = targetScreenPos.x / _UILogic.ScreenWidth
        targetScreenPos.y = targetScreenPos.y / _UILogic.ScreenHeight
    
        local options = {["CenterPos"] = targetScreenPos}
    
        _MaterialService:ChangeMaterialProperty(self.materialId, options)
        end
    end
    

# SeeAlso

  * UILogic
  * EntryService
  * UserService
  * [머티리얼 응용하기](/docs?postId=950)
  * [머티리얼 활용하기](/docs?postId=828)
Blackboard

AI 행동 트리에서 사용하는 데이터 저장소입니다. 키-값 쌍으로 데이터를 관리하며 행동 트리 노드 간 데이터를 공유합니다.

# Methods

[{"index":"boolean GetBool(string key)","0":"지정한 키에 저장된 boolean 값을 조회합니다."}]

[{"index":"Color GetColor(string key)","0":"지정한 키에 저장된 Color 값을 조회합니다."}]

[{"index":"Component GetComponent(string key)","0":"지정한 키에 저장된 Component를 조회합니다."}]

[{"index":"ComponentRef GetComponentRef(string key)","0":"지정한 키에 저장된 ComponentRef를 조회합니다."}]

[{"index":"Entity GetEntity(string key)","0":"지정한 키에 저장된 엔티티를 직접 조회합니다."}]

[{"index":"EntityRef GetEntityRef(string key)","0":"지정한 키에 저장된 EntityRef를 조회합니다."}]

[{"index":"integer GetInt(string key)","0":"지정한 키에 저장된 정수형 값을 조회합니다."}]

[{"index":"number GetNumber(string key)","0":"지정한 키에 저장된 실수형 값을 조회합니다."}]

[{"index":"string GetString(string key)","0":"지정한 키에 저장된 String 값을 조회합니다."}]

[{"index":"Vector2 GetVector2(string key)","0":"지정한 키에 저장된 Vector2 값을 조회합니다."}]

[{"index":"Vector3 GetVector3(string key)","0":"지정한 키에 저장된 Vector3 값을 조회합니다."}]

[{"index":"Vector4 GetVector4(string key)","0":"지정한 키에 저장된 Vector4 값을 조회합니다."}]

[{"index":"void SetBool(string key, boolean value)","0":"지정한 키에 boolean 값을 저장합니다."}]

[{"index":"void SetColor(string key, Color value)","0":"지정한 키에 Color 값을 저장합니다."}]

[{"index":"void SetComponent(string key, Component value)","0":"지정한 키에 Component 값을 저장합니다."}]

[{"index":"void SetComponentRef(string key, ComponentRef value)","0":"지정한 키에 ComponentRef 값을 저장합니다."}]

[{"index":"void SetEntity(string key, Entity value)","0":"지정한 키에 Entity 값을 저장합니다."}]

[{"index":"void SetEntityRef(string key, EntityRef value)","0":"지정한 키에 EntityRef 값을 저장합니다."}]

[{"index":"void SetInt(string key, integer value)","0":"지정한 키에 정수 값을 저장합니다."}]

[{"index":"void SetNumber(string key, number value)","0":"지정한 키에 실수 값을 저장합니다."}]

[{"index":"void SetString(string key, string value)","0":"지정한 키에 String 값을 저장합니다."}]

[{"index":"void SetVector2(string key, Vector2 value)","0":"지정한 키에 Vector2 값을 저장합니다."}]

[{"index":"void SetVector3(string key, Vector3 value)","0":"지정한 키에 Vector3 값을 저장합니다."}]

[{"index":"void SetVector4(string key, Vector4 value)","0":"지정한 키에 Vector4 값을 저장합니다."}]
AttachedSpriteTypeOverlayLightInfo

엔티티의 자식으로 스폰될 Sprite 타입의 광원 정보입니다.

# Properties

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

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

[{"index":"float Lifetime","0":"광원이 표시될 시간입니다. 적혀있는 시간을 경과하면 생성되었던 광원이 자동으로 사라집니다. 단, 0 이하의 값을 입력할 경우에는 아무리 시간이 지나도 사라지지 않습니다."}]

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

[{"index":"Vector3 LocalPosition","0":"광원이 위치할 부모 엔티티 공간 상의 좌표입니다."}]

[{"index":"Vector3 LocalScale","0":"광원에 적용될 부모 엔티티 공간 상의 스케일입니다."}]

[{"index":"float LocalZRotation","0":"광원에 적용될 부모 엔티티 공간 상의 Z축 기준 회전값입니다."}]

[{"index":"boolean Loop","0":"스프라이트의 반복 재생 여부입니다. 스프라이트가 단일 프레임인 경우 false면 즉시 사라집니다."}]

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

[{"index":"Entity ParentEntity","0":"생성된 광원이 추가될 엔티티입니다."}]

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

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

# Constructors

[{"index":"AttachedSpriteTypeOverlayLightInfo(Entity parentEntity)","0":"지정한 값으로 AttachedSpriteTypeOverlayLightInfo를 초기화합니다."}]

[{"index":"AttachedSpriteTypeOverlayLightInfo(Entity parentEntity, float lifetime, Vector3 localPosition, float localZRotation, Vector3 localScale, Color color, float intensity, OverlayLightOverlapOperation overlapOperation, int32 lightOrder, string spriteRUID, float playRate, boolean loop)","0":"지정한 값으로 AttachedSpriteTypeOverlayLightInfo를 초기화합니다."}]
PolygonRendererComponent

다각형을 그리는 기능입니다.

# Properties

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

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

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

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

[{"index":"SyncList Points (Sync)","0":"다각형을 구성하는 꼭짓점들의 집합입니다."}]

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

[{"index":"boolean UseCustomUVs (Sync)","0":"true라면 UVs에 설정한 UV 값이 도형에 적용됩니다."}]

[{"index":"SyncList UVs (Sync)","0":"꼭짓점의 UV를 설정합니다. 반드시 Points와 길이가 같아야 합니다."}]

##### 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":"boolean IsDrawable()","0":"Points 프로퍼티에 저장된 꼭짓점들을 이어 다각형이 그려지는지 확인합니다. 교차하는 변이 있으면 다각형이 그려지지 않습니다."}]

##### inherited from Component:

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

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

# Events

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

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

# SeeAlso

  * [다각형 그리기](/docs?postId=1080)