[task] | code [pass] | ⏳ 미판정 [title] | Maple GYM 만들기 Ⅱ [question] | PlayerStats 컴포넌트에 정의된 테이블 정보를 기반으로 현재 금액을 확인하고, UIManager 컴포넌트의 SetShopInfo() 메서드에서 SkillLevelText, DnaLevelText, SkillUpButtonText, DnaUpButtonText 프로퍼티의 TextComponent 를 활용해 금액 및 색상 정보를 표시하도록 하는 스크립트를 작성해줘 [answer] | 참고 문서에는 `SetShopInfo()` 메서드의 구체적인 구현 코드(테이블 접근 방식, 색상 변경 로직 등)가 제공되지 않았습니다. 문서 3번 항목은 "아래와 같이 작성합니다"라고 언급하고 있지만, 실제 코드 블록은 생략되어 있습니다. 따라서 문서에 명시된 정보(프로퍼티 정의, `OnBeginPlay`에서의 초기화)를 기반으로, `PlayerStats` 컴포넌트의 테이블 정보를 활용하는 **추정된 구조**만 제시할 수 있으며, 문서에 없는 구체적인 API(예: `PlayerStats` 테이블의 정확한 키 이름, 색상 설정 AP [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 상점에 알맞는 정보가 표시될 수 있도록 만들어봅시다. 1. **UIManager** 컴포넌트에 새로운 프로퍼티를 4개를 추가합니다. 이 프로퍼티들은 **TextComponent** 정보를 가집니다. ```lua Property: [None] Component SkillLevelText = nil [None] Component DnaLevelText = nil [None] Component SkillUpButtonText = nil [None] Componen
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | 컴포넌트 스크립트에서 다른 엔티티의 컴포넌트에 직접 접근하려고 해도 안 되는데, 엔티티와 컴포넌트 구조상 접근이 제한되는 이유가 무엇인가요? [answer] | 메이플스토리 월드의 엔티티-컴포넌트 구조에서 다른 엔티티의 컴포넌트에 직접 접근이 제한되는 이유는, 각 컴포넌트가 특정 엔티티와 1:1로 결합되어 있으며 엔티티 간 연결이 명시적인 참조 경로를 통해서만 이루어지기 때문입니다. 제공된 문서의 구조를 살펴보면 다음과 같은 원리가 적용됩니다. 1. **엔티티 중심의 참조 구조**: 컴포넌트는 독립적으로 존재하지 않고 항상 특정 엔티티를 포함하는 주체입니다. 따라서 다른 엔티티의 컴포넌트를 사용하려면 먼저 해당 **엔티티 객체**를 참조해야 합니다. 2. **명시적 경로를 통한 접근** [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 엔티티와 컴포넌트 구조를 간략하게 이해하고, 스크립트를 통해 엔티티와 컴포넌트에 접근하는 방법을 알아봅니다. # 엔티티와 컴포넌트 구조 먼저 엔티티와 컴포넌트의 구조를 알아보겠습니다. 기본적으로 엔티티는 각기 다른 컴포넌트들로 구성되어 있고, 각각의 엔티티는 상위, 하위 관계로 연결되어 있습니다. 이 연결 구조를 이용하면 특정 컴포넌트에서 다른 엔티티나 컴포넌트로 접근할 수 있습니다. 아래 이미지는 엔티티 간의 상-하위 구조와 각 엔티티를 구성하는 컴포넌트를 도식화한 것입니다. 이후 이 구조를 바탕으로 설명
[task] | code [pass] | ⏳ 미판정 [title] | MSW 기본 이벤트 함수 [question] | `OnInitialize` 함수에서 초기값을 설정하고, `OnBeginPlay` 함수에서 다른 엔티티와 컴포넌트의 참조가 보장된 시점에 해당 참조 객체를 활용하여 초기값을 검증하거나 출력하는 로직을 구현하는 스크립트를 작성해줘 [answer] | `OnInitialize`는 다른 엔티티나 컴포넌트의 참조가 보장되지 않기 때문에, 이 시점에는 자기 자신(`self`)의 프로퍼티 초기값 설정만 수행해야 합니다. 반면 `OnBeginPlay`는 다른 엔티티와 컴포넌트가 모두 생성된 후에 호출되므로, 여기서 다른 객체를 참조하여 `OnInitialize`에서 설정된 값을 검증하거나 출력하는 로직을 실행해야 합니다. 아래는 이 구조를 따르는 두 개의 컴포넌트(`ComponentA`, `ComponentB`) 예시입니다. 1. **ComponentA**: `OnInitialize` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 본격적으로 로직이 시작되는 시점(`OnInitialize` 함수 호출 이후, `OnUpdate` 호출 직전)에 1회 호출되는 함수입니다. 엔티티의 `OnBeginPlay` 함수는 다른 엔티티와 컴포넌트가 모두 생성된 뒤에 호출됩니다. 동적으로 생성된 엔티티도 해당 엔티티의 컴포넌트가 모두 생성된 후에 `OnBeginPlay` 함수가 호출됩니다. 그러므로 `OnInitialize` 함수와는 달리 `OnBeginPlay` 함수는 다른 엔티티 및 컴포넌트의 참조가 보장됩니다. ```lua void OnBeginPlay() { lo
[task] | two_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | `Entity.Children`을 반복문으로 검색하는 방식과 `GetChildByName()`을 사용하는 방식 중 어떤 것이 더 효율적이며, 그 이유는 무엇인가요? [answer] | `GetChildByName()`을 사용하는 방식이 더 효율적입니다. `Entity.Children`은 모든 하위 엔티티를 테이블 형태로 반환하므로, 원하는 특정 엔티티를 찾으려면 반복문(for)을 돌리며 각 엔티티의 이름을 비교해야 합니다. 이는 하위 엔티티 수가 많을수록 불필요한 비교 연산이 증가하여 비효율적입니다. 반면, `GetChildByName()`은 찾고자 하는 엔티티의 이름만 매개 변수로 전달하면 해당 엔티티를 직접 반환합니다. 따라서 전체 목록을 반복하지 않고도 즉시 목표 엔티티를 가져올 수 있어 코드 작성과 실 [followup] | 특정 이름의 엔티티를 찾기 위해 `Entity.Children` 배열을 직접 순회하는 대신 `GetChildByName()`을 사용하는 것이 왜 더 간단한지 원문 내용을 바탕으로 설명해 주세요. [followup_answer] | `Entity.Children`을 사용할 경우, 모든 하위 엔티티를 받아온 이후 반복문을 통해 원하는 엔티티를 하나씩 찾아야 합니다. 반면 `GetChildByName()`을 사용하면 찾고자 하는 엔티티의 이름만 알고 있으면 바로 해당 엔티티를 가져올 수 있습니다. 따라서 전체 목록을 순회하는 과정이 생략되므로, 특정 이름의 엔티티를 참조하는 작업이 훨씬 간단해집니다. [scores] | [judge_reason] | [source_doc] | Entity.Children처럼 하위 엔티티를 참조하는 또 다른 방법을 알아봅시다. Entity:GetChildByName()은 하위 엔티티 중 매개 변수로 넘겨진 값과 같은 이름의 엔티티를 반환하는 함수입니다. 따라서 Entity.Children처럼 모든 하위 엔티티를 받아온 후 반복문을 통해 원하는 엔티티를 찾을 필요가 없습니다. 찾고자 하는 엔티티의 이름만 알고 있다면 훨씬 간단하게 하위 엔티티를 가져올 수 있습니다. * **매개 변수** * GetChildByName 함수는 두 개의 매개 변수를 받을 수 있습니다.
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | 스크립트에서 특정 엔티티의 고유 ID를 확인하기 위해 편집기에서 수행해야 하는 절차와, 코드 내에서 ID를 직접 추출하는 방법은 무엇인가요? [answer] | 특정 엔티티의 고유 ID를 확인하는 방법은 편집기 조작과 코드 작성 두 가지로 나눌 수 있습니다. **1. 편집기에서 ID 확인 절차** 에디터에서 엔티티를 선택한 후 콘텍스트 메뉴에서 **Copy Entity ID**를 클릭하면 해당 엔티티의 ID가 클립보드에 복사됩니다. 이렇게 복사한 ID를 스크립트의 `_EntityService:GetEntity` 매개변수로 사용할 수 있습니다. **2. 코드 내에서 ID 추출 방법** 스크립트 실행 중 특정 엔티티의 ID를 직접 얻고자 할 경우, 해당 엔티티 객체의 `ID` 프로퍼티를 접 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 매개 변수로 엔티티 ID를 넘겨주면 해당 ID의 엔티티를 반환하는 함수입니다. 엔티티의 계층 구조가 동적으로 변경되거나 엔티티의 이름이 바뀌면서 경로가 변경될 여지가 있으면, 유니크한 ID를 이용해 엔티티를 받아올 수 있는 GetEntity를 사용하는 것이 효율적입니다. * **매개 변수** | Parameter | Type | Description | | --- | --- | --- | | ID | string | 얻고자 하는 엔티티 ID를 넣어줍니다. 엔티티의 콘텍스트 메뉴에서 **Copy Entity I
[task] | two_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | `GetFirstChildComponentByTypeName` 메서드의 `recursive` 매개변수가 `true`와 `false`일 때 검색 범위가 어떻게 다른지 설명해 주세요 [answer] | `GetFirstChildComponentByTypeName` 메서드의 `recursive` 매개변수는 하위 엔티티를 얼마나 깊이 탐색할지를 결정합니다. * **`false` (기본값):** 현재 엔티티의 **직접적인 하위 엔티티들**만 순회합니다. 하위 엔티티 안에 더 들어 있는 하위 엔티티(하위의 하위)까지 찾지 않습니다. 매개변수를 생략할 경우에도 `false`로 처리됩니다. * **`true`:** 현재 엔티티의 하위 엔티티뿐만 아니라, **하위 엔티티 안에 더 들어 있는 하위 엔티티들까지 포함**해 순회합니다. 즉 [followup] | `recursive`가 기본값인 경우와 `true`일 때의 차이점을 코드로 비교한 예시를 보여주세요 [followup_answer] | `recursive` 매개변수를 생략한 경우와 `true`를 명시적으로 전달한 경우의 차이를 비교한 코드 예시는 다음과 같습니다. `recursive`를 생략하면 기본값인 `false`로 처리되어 현재 엔티티의 직접적인 하위 엔티티만 검색됩니다. 반면 `true`를 전달하면 하위 엔티티 안에 더 포함된 하위 엔티티까지 모두 검색합니다. ```lua Method: void CompareRecursiveSearch() { local map01Entity = self.Entity.CurrentMap -- recursi [scores] | [judge_reason] | [source_doc] | > **Component Entity:GetFirstChildComponentByTypeName(string typename, bool recursive)** > 하위 엔티티들을 순회하면서 하위 엔티티에 typename과 일치하는 컴포넌트가 있으면, 해당 컴포넌트를 반환합니다. > * **매개 변수** > > | Parameter | Type | Description | > | --- | --- | --- | > | typename | string | 찾고자 하는 컴포넌트의 이름을 입력합니다. | >
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | _EntityService:GetEntityByPath("/maps/map01/obj")로 특정 경로에 있는 엔티티를 참조하고, 해당 엔티티의 Name을 log()로 출력하는 스크립트를 작성해줘 [answer] | `_EntityService:GetEntityByPath()` 함수를 사용하여 지정한 경로에 있는 엔티티를 가져오고, 그 엔티티의 `Name` 속성을 `log()` 함수로 출력하는 스크립트입니다. ```lua Method: [server only] void OnBeginPlay() { local targetEntity = _EntityService:GetEntityByPath("/maps/map01/obj") if targetEntity then log(targetEntity.Name) [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | Entity.Children처럼 하위 엔티티를 참조하는 또 다른 방법을 알아봅시다. Entity:GetChildByName()은 하위 엔티티 중 매개 변수로 넘겨진 값과 같은 이름의 엔티티를 반환하는 함수입니다. 따라서 Entity.Children처럼 모든 하위 엔티티를 받아온 후 반복문을 통해 원하는 엔티티를 찾을 필요가 없습니다. 찾고자 하는 엔티티의 이름만 알고 있다면 훨씬 간단하게 하위 엔티티를 가져올 수 있습니다. * **매개 변수** * GetChildByName 함수는 두 개의 매개 변수를 받을 수 있습니다.
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | 엔티티 이름이나 경로가 변경될 수 있는 상황에서는 GetEntityByPath 대신 GetEntity를 사용하는 것이 효율적인 이유는 무엇인가요? [answer] | 엔티티의 계층 구조가 동적으로 변경되거나 엔티티의 이름이 바뀌어 경로가 달라질 수 있는 상황에서는 `GetEntity`를 사용하는 것이 효율적입니다. `GetEntityByPath`는 엔티티의 경로를 기반으로 참조하므로, 엔티티 이름이나 위치가 바뀌면 기존 경로가 더 이상 유효하지 않아 참조에 실패할 수 있습니다. 반면 `GetEntity`는 엔티티마다 고유하게 부여되는 ID를 매개 변수로 받아 해당 ID의 엔티티를 반환합니다. ID는 엔티티의 이름이나 계층 구조와 무관하게 고정되어 있으므로, 이러한 환경 변화에도 안정적으로 엔티 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 매개 변수로 엔티티 ID를 넘겨주면 해당 ID의 엔티티를 반환하는 함수입니다. 엔티티의 계층 구조가 동적으로 변경되거나 엔티티의 이름이 바뀌면서 경로가 변경될 여지가 있으면, 유니크한 ID를 이용해 엔티티를 받아올 수 있는 GetEntity를 사용하는 것이 효율적입니다. * **매개 변수** | Parameter | Type | Description | | --- | --- | --- | | ID | string | 얻고자 하는 엔티티 ID를 넣어줍니다. 엔티티의 콘텍스트 메뉴에서 **Copy Entity I
[task] | code [pass] | ⏳ 미판정 [title] | MSW 기본 이벤트 함수 [question] | `OnBeginPlay`에서 `_TimerService`를 사용하여 5초 후 `OnMapLeave`에서 감소한 `TransformComponent.Scale`을 초기값으로 복원하는 로직을 추가하는 스크립트를 작성해줘 [answer] | `OnBeginPlay`는 엔티티가 월드에 진입하여 생성될 때 단 한 번만 호출되는 함수이며, `OnMapLeave`는 엔티티가 맵에서 퇴장할 때마다 호출되는 함수입니다. 질문하신 요구사항인 "5초 후 `OnMapLeave`에서 감소한 Scale을 초기값으로 복원"하는 로직은 `OnBeginPlay`와 `OnMapLeave`의 실행 시점과 역할이 상이하여 단일 스크립트 내에서 직관적으로 구현하기 어렵습니다. `OnBeginPlay`는 초기화 시점(1회)이고, `OnMapLeave`는 맵 퇴장 시점(반복)이기 때문입니다. 또한, ` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 예를 들어, 내 플레이어 엔티티가 **map01에서 map02로 이동**했다고 가정합니다. 이때 내 플레이어 엔티티의 스크립트 컴포넌트에 `OnMapEnter` 함수가 있었다면, map02로 이동할 때 내 플레이어 엔티티의 `OnMapEnter` 함수가 호출됩니다. 그런데 내 플레이어뿐만 아니라 다른 플레이어의 `OnMapEnter` 함수도 호출되는 것을 볼 수 있습니다. 클라이언트 상에서 보자면, 현재 내가 존재하는 맵에 다른 플레이어 엔티티가 생성된 것과 마찬가지이기 때문입니다. 하지만 서버상에서는 내 플레이어 엔티티가 map
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | HandleUserEnterEventType 이벤트 핸들러에서 event.UserId를 이용해 특정 플레이어 엔티티를 가져오는 정확한 함수 호출 문법은 어떻게 되나요? [answer] | `HandleUserEnterEventType` 이벤트 핸들러에서 `event.UserId`를 이용해 특정 플레이어 엔티티를 가져오기 위해서는 `_UserService:GetUserEntityByUserID()` 함수를 사용합니다. 정확한 함수 호출 문법은 다음과 같습니다. ```lua local playerEntity = _UserService:GetUserEntityByUserID(event.UserId) ``` 이 함수는 매개변수로 전달된 `UserId`에 해당하는 플레이어 엔티티가 존재하면 해당 `Entity`를 반환하 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 게임에 접속해 있는 모든 플레이어 엔티티를 딕셔너리 형태로 받아오는 읽기 전용 프로퍼티입니다. * Key: string UserId * Value: Entity PlayerEntity key 값인 UserId는 유저가 메이플스토리 월드에 가입 시 생성한 Id로 UserId와 플레이어 엔티티의 이름을 동일하게 사용하고 있습니다. ```lua void PrintUserEntitiesName() { log(_UserService:GetUserCount()) local playerEntitiesDic = _UserServi
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | Entity:GetChildByName("Missing")을 호출하여 존재하지 않는 엔티티를 참조했을 때 nil이 반환되는 것을 확인하고, nil이 아닌 경우에만 실행되도록 if 문을 사용하여 "Found"를 log()로 출력하는 스크립트를 작성해줘 [answer] | 존재하지 않는 엔티티를 `Entity:GetChildByName()`으로 조회하면 `nil`이 반환됩니다. 이 `nil` 값을 확인하여, 엔티티가 실제로 존재하는 경우에만 "Found"를 출력하는 스크립트는 다음과 같습니다. ```lua void OnBeginPlay() { local targetEntity = self.Entity:GetChildByName("Missing") if targetEntity ~= nil then log("Found") end } ``` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | Entity.Children처럼 하위 엔티티를 참조하는 또 다른 방법을 알아봅시다. Entity:GetChildByName()은 하위 엔티티 중 매개 변수로 넘겨진 값과 같은 이름의 엔티티를 반환하는 함수입니다. 따라서 Entity.Children처럼 모든 하위 엔티티를 받아온 후 반복문을 통해 원하는 엔티티를 찾을 필요가 없습니다. 찾고자 하는 엔티티의 이름만 알고 있다면 훨씬 간단하게 하위 엔티티를 가져올 수 있습니다. * **매개 변수** * GetChildByName 함수는 두 개의 매개 변수를 받을 수 있습니다.
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | world 엔티티는 맵과 마찬가지로 게임 내에 하나만 존재하므로, 어떤 엔티티에서든 CurrentWorld를 통해 참조할 수 있다는 설명이 올바른가요? [answer] | 네, 그 설명은 올바릅니다. `world` 엔티티는 게임 내에서 단 하나만 존재하는 고유한 엔티티입니다. 따라서 특정 엔티티의 계층 구조나 경로를 직접 추적하지 않고도, 해당 엔티티에 포함된 `CurrentWorld` 프로퍼티를 통해 `world` 엔티티를 쉽게 참조할 수 있습니다. 다음은 특정 엔티티(예: `EntityB`)에 있는 스크립트에서 `CurrentWorld`를 사용하여 `world` 엔티티를 참조하는 예시입니다. ```lua Method: [server only] void OnBeginPlay() { loc [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 매개 변수로 엔티티 ID를 넘겨주면 해당 ID의 엔티티를 반환하는 함수입니다. 엔티티의 계층 구조가 동적으로 변경되거나 엔티티의 이름이 바뀌면서 경로가 변경될 여지가 있으면, 유니크한 ID를 이용해 엔티티를 받아올 수 있는 GetEntity를 사용하는 것이 효율적입니다. * **매개 변수** | Parameter | Type | Description | | --- | --- | --- | | ID | string | 얻고자 하는 엔티티 ID를 넣어줍니다. 엔티티의 콘텍스트 메뉴에서 **Copy Entity I
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | _UserService.UserEntities 딕셔너리의 key와 value 각각이 무엇을 의미하며, 이 데이터를 어떻게 순회해야 하는지 궁금합니다. [answer] | `_UserService.UserEntities` 딕셔너리의 구조와 순회 방법은 다음과 같습니다. * **Key**: `string` 타입의 `UserId`입니다. 이는 유저가 메이플스토리 월드에 가입할 때 생성된 고유 식별자이며, 현재는 플레이어 엔티티의 이름과 동일한 값으로 사용됩니다. * **Value**: `Entity` 타입의 `PlayerEntity`입니다. 이는 게임에 접속해 있는 해당 유저의 플레이어 엔티티 객체입니다. 이 딕셔너리는 읽기 전용 프로퍼티로, 모든 플레이어 엔티티를 순회하기 위해 Lua의 `p [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 게임에 접속해 있는 모든 플레이어 엔티티를 딕셔너리 형태로 받아오는 읽기 전용 프로퍼티입니다. * Key: string UserId * Value: Entity PlayerEntity key 값인 UserId는 유저가 메이플스토리 월드에 가입 시 생성한 Id로 UserId와 플레이어 엔티티의 이름을 동일하게 사용하고 있습니다. ```lua void PrintUserEntitiesName() { log(_UserService:GetUserCount()) local playerEntitiesDic = _UserServi
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | self.Entity.CurrentMap 프로퍼티를 사용하면 어떤 이점이 있으며, 이 값을 가져오기 전 반드시 확인해야 하는 유효성 검증 방법은 무엇인가요? [answer] | `self.Entity.CurrentMap` 프로퍼티를 사용하면 엔티티가 현재 속해 있는 맵 엔티티를 직접적으로 참조할 수 있는 이점이 있습니다. 엔티티의 `Parent`를 순차적으로 추적하여 맵 엔티티를 찾아야 하는 복잡한 과정을 생략하고, 한 줄의 코드로 바로 맵 정보를 가져올 수 있어 스크립트 작성과 유지보수가 효율적입니다. 이 값을 가져오기 전 반드시 확인해야 하는 유효성 검증 방법은 `isvalid()` 함수를 사용하는 것입니다. `CurrentMap`은 특정 엔티티가 존재하지 않거나 유효하지 않은 상태일 때 잘못된 참조 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 매개 변수로 엔티티 ID를 넘겨주면 해당 ID의 엔티티를 반환하는 함수입니다. 엔티티의 계층 구조가 동적으로 변경되거나 엔티티의 이름이 바뀌면서 경로가 변경될 여지가 있으면, 유니크한 ID를 이용해 엔티티를 받아올 수 있는 GetEntity를 사용하는 것이 효율적입니다. * **매개 변수** | Parameter | Type | Description | | --- | --- | --- | | ID | string | 얻고자 하는 엔티티 ID를 넣어줍니다. 엔티티의 콘텍스트 메뉴에서 **Copy Entity I
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | Entity:GetChildByName()을 사용하여 OnBeginPlay()에서 바로 아래 단계의 하위 엔티티 "Target"을 찾고, 찾지 못하면 nil을 반환하는 것을 확인하기 위해 log()로 이름을 출력하는 스크립트를 작성해줘 [answer] | `Entity:GetChildByName()` 함수는 매개변수로 넘긴 이름과 동일한 하위 엔티티를 반환합니다. 두 번째 매개변수인 `recursive`를 생략하면 기본값인 `false`가 적용되어, 바로 아래 단계의 엔티티만 검색합니다. 만약 해당 이름의 엔티티가 존재하지 않으면 `nil`을 반환하므로, 이를 확인하기 위해 `log()`로 출력하면 됩니다. 요청하신 조건(OnBeginPlay에서 "Target" 검색, nil 확인)을 만족하는 mLua 스크립트는 다음과 같습니다. ```lua Method: [server only [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | Entity.Children처럼 하위 엔티티를 참조하는 또 다른 방법을 알아봅시다. Entity:GetChildByName()은 하위 엔티티 중 매개 변수로 넘겨진 값과 같은 이름의 엔티티를 반환하는 함수입니다. 따라서 Entity.Children처럼 모든 하위 엔티티를 받아온 후 반복문을 통해 원하는 엔티티를 찾을 필요가 없습니다. 찾고자 하는 엔티티의 이름만 알고 있다면 훨씬 간단하게 하위 엔티티를 가져올 수 있습니다. * **매개 변수** * GetChildByName 함수는 두 개의 매개 변수를 받을 수 있습니다.
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | 서버 스크립트에서 _UserService.LocalPlayer를 호출했는데 nil이 반환되는 이유는 무엇인가요? [answer] | `_UserService.LocalPlayer`는 **클라이언트 공간**에서만 사용 가능한 읽기 전용 프로퍼티입니다. 서버에서는 "내 플레이어"라는 개념이 존재하지 않기 때문에, 서버 스크립트에서 이 프로퍼티를 참조하면 `nil`을 반환합니다. 서버에서 특정 플레이어를 참조해야 한다면 `_UserService.LocalPlayer` 대신 아래 방법을 사용해야 합니다. 1. **`_UserService.UserEntities`**: 접속한 모든 플레이어 엔티티를 딕셔너리 형태로 반환합니다. 2. **`_UserService:G [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 게임에 접속해 있는 모든 플레이어 엔티티를 딕셔너리 형태로 받아오는 읽기 전용 프로퍼티입니다. * Key: string UserId * Value: Entity PlayerEntity key 값인 UserId는 유저가 메이플스토리 월드에 가입 시 생성한 Id로 UserId와 플레이어 엔티티의 이름을 동일하게 사용하고 있습니다. ```lua void PrintUserEntitiesName() { log(_UserService:GetUserCount()) local playerEntitiesDic = _UserServi
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | 문서 예시의 GetChildComponents 메서드를 수정하여, ComponentA가 없으면 nil을 반환하는지 확인하는 5줄 이내의 코드만 출력하세요. [answer] | ```lua local comp = self.Entity.CurrentMap:GetFirstChildComponentByTypeName("ComponentA") if comp == nil then log("ComponentA not found") else log("ComponentA found") end ``` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | > **Component Entity:GetFirstChildComponentByTypeName(string typename, bool recursive)** > 하위 엔티티들을 순회하면서 하위 엔티티에 typename과 일치하는 컴포넌트가 있으면, 해당 컴포넌트를 반환합니다. > * **매개 변수** > > | Parameter | Type | Description | > | --- | --- | --- | > | typename | string | 찾고자 하는 컴포넌트의 이름을 입력합니다. | >
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | EntityA부터 EntityD 순으로 하위 엔티티가 순회될 때 recursive가 false인 경우 ComponentA를 가진 엔티티가 3번째에 있는 경우 반환 결과를 3문장 이내로 설명하세요. [answer] | recursive가 false이므로 하위 엔티티까지만 순회하며, 순서대로 1, 2번째 엔티티를 확인한 뒤 3번째 엔티티에서 ComponentA를 발견합니다. 따라서 해당 3번째 엔티티의 ComponentA가 반환됩니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | > **Component Entity:GetFirstChildComponentByTypeName(string typename, bool recursive)** > 하위 엔티티들을 순회하면서 하위 엔티티에 typename과 일치하는 컴포넌트가 있으면, 해당 컴포넌트를 반환합니다. > * **매개 변수** > > | Parameter | Type | Description | > | --- | --- | --- | > | typename | string | 찾고자 하는 컴포넌트의 이름을 입력합니다. | >
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | GetChildComponentsByTypeName 함수의 recursive 매개변수를 true로 설정하지 않으면 어떤 범위까지 컴포넌트가 검색되나요? [answer] | `GetChildComponentsByTypeName` 함수의 `recursive` 매개변수를 `true`로 설정하지 않으면(값을 넣지 않거나 `false`를 전달하면), 해당 엔티티의 **직접적인 하위 엔티티**까지만 검색 범위가 제한됩니다. 즉, 하위에 다시 하위 엔티티가 있는 경우(증손자 엔티티)까지 깊이 들어가지 않고, 해당 엔티티의 1단계 자식 엔티티들에 포함된 컴포넌트만 찾아서 반환합니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 컴포넌트는 엔티티를 작동시키는 구성품입니다. 그러므로 반드시 엔티티를 통해 컴포넌트로 접근해야 합니다. 일반적으로 **Entity.컴포넌트 명** 형태로 컴포넌트에 접근할 수 있습니다. 네이티브 컴포넌트는 스크립트 에디터에서 컴포넌트 명이 자동 완성됩니다. 다음은 내 플레이어 엔티티의 **RigidbodyComponent**에 접근하는 예시 코드입니다. ```lua [client only] void OnBeginPlay() { local myPlayerEntity = _UserService.LocalPlayer
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | Entity:GetChildByName()의 두 번째 매개 변수 recursive를 true로 설정하여 OnBeginPlay()에서 하위에 하위까지 재귀적으로 "DeepTarget" 엔티티를 찾고, 그 이름과 TransformComponent.Position을 log()로 출력하는 스크립트를 작성해줘 [answer] | `Entity:GetChildByName()`의 두 번째 매개 변수 `recursive`를 `true`로 설정하면, 바로 아래 단계뿐 아니라 하위에 있는 하위 엔티티까지 재귀적으로 검색할 수 있습니다. 찾고자 하는 엔티티가 존재하면 해당 엔티티를 반환하고, 없으면 `nil`을 반환합니다. 요청하신 조건(하위에 하위까지 재귀적으로 "DeepTarget" 엔티티를 찾고, 이름과 `TransformComponent.Position`을 출력)에 맞춰 작성한 스크립트는 다음과 같습니다. ```lua Method: [server only] [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | Entity.Children처럼 하위 엔티티를 참조하는 또 다른 방법을 알아봅시다. Entity:GetChildByName()은 하위 엔티티 중 매개 변수로 넘겨진 값과 같은 이름의 엔티티를 반환하는 함수입니다. 따라서 Entity.Children처럼 모든 하위 엔티티를 받아온 후 반복문을 통해 원하는 엔티티를 찾을 필요가 없습니다. 찾고자 하는 엔티티의 이름만 알고 있다면 훨씬 간단하게 하위 엔티티를 가져올 수 있습니다. * **매개 변수** * GetChildByName 함수는 두 개의 매개 변수를 받을 수 있습니다.
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | _UserService:GetUserEntityByUserID() 함수에 유효하지 않은 UserId를 전달하면 어떤 값이 반환되며, 이를 어떻게 처리해야 안전한지 궁금합니다. [answer] | `_UserService:GetUserEntityByUserID()` 함수에 유효하지 않은(현재 게임에 존재하지 않는) `UserId`를 전달하면 **`nil`** 을 반환합니다. 따라서 반환값을 사용하는 코드는 반드시 `nil` 체크를 수행해야 합니다. `nil` 상태의 엔티티에서 프로퍼티(예: `.Name`, `.Id`)나 메서드를 호출하면 런타임 오류가 발생할 수 있습니다. 안전한 처리 예제는 다음과 같습니다. ```lua Method: [server only] void HandleSpecificUser(string ta [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 게임에 접속해 있는 모든 플레이어 엔티티를 딕셔너리 형태로 받아오는 읽기 전용 프로퍼티입니다. * Key: string UserId * Value: Entity PlayerEntity key 값인 UserId는 유저가 메이플스토리 월드에 가입 시 생성한 Id로 UserId와 플레이어 엔티티의 이름을 동일하게 사용하고 있습니다. ```lua void PrintUserEntitiesName() { log(_UserService:GetUserCount()) local playerEntitiesDic = _UserServi
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | recursive 매개변수의 true/false/값 없음 세 가지 상태별 검색 범위를 3줄짜리 표로 정리하세요. [answer] | | recursive 값 | 검색 범위 | | :--- | :--- | | `true` | 하위 엔티티와 그 아래에 있는 하위 엔티티까지 포함하여 컴포넌트를 검색합니다. | | `false` | 해당 엔티티의 바로 아래 하위 엔티티까지만 검색합니다. | | 값 없음 | 기본값인 `false`로 설정되어, 해당 엔티티의 바로 아래 하위 엔티티까지만 검색합니다. | [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | > **Component Entity:GetFirstChildComponentByTypeName(string typename, bool recursive)** > 하위 엔티티들을 순회하면서 하위 엔티티에 typename과 일치하는 컴포넌트가 있으면, 해당 컴포넌트를 반환합니다. > * **매개 변수** > > | Parameter | Type | Description | > | --- | --- | --- | > | typename | string | 찾고자 하는 컴포넌트의 이름을 입력합니다. | >
[task] | two_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | Entity.CurrentMap과 Entity.CurrentWorld 프로퍼티를 사용하여 고유 엔티티를 참조하는 코드는 어떻게 작성하나요? [answer] | `Entity.CurrentMap`과 `Entity.CurrentWorld`는 게임 내 하나만 존재하는 맵 엔티티와 월드 엔티티를 특정 엔티티를 통해 쉽게 참조하기 위한 프로퍼티입니다. ### 1. Entity.CurrentMap 사용법 특정 엔티티가 속해 있는 맵 엔티티를 가져올 때 사용합니다. `self.Entity`를 통해 자신의 엔티티를 얻은 후, `.CurrentMap` 프로퍼티에 접근합니다. ```lua Method: [server only] void OnBeginPlay() { local myEntity = [followup] | isvalid() 체크를 생략했을 때 발생할 수 있는 에러와, 반드시 체크해야 하는 이유를 설명해 주세요. [followup_answer] | 참고 문서에는 `isvalid()` 함수의 구체적인 에러 메시지나 내부 동작 원리에 대한 설명이 포함되어 있지 않습니다. 다만, 문서의 예제 코드에서 `Entity.CurrentMap`과 `Entity.CurrentWorld`를 참조한 직후 `isvalid()` 체크를 수행하고, 체크에 실패하면 `return`으로 함수를 종료하는 패턴이 일관되게 제시되어 있습니다. 문서에 근거할 때 `isvalid()` 체크를 수행해야 하는 이유는 다음과 같이 설명할 수 있습니다. 1. **nil 반환 가능성**: `_EntityService [scores] | [judge_reason] | [source_doc] | 매개 변수로 엔티티 ID를 넘겨주면 해당 ID의 엔티티를 반환하는 함수입니다. 엔티티의 계층 구조가 동적으로 변경되거나 엔티티의 이름이 바뀌면서 경로가 변경될 여지가 있으면, 유니크한 ID를 이용해 엔티티를 받아올 수 있는 GetEntity를 사용하는 것이 효율적입니다. * **매개 변수** | Parameter | Type | Description | | --- | --- | --- | | ID | string | 얻고자 하는 엔티티 ID를 넣어줍니다. 엔티티의 콘텍스트 메뉴에서 **Copy Entity I
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | recursive 값을 지정하지 않고 GetFirstChildComponentByTypeName을 호출하면 기본적으로 어떤 동작을 하는지 알려주세요. [answer] | `recursive` 값을 지정하지 않고 `GetFirstChildComponentByTypeName`을 호출하면, 기본값으로 `false`가 설정됩니다. 따라서 해당 엔티티의 **직접적인 하위 엔티티(Entity의 하위 엔티티)까지만** 순회하여 컴포넌트를 찾게 됩니다. 하위에 다시 하위 엔티티가 있는 경우(하위에 하위 엔티티)까지 검색하지 않습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | > **Component Entity:GetFirstChildComponentByTypeName(string typename, bool recursive)** > 하위 엔티티들을 순회하면서 하위 엔티티에 typename과 일치하는 컴포넌트가 있으면, 해당 컴포넌트를 반환합니다. > * **매개 변수** > > | Parameter | Type | Description | > | --- | --- | --- | > | typename | string | 찾고자 하는 컴포넌트의 이름을 입력합니다. | >
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | GetEntity 함수로 엔티티를 찾을 때 nil이 반환되는 원인은 무엇이며, 이 경우 어떻게 처리해야 하나요? [answer] | `_EntityService:GetEntity` 함수가 `nil`을 반환하는 가장 큰 원인은 **입력한 ID에 해당하는 엔티티가 존재하지 않기 때문**입니다. 구체적인 원인은 다음과 같습니다. 1. **잘못된 ID 입력:** 엔티티 ID를 잘못 복사하거나, 오타가 있는 경우. 2. **엔티티 삭제:** 해당 ID를 가진 엔티티가 이미 파괴(destroy)되었거나 맵에서 제거된 경우. 3. **존재하지 않는 ID:** 게임 내에서 해당 ID를 가진 엔티티가 생성된 적 없는 경우. ### 처리 방법 `GetEntity` 함수 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 매개 변수로 엔티티 ID를 넘겨주면 해당 ID의 엔티티를 반환하는 함수입니다. 엔티티의 계층 구조가 동적으로 변경되거나 엔티티의 이름이 바뀌면서 경로가 변경될 여지가 있으면, 유니크한 ID를 이용해 엔티티를 받아올 수 있는 GetEntity를 사용하는 것이 효율적입니다. * **매개 변수** | Parameter | Type | Description | | --- | --- | --- | | ID | string | 얻고자 하는 엔티티 ID를 넣어줍니다. 엔티티의 콘텍스트 메뉴에서 **Copy Entity I
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 함수 [question] | 매개 변수에 값이 전달되지 않을 때 발생하는 값과, 매개 변수 2개 이상일 때 삭제되는 순서를 표로 정리하세요. [answer] | 참고 문서에 근거하여 요청하신 내용을 표로 정리했습니다. | 구분 | 내용 | | :--- | :--- | | **값이 전달되지 않을 때 발생하는 값** | `nil` | | **매개 변수 2개 이상일 때 삭제 순서** | 오른쪽 매개 변수부터 차례로 삭제 | [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 함수에 대한 간략한 소개와 함께 함수의 선언과 정의, 호출에 대해 알아봅니다. # 메소드 소개 **컴포넌트**는 기본적으로 **프로퍼티**와 **메소드**로 구성됩니다. 그중 함수는 객체지향 프로그래밍에서 사용되는 용어로, 특정 액션을 수행하기 위한 코드들의 집합체라 할 수 있습니다. 메이플스토리 월드의 함수는 함수의 호출 주체가 누구냐에 따라 **기본 이벤트 메소드**와 **사용자 지정 메소드**로 나눌 수 있습니다. 기본 이벤트 함수는 게임 시작, 플레이 중, 게임 종료 시 등 특정 이벤트가 발생했을 때
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 함수 [question] | 기본 이벤트 메소드와 사용자 지정 메소드의 차이점을 3문장 이내로 설명하세요. [answer] | 기본 이벤트 메소드는 시스템에서 특정 시점에 자동으로 호출되며 이름과 시점이 정해져 있고 다른 함수에서 직접 호출할 수 없습니다. 반면 사용자 지정 메소드는 이름을 자유롭게 지을 수 있으며, 시스템이 자동 호출하지 않아 반드시 기본 이벤트 메소드로부터 호출되어야 실행됩니다. 기본 이벤트 메소드는 게임 동작의 진입점 역할을 하고, 사용자 지정 메소드는 구체적인 액션 구현을 담당합니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 함수에 대한 간략한 소개와 함께 함수의 선언과 정의, 호출에 대해 알아봅니다. # 메소드 소개 **컴포넌트**는 기본적으로 **프로퍼티**와 **메소드**로 구성됩니다. 그중 함수는 객체지향 프로그래밍에서 사용되는 용어로, 특정 액션을 수행하기 위한 코드들의 집합체라 할 수 있습니다. 메이플스토리 월드의 함수는 함수의 호출 주체가 누구냐에 따라 **기본 이벤트 메소드**와 **사용자 지정 메소드**로 나눌 수 있습니다. 기본 이벤트 함수는 게임 시작, 플레이 중, 게임 종료 시 등 특정 이벤트가 발생했을 때
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | 프로퍼티 에디터에서 설정한 값과 스크립트에서 동적으로 변경한 값의 차이점은 무엇이며, 게임 실행 중에는 어떤 방식으로 접근해야 하나요? [answer] | 프로퍼티 에디터에서 설정한 값과 스크립트에서 동적으로 변경한 값의 차이점은 **설정 시점**과 **변경 가능 여부**입니다. 1. **프로퍼티 에디터 설정**: * 게임이 실행되기 **전에** 프로퍼티의 **초깃값만** 설정할 수 있습니다. * 게임 실행 중에는 프로퍼티 에디터로 값을 변경할 수 없습니다. 2. **스크립트에서 동적 변경**: * 게임 실행 **중**에도 프로퍼티 값을 자유롭게 변경할 수 있습니다. * 프로퍼티 값 설정 외에도 컴포넌트에 속한 함수를 호출하여 크리에이 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 게임에 접속해 있는 모든 플레이어 엔티티를 딕셔너리 형태로 받아오는 읽기 전용 프로퍼티입니다. * Key: string UserId * Value: Entity PlayerEntity key 값인 UserId는 유저가 메이플스토리 월드에 가입 시 생성한 Id로 UserId와 플레이어 엔티티의 이름을 동일하게 사용하고 있습니다. ```lua void PrintUserEntitiesName() { log(_UserService:GetUserCount()) local playerEntitiesDic = _UserServi
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | self.Entity.CurrentMap을 활용해 현재 엔티티가 속한 맵 엔티티를 가져와 isvalid 검사를 거친 후, 맵 이름을 로그로 출력하는 스크립트를 작성해줘. [answer] | ```lua Method: [server] void OnBeginPlay() { local myEntity = self.Entity local curMap = myEntity.CurrentMap if isvalid(curMap) == false then return end log(curMap.Name) } ``` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 매개 변수로 엔티티 ID를 넘겨주면 해당 ID의 엔티티를 반환하는 함수입니다. 엔티티의 계층 구조가 동적으로 변경되거나 엔티티의 이름이 바뀌면서 경로가 변경될 여지가 있으면, 유니크한 ID를 이용해 엔티티를 받아올 수 있는 GetEntity를 사용하는 것이 효율적입니다. * **매개 변수** | Parameter | Type | Description | | --- | --- | --- | | ID | string | 얻고자 하는 엔티티 ID를 넣어줍니다. 엔티티의 콘텍스트 메뉴에서 **Copy Entity I
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | _EntityService:GetEntity를 사용해 지정된 ID의 엔티티를 조회하고, nil이면 "엔티티 없음"을 로그로 출력하며, 존재하면 해당 엔티티의 Name을 출력하는 스크립트를 작성해줘. [answer] | ```lua Method: [server only] void OnBeginPlay() { local targetEntity = _EntityService:GetEntity("eb9c3412-9730-4e32-a180-69f4d1596652") if targetEntity == nil then log("엔티티 없음") else log(targetEntity.Name) end } ``` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 매개 변수로 엔티티 ID를 넘겨주면 해당 ID의 엔티티를 반환하는 함수입니다. 엔티티의 계층 구조가 동적으로 변경되거나 엔티티의 이름이 바뀌면서 경로가 변경될 여지가 있으면, 유니크한 ID를 이용해 엔티티를 받아올 수 있는 GetEntity를 사용하는 것이 효율적입니다. * **매개 변수** | Parameter | Type | Description | | --- | --- | --- | | ID | string | 얻고자 하는 엔티티 ID를 넣어줍니다. 엔티티의 콘텍스트 메뉴에서 **Copy Entity I