[task] | two_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | `Entity:GetChildByName()` 함수의 두 번째 매개 변수 `recursive`를 사용할 때의 차이점을 어떻게 이해해야 하나요? [answer] | `Entity:GetChildByName()` 함수의 두 번째 매개 변수인 `recursive`는 엔티티를 찾을 때 탐색 범위를 결정하는 boolean 값입니다. * **`false` (또는 값 미지정):** 현재 엔티티의 **바로 아래 단계(직속 자식)**에서만 이름이 일치하는 엔티티를 찾습니다. 하위에 하위가 있는 구조는 무시됩니다. * **`true`:** 현재 엔티티의 하위 엔티티를 **재귀적으로** 탐색합니다. 즉, 자식의 자식, 자식의 자식의 자식 등 모든 하위 계층에 걸쳐 이름이 일치하는 엔티티를 찾습니다. [followup] | `recursive`가 `false`인 경우와 `true`인 경우의 동작 차이를 설명하고, 하위에 하위 엔티티를 찾는 구체적인 코드 예시를 보여주세요. [followup_answer] | `Entity:GetChildByName()` 함수의 두 번째 매개 변수 `recursive`는 엔티티 탐색 범위를 결정하는 boolean 값입니다. ### 동작 차이 * **`recursive`가 `false` (또는 값 미지정):** * 현재 엔티티의 **바로 아래 단계(직속 자식)**에서만 이름이 일치하는 엔티티를 찾습니다. * 하위에 하위가 있는 구조는 무시됩니다. * `recursive`는 옵셔널 매개 변수이므로 값을 넣지 않으면 기본적으로 `false`로 동작합니다. * **` [scores] | [judge_reason] | [source_doc] | Entity.Children처럼 하위 엔티티를 참조하는 또 다른 방법을 알아봅시다. Entity:GetChildByName()은 하위 엔티티 중 매개 변수로 넘겨진 값과 같은 이름의 엔티티를 반환하는 함수입니다. 따라서 Entity.Children처럼 모든 하위 엔티티를 받아온 후 반복문을 통해 원하는 엔티티를 찾을 필요가 없습니다. 찾고자 하는 엔티티의 이름만 알고 있다면 훨씬 간단하게 하위 엔티티를 가져올 수 있습니다. * **매개 변수** * GetChildByName 함수는 두 개의 매개 변수를 받을 수 있습니다.
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 함수 [question] | 동일 컴포넌트 내 메소드 호출 시 사용되는 문법 형식과 self의 의미를 2문장 이내로 설명하세요. [answer] | 동일 컴포넌트 내 메소드를 호출할 때는 `self:메소드명(매개 변수)` 형식을 사용합니다. 여기서 `self`는 현재 작동 중인 메소드를 포함하고 있는 컴포넌트 객체를 의미합니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 메소드 내부에서는 다른 메소드를 호출해서 다른 함수의 기능을 작동시킬 수 있습니다. 기본적으로 메소드는 **컴포넌트 객체(또는 서비스):메소드명(매개 변수)** 형식으로 호출합니다. #### 동일한 컴포넌트 내 메소드 호출 시 동일 컴포넌트의 메소드를 호출할 때는 다음과 같이 **self:메소드명(매개 변수)** 형식으로 호출합니다. (**self**는 현재 작동 중인 메소드를 포함하고 있는 컴포넌트 객체를 의미합니다.) ```lua --개념 이해를 돕기 위한 코드로, 컴포넌트에 적용 시 정상적으로 동작하지 않을 수 있습니다.
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | 클라이언트 공간에서 _UserService.LocalPlayer 프로퍼티를 통해 내 플레이어 엔티티를 가져와서 그 Name 속성을 로그로 출력하는 OnBeginPlay 메서드 스크립트를 작성해줘 [answer] | 클라이언트 공간에서만 실행되는 `OnBeginPlay` 메서드를 정의하고, `_UserService.LocalPlayer` 프로퍼티를 통해 내 플레이어 엔티티를 참조한 뒤 `Name` 속성을 로그로 출력하는 스크립트는 다음과 같습니다. ```lua Method: [client only] void OnBeginPlay() { local myPlayerEntity = _UserService.LocalPlayer log(myPlayerEntity.Name) } ``` [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] | _UserService.UserEntities 딕셔너리를 순회하여 현재 접속된 모든 플레이어 엔티티의 이름(Name)을 한 줄에 하나씩 콘솔에 출력하는 OnUpdate 메서드 스크립트를 작성해줘 [answer] | 요청하신 기능을 수행하기 위한 mLua 스크립트입니다. `OnUpdate` 메서드 내에서 `_UserService.UserEntities` 딕셔너리를 순회하며 각 플레이어 엔티티의 `Name` 속성을 로그로 출력하도록 작성했습니다. ```lua Method: [server only] void OnUpdate(number delta) { local playerEntitiesDic = _UserService.UserEntities for key, playerEntity in pairs(playerEntities [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] | two_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | 자식 엔티티의 컴포넌트를 일괄 조회하는 GetChildComponentsByTypeName 메서드의 동작 원리가 궁금합니다. [answer] | `Entity:GetChildComponentsByTypeName(string typename, bool recursive)` 메서드는 특정 엔티티의 **하위 엔티티**에 포함된 컴포넌트 중, 이름이 `typename`과 정확히 일치하는 모든 컴포넌트를 `Array` 형태로 반환합니다. 동작 원리는 다음과 같습니다: 1. **대상 범위**: 호출한 엔티티의 자식 엔티티들을 탐색합니다. 2. **재귀 설정 (`recursive`)**: * `true` 또는 생략 없이 `true`로 지정 시: 하위 엔티티 안에 또 다 [followup] | recursive 매개 변수가 true와 false일 때 각각 어떤 범위의 엔티티가 검색 대상이 되는지 구체적인 차이점을 설명해 주세요. [followup_answer] | `Entity:GetChildComponentsByTypeName` 메서드의 `recursive` 매개 변수에 따라 검색되는 엔티티 범위는 다음과 같이 달라집니다. **1. `recursive`가 `false` (또는 값 미입력) 일 때** * **검색 범위:** **직접적인 하위 엔티티 1단계**까지만 대상이 됩니다. * **동작:** 현재 엔티티에 바로 연결된 자식 엔티티들만 확인하며, 그 자식 엔티티 안에 더 하위 엔티티(손자 엔티티)가 있더라도 그 안의 컴포넌트는 찾지 않습니다. * **기본값:** 매개 변수에 [scores] | [judge_reason] | [source_doc] | 컴포넌트는 엔티티를 작동시키는 구성품입니다. 그러므로 반드시 엔티티를 통해 컴포넌트로 접근해야 합니다. 일반적으로 **Entity.컴포넌트 명** 형태로 컴포넌트에 접근할 수 있습니다. 네이티브 컴포넌트는 스크립트 에디터에서 컴포넌트 명이 자동 완성됩니다. 다음은 내 플레이어 엔티티의 **RigidbodyComponent**에 접근하는 예시 코드입니다. ```lua [client only] void OnBeginPlay() { local myPlayerEntity = _UserService.LocalPlayer
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 함수 [question] | 다른 컴포넌트 및 서비스의 메소드 호출 방식을 구분하여 2열 3행 표로 정리하세요. [answer] | | 구분 | 호출 방식 | | :--- | :--- | | **동일 컴포넌트 내 메소드** | `self:메소드명(매개 변수)` | | **다른 컴포넌트 메소드** | `컴포넌트 객체:메소드명(매개 변수)` | | **서비스 메소드** | `서비스명:메소드명(매개 변수)` | [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 메소드 내부에서는 다른 메소드를 호출해서 다른 함수의 기능을 작동시킬 수 있습니다. 기본적으로 메소드는 **컴포넌트 객체(또는 서비스):메소드명(매개 변수)** 형식으로 호출합니다. #### 동일한 컴포넌트 내 메소드 호출 시 동일 컴포넌트의 메소드를 호출할 때는 다음과 같이 **self:메소드명(매개 변수)** 형식으로 호출합니다. (**self**는 현재 작동 중인 메소드를 포함하고 있는 컴포넌트 객체를 의미합니다.) ```lua --개념 이해를 돕기 위한 코드로, 컴포넌트에 적용 시 정상적으로 동작하지 않을 수 있습니다.
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | 하위 엔티티의 구조가 복잡한 맵에서 특정 이름의 컴포넌트만 효율적으로 모두 가져오려면 어떤 API를 사용해야 하나요? [answer] | 복잡한 맵 구조에서 특정 이름의 컴포넌트를 효율적으로 모두 가져오려면 `Entity:GetChildComponentsByTypeName` API를 사용해야 합니다. 이 메서드는 엔티티의 하위 엔티티들에 포함된 컴포넌트 중 지정된 이름과 일치하는 모든 컴포넌트를 배열(Array) 형태로 반환합니다. 두 번째 매개변수인 `recursive`를 `true`로 설정하면 하위 엔티티에 포함된 하위 엔티티들까지 재귀적으로 검색하므로, 복잡한 구조에서도 목표 컴포넌트를 빠짐없이 찾을 수 있습니다. 아래는 맵 엔티티(`self.Entity.C [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 컴포넌트는 엔티티를 작동시키는 구성품입니다. 그러므로 반드시 엔티티를 통해 컴포넌트로 접근해야 합니다. 일반적으로 **Entity.컴포넌트 명** 형태로 컴포넌트에 접근할 수 있습니다. 네이티브 컴포넌트는 스크립트 에디터에서 컴포넌트 명이 자동 완성됩니다. 다음은 내 플레이어 엔티티의 **RigidbodyComponent**에 접근하는 예시 코드입니다. ```lua [client only] void OnBeginPlay() { local myPlayerEntity = _UserService.LocalPlayer
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | 플레이어가 입장할 때마다 _UserService:GetUserEntityByUserID()로 해당 플레이어 엔티티를 조회하고, 그 엔티티의 TransformComponent.Position을 로그로 출력하는 이벤트 핸들러 스크립트를 작성해줘 [answer] | 사용자가 질문한 `HandleUserEnterEvent` 이벤트 핸들러는 `UserService` 서비스에서 발생하며, 매개변수로 `UserId`를 받습니다. `_UserService:GetUserEntityByUserID(UserId)`를 호출하여 해당 플레이어 엔티티를 조회하고, `TransformComponent.Position`을 로그로 출력하는 코드를 작성합니다. ```lua Event Handler: [service: UserService] HandleUserEnterEvent(UserEnterEvent event) { [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] | _UserService.UserEntities를 통해 현재 접속한 모든 유저 엔티티를 순회하며, 각 유저 엔티티의 ID와 Name을 로그로 출력하는 스크립트를 작성해줘. [answer] | `_UserService.UserEntities`는 현재 접속한 모든 유저 엔티티를 테이블로 반환하며, 이 테이블을 순회하여 각 유저 엔티티의 `ID`와 `Name` 프로퍼티를 읽을 수 있습니다. 엔티티의 `ID`와 `Name`은 일반 엔티티 프로퍼티이므로 직접 접근 가능합니다. ```lua Method: [server only] void OnBeginPlay() { local userEntities = _UserService.UserEntities if userEntities == nil then r [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] | "/maps/map01/bullets/bullet" 경로에 존재하는 모든 탄막 엔티티를 _EntityService:GetEntitiesByPath() 로 리스트 형태로 가져와, nil 체크 후 for 루프로 순회하며 각 엔티티의 TransformComponent.Position 을 log() 로 출력하는 스크립트를 작성해줘 [answer] | ```lua Method: [server only] void OnBeginPlay() { local bulletEntities = _EntityService:GetEntitiesByPath("/maps/map01/bullets/bullet") if bulletEntities == nil then return end for index, entity in pairs(bulletEntities) do log(entity.TransformComponent.Position) end } ``` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 찾으려는 엔티티 경로(Path)를 매개 변수로 넘겨주면, 해당 경로의 엔티티를 반환하는 함수입니다. 가장 보편적으로 사용되는 함수입니다. * **매개 변수** | Parameter | Type | Description | | --- | --- | --- | | worldPath | string | 얻고자 하는 엔티티 경로를 넣어줍니다. 경로는 /maps/부터 시작해서 하위 엔티티들을 입력합니다. 예를 들어 다음과 같은 계층 구조에서 "object_1"의 경로는 다음과 같습니다. "/maps/map01
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | _UserService.UserEntities의 Key(UserId)와 Value(PlayerEntity)를 이용하여, 각 플레이어의 UserId와 실제 엔티티 이름이 일치하는지 비교하여 불일치 시 로그로 경고 메시지를 출력하는 검증 로직 스크립트를 작성해줘 [answer] | `_UserService.UserEntities` 딕셔너리의 Key(`UserId`)와 Value(`PlayerEntity`)의 `Name` 프로퍼티를 비교하여 일치하지 않을 경우 경고 로그를 출력하는 스크립트입니다. ```lua Method: [server only] void CheckUserIdAndEntityNameConsistency() { local playerEntitiesDic = _UserService.UserEntities for userId, playerEntity in pairs(play [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] | 콜론(:)과 점(.) 중 어떤 기호로 호출해야 하는지 Static 메소드와 일반 메소드의 차이를 코드 블록 안에 주석으로만 설명하세요. [answer] | ```lua void OnBeginPlay() { -- 일반 메소드: 콜론(:)으로 호출합니다. -- (예: self:MyMethod(), component:Method(), service:Method()) self:PrintHello() -- Static 메소드: 점(.)으로 호출합니다. -- (예: Vector2.Distance(), table.insert(), string.len()) local dist = Vector2.Distance(Vector2(0,0), Vector2(10, [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 메소드 내부에서는 다른 메소드를 호출해서 다른 함수의 기능을 작동시킬 수 있습니다. 기본적으로 메소드는 **컴포넌트 객체(또는 서비스):메소드명(매개 변수)** 형식으로 호출합니다. #### 동일한 컴포넌트 내 메소드 호출 시 동일 컴포넌트의 메소드를 호출할 때는 다음과 같이 **self:메소드명(매개 변수)** 형식으로 호출합니다. (**self**는 현재 작동 중인 메소드를 포함하고 있는 컴포넌트 객체를 의미합니다.) ```lua --개념 이해를 돕기 위한 코드로, 컴포넌트에 적용 시 정상적으로 동작하지 않을 수 있습니다.
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | self.Entity.CurrentWorld를 통해 최상위 World 엔티티를 참조하고, 유효성 검사를 통과하면 World 엔티티의 Name을 콘솔에 출력하는 스크립트를 작성해줘. [answer] | `self.Entity.CurrentWorld` 프로퍼티는 해당 엔티티가 속한 최상위 World 엔티티를 가져오는 데 사용됩니다. World 엔티티는 게임 내에서 단 하나만 존재하므로, 어떤 엔티티에서든 이 프로퍼티를 통해 쉽게 참조할 수 있습니다. 요청하신 동작을 수행하는 스크립트는 다음과 같습니다. ```lua Method: [server only] void OnBeginPlay() { -- 자신이 포함하고 있는 Entity를 받아 옴 local myEntity = self.Entity -- 최 [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] | 스크립트 컴포넌트에 접근하려고 했는데 nil 값이 반환되는 경우, 가장 먼저 확인해야 할 사항은 무엇인가요? [answer] | 참고 문서에 따르면, 스크립트 컴포넌트에 접근했을 때 `nil` 값이 반환되는 경우 가장 먼저 확인해야 할 사항은 **해당 엔티티에 스크립트 컴포넌트가 실제로 존재하는지**입니다. 문서는 스크립트 컴포넌트 접근 예시 코드에서 `nil` 체크를 수행하고 있으며, 이는 접근하려는 엔티티에 해당 이름의 컴포넌트가 없거나 아직 생성되지 않았을 수 있음을 시사합니다. 특히 스크립트 컴포넌트는 "직접 제작한 뒤" 접근할 수 있다고 명시되어 있으므로, 해당 엔티티에 해당 이름의 스크립트 컴포넌트가 올바르게 추가(생성)되었는지 우선적으로 확인해 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 컴포넌트는 엔티티를 작동시키는 구성품입니다. 그러므로 반드시 엔티티를 통해 컴포넌트로 접근해야 합니다. 일반적으로 **Entity.컴포넌트 명** 형태로 컴포넌트에 접근할 수 있습니다. 네이티브 컴포넌트는 스크립트 에디터에서 컴포넌트 명이 자동 완성됩니다. 다음은 내 플레이어 엔티티의 **RigidbodyComponent**에 접근하는 예시 코드입니다. ```lua [client only] void OnBeginPlay() { local myPlayerEntity = _UserService.LocalPlayer
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 엔티티의 충돌 [question] | TriggerComponent와 HitComponent의 역할 차이와 충돌체 편집 활성화 방법을 3문장 이내로 설명하세요. [answer] | TriggerComponent는 충돌 범위를, HitComponent는 피격 범위를 설정할 때 각각 충돌체를 사용합니다. 프로퍼티 에디터의 [Edit] 버튼을 눌러 편집을 활성화하면 충돌 영역 색상이 초록색으로 변경됩니다. 활성화된 상태에서 포인트를 잡아당겨 크기나 ColliderOffset을 조정할 수 있습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 충돌 이벤트와 충돌 처리 방법에 대해 알아봅시다. ##### 참고 가이드 [Event System](https://mod-developers.nexon.com/docs?postId=73) [Entity Event System](https://mod-developers.nexon.com/docs?postId=176) # 충돌 **충돌**이란 충돌체를 포함하는 엔티티'의 충돌 영역이 서로 교차하는 것을 말합니다. 엔티티에 [TriggerComponent](/apiReference/Components/Trigge
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | _EntityService:GetEntitiesByPath("/maps/map01/enemies") 로 동일한 경로에 있는 적 엔티티들을 모두 가져와, nil이 아닌 경우 테이블을 순회하며 각 적 엔티티의 이름을 log() 로 출력하는 스크립트를 작성해줘 [answer] | ```lua Method: [server only] void OnBeginPlay() { local enemyTable = _EntityService:GetEntitiesByPath("/maps/map01/enemies") if enemyTable == nil then return end for index, entity in pairs(enemyTable) do log(entity.Name) end } ``` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 찾으려는 엔티티 경로(Path)를 매개 변수로 넘겨주면, 해당 경로의 엔티티를 반환하는 함수입니다. 가장 보편적으로 사용되는 함수입니다. * **매개 변수** | Parameter | Type | Description | | --- | --- | --- | | worldPath | string | 얻고자 하는 엔티티 경로를 넣어줍니다. 경로는 /maps/부터 시작해서 하위 엔티티들을 입력합니다. 예를 들어 다음과 같은 계층 구조에서 "object_1"의 경로는 다음과 같습니다. "/maps/map01
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | GetFirstChildComponentByTypeName 메서드의 recursive 매개변수를 true로 설정하면 어떤 범위의 엔티티까지 검색하게 되나요? [answer] | `GetFirstChildComponentByTypeName` 메서드의 `recursive` 매개변수를 `true`로 설정하면, 해당 엔티티의 하위 엔티티뿐만 아니라 **하위에 하위 엔티티까지(재귀적으로)** 포함하여 검색하게 됩니다. 즉, `true`로 설정하면 대상 엔티티의 모든 깊이(deep)에 있는 하위 엔티티들을 순회하며, 지정한 이름(`typename`)과 일치하는 컴포넌트를 가진 **첫 번째** 엔티티의 해당 컴포넌트를 반환합니다. 반대로 `false`로 설정하거나 매개변수를 생략하면, 대상 엔티티의 **직접적인 하 [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] | GetEntityByPath()와 GetEntitiesByPath()는 어떤 상황에서 각각 사용해야 하며, 반환값의 차이점은 무엇인가요? [answer] | `GetEntityByPath()`와 `GetEntitiesByPath()`는 엔티티를 경로(Path)로 조회하는 함수이지만, 반환되는 데이터의 형태와 사용 목적에 명확한 차이가 있습니다. ### 1. 반환값의 차이점 * **`GetEntityByPath()`** * **반환 타입:** `Entity` (단일 객체) 또는 `nil` * **동작:** 매개변수로 입력한 경로와 일치하는 엔티티 중 **가장 먼저 찾은 하나**만 반환합니다. * **주의:** 경로가 동일한 엔티티가 여러 개 존재하더 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 찾으려는 엔티티 경로(Path)를 매개 변수로 넘겨주면, 해당 경로의 엔티티를 반환하는 함수입니다. 가장 보편적으로 사용되는 함수입니다. * **매개 변수** | Parameter | Type | Description | | --- | --- | --- | | worldPath | string | 얻고자 하는 엔티티 경로를 넣어줍니다. 경로는 /maps/부터 시작해서 하위 엔티티들을 입력합니다. 예를 들어 다음과 같은 계층 구조에서 "object_1"의 경로는 다음과 같습니다. "/maps/map01
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | "/maps/map01/obj/target" 경로의 엔티티를 _EntityService:GetEntityByPath() 로 찾아 존재 여부를 확인하고, 존재하지 않을 경우 nil 체크 후 종료하며 존재할 경우 이름을 log() 로 출력하는 스크립트를 작성해줘 [answer] | 요청하신 `_EntityService:GetEntityByPath()` 함수를 사용하여 엔티티의 존재 여부를 확인하고, 조건에 따라 처리하는 스크립트는 다음과 같습니다. ```lua Method: [server only] void OnBeginPlay() { -- "/maps/map01/obj/target" 경로의 엔티티를 조회합니다. local targetEntity = _EntityService:GetEntityByPath("/maps/map01/obj/target") -- 엔티티가 존재하지 않을 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 찾으려는 엔티티 경로(Path)를 매개 변수로 넘겨주면, 해당 경로의 엔티티를 반환하는 함수입니다. 가장 보편적으로 사용되는 함수입니다. * **매개 변수** | Parameter | Type | Description | | --- | --- | --- | | worldPath | string | 얻고자 하는 엔티티 경로를 넣어줍니다. 경로는 /maps/부터 시작해서 하위 엔티티들을 입력합니다. 예를 들어 다음과 같은 계층 구조에서 "object_1"의 경로는 다음과 같습니다. "/maps/map01
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 엔티티의 충돌 [question] | 충돌 이벤트 매개 변수에 포함되는 상대 엔티티 정보의 내용을 3문장 이내로 [answer] | 충돌 이벤트 매개 변수에는 충돌한 상대 엔티티 정보가 포함됩니다. 이 정보는 `event.TriggerBodyEntity`를 통해 접근할 수 있습니다. 상대 엔티티의 이름(`Name`)이나 해당 엔티티를 대상으로 한 서비스 호출 등에 사용할 수 있습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 다른 스크립트 컴포넌트와는 달리, 확장된 **TriggerComponent**에는 몇 가지 함수를 오버라이딩할 수 있습니다. 이 함수들은 충돌 이벤트가 발생할 때 호출되는 것입니다. 이 함수를 추가하면 해당 함수의 정의부를 편집하여 오버라이딩할 수 있습니다. 오버라이딩할 수 있는 함수는 총 세 가지입니다. 다음은 함수별 호출 시점입니다. * **OnEnterTriggerBody** :엔티티 간 충돌이 처음 발생했을 때 1회 호출됩니다. * **OnStayTriggerBody**: 엔티티 간 충돌이 발생한 뒤, 두 엔티티가 겹쳐
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 함수 [question] | 스크립트 에디터에서 사용자 지정 함수를 생성하고 매개 변수를 추가하는 절차를 단계별 번호 목록으로 정리하세요. [answer] | 참고 문서에 기반하여 스크립트 에디터에서 사용자 지정 함수를 생성하고 매개 변수를 추가하는 절차는 다음과 같습니다. 1. **새 스크립트 컴포넌트 생성 및 에디터 열기**: 새 스크립트 컴포넌트를 생성한 뒤 스크립트 에디터를 엽니다. 2. **사용자 지정 함수 추가**: * **Function** 옆의 **[+]** 버튼을 눌러 함수 목록을 엽니다. * **New**를 클릭하여 사용자 지정 함수를 추가합니다. (기본 이벤트 함수가 아닌 사용자 지정 함수를 만들 때 사용) * 기본 이름인 **Fu [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 함수에 대한 간략한 소개와 함께 함수의 선언과 정의, 호출에 대해 알아봅니다. # 메소드 소개 **컴포넌트**는 기본적으로 **프로퍼티**와 **메소드**로 구성됩니다. 그중 함수는 객체지향 프로그래밍에서 사용되는 용어로, 특정 액션을 수행하기 위한 코드들의 집합체라 할 수 있습니다. 메이플스토리 월드의 함수는 함수의 호출 주체가 누구냐에 따라 **기본 이벤트 메소드**와 **사용자 지정 메소드**로 나눌 수 있습니다. 기본 이벤트 함수는 게임 시작, 플레이 중, 게임 종료 시 등 특정 이벤트가 발생했을 때
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 엔티티의 충돌 [question] | TriggerComponent의 충돌 이벤트 핸들러를 Event System 방식으로 구성할 때 self와 entity 센더 설정의 차이점을 3문장 이내로 [answer] | 센더를 `self`로 설정하면 해당 스크립트 컴포넌트를 포함하고 있는 엔티티 자체의 충돌 이벤트를 수신합니다. 반면 `entity`로 설정하면 지정된 다른 엔티티의 충돌 이벤트를 수신하도록 할 수 있습니다. 따라서 자신의 충돌을 처리할 때는 `self`, 타겟 엔티티의 충돌을 감지할 때는 `entity`를 선택해야 합니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 충돌 이벤트 이후 액션은 **Entity Event System**을 활용하거나, **확장된 TriggerComponent** 활용합니다. 월드에 **TriggerComponent**를 포함하는 A와 B, 두 엔티티가 있다고 가정해 봅시다. A와 B가 부딪히면 충돌 이벤트가 발생합니다. 그러나 이후 특별한 변화가 일어나지 않을 것입니다. 충돌 이벤트 발생을 한 뒤 일어날 추가 액션이 없기 때문입니다. **TriggerComponent**를 활용하면 충돌 이벤트가 발생할 때 일어날 액션을 추가할 수 있습니다. 예를 들어 A와 B가 충
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 엔티티의 충돌 [question] | 충돌 이벤트 발생 시점별 TriggerEnterEvent, TriggerStayEvent, TriggerLeaveEvent의 발생 조건을 표로 정리해서 [answer] | 충돌 이벤트의 발생 시점에 따른 Trigger 이벤트 조건은 다음과 같습니다. | 이벤트 이름 | 발생 조건 | 발생 빈도 | | :--- | :--- | :--- | | `TriggerEnterEvent` | 엔티티가 처음 충돌할 때 | 1회 | | `TriggerStayEvent` | 엔티티가 충돌 상태가 유지되는 동안 | 프레임마다 | | `TriggerLeaveEvent` | 엔티티가 충돌했다가 충돌이 끝날 때 | 1회 | [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 충돌 이벤트 이후 액션은 **Entity Event System**을 활용하거나, **확장된 TriggerComponent** 활용합니다. 월드에 **TriggerComponent**를 포함하는 A와 B, 두 엔티티가 있다고 가정해 봅시다. A와 B가 부딪히면 충돌 이벤트가 발생합니다. 그러나 이후 특별한 변화가 일어나지 않을 것입니다. 충돌 이벤트 발생을 한 뒤 일어날 추가 액션이 없기 때문입니다. **TriggerComponent**를 활용하면 충돌 이벤트가 발생할 때 일어날 액션을 추가할 수 있습니다. 예를 들어 A와 B가 충
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 엔티티의 충돌 [question] | OnEnterTriggerBody, OnStayTriggerBody, OnLeaveTriggerBody 함수별 호출 빈도(1회 vs 프레임마다)를 단계별 번호 목록으로 [answer] | 충돌 이벤트가 발생하는 시점에 따라 호출 빈도가 다른 함수들의 특성은 다음과 같습니다. 1. `OnEnterTriggerBody`: 엔티티 간 충돌이 **처음 발생했을 때 1회**만 호출됩니다. 2. `OnStayTriggerBody`: 충돌이 발생한 뒤 두 엔티티가 겹쳐있는 동안 **프레임마다** 호출됩니다. 3. `OnLeaveTriggerBody`: 엔티티 간 충돌이 종료될 때 **1회**만 호출됩니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 다른 스크립트 컴포넌트와는 달리, 확장된 **TriggerComponent**에는 몇 가지 함수를 오버라이딩할 수 있습니다. 이 함수들은 충돌 이벤트가 발생할 때 호출되는 것입니다. 이 함수를 추가하면 해당 함수의 정의부를 편집하여 오버라이딩할 수 있습니다. 오버라이딩할 수 있는 함수는 총 세 가지입니다. 다음은 함수별 호출 시점입니다. * **OnEnterTriggerBody** :엔티티 간 충돌이 처음 발생했을 때 1회 호출됩니다. * **OnStayTriggerBody**: 엔티티 간 충돌이 발생한 뒤, 두 엔티티가 겹쳐
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 엔티티의 충돌 [question] | TriggerComponent에서 오버라이딩 가능한 함수 3가지의 이름과 호출 시점을 표로 정리해서 [answer] | TriggerComponent에서 오버라이딩할 수 있는 함수 3가지와 각 함수의 호출 시점은 다음과 같습니다. | 함수 이름 | 호출 시점 | | :--- | :--- | | `OnEnterTriggerBody` | 엔티티 간 충돌이 처음 발생했을 때 1회 호출됩니다. | | `OnStayTriggerBody` | 엔티티 간 충돌이 발생한 뒤, 두 엔티티가 겹쳐있는 동안 프레임마다 호출됩니다. | | `OnLeaveTriggerBody` | 엔티티 간 충돌이 종료될 때 1회 호출됩니다. | [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 다른 스크립트 컴포넌트와는 달리, 확장된 **TriggerComponent**에는 몇 가지 함수를 오버라이딩할 수 있습니다. 이 함수들은 충돌 이벤트가 발생할 때 호출되는 것입니다. 이 함수를 추가하면 해당 함수의 정의부를 편집하여 오버라이딩할 수 있습니다. 오버라이딩할 수 있는 함수는 총 세 가지입니다. 다음은 함수별 호출 시점입니다. * **OnEnterTriggerBody** :엔티티 간 충돌이 처음 발생했을 때 1회 호출됩니다. * **OnStayTriggerBody**: 엔티티 간 충돌이 발생한 뒤, 두 엔티티가 겹쳐
[task] | two_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | mLua에서 엔티티를 참조하는 방법과 GetEntity 함수의 특징은 무엇인가요? [answer] | mLua에서 엔티티를 참조하는 방법과 `_EntityService:GetEntity` 함수의 특징은 다음과 같습니다. ### 1. 엔티티 참조 방법 엔티티를 참조하는 주요 방법에는 **ID 기반 참조**, **경로 기반 참조**, 그리고 **고유 엔티티 프로퍼티 참조**가 있습니다. #### (1) ID 기반 참조 (`_EntityService:GetEntity`) 엔티티의 고유 ID를 매개변수로 전달하여 엔티티를 가져옵니다. 엔티티의 이름이 바뀌거나 계층 구조가 동적으로 변경되어 경로가 변할 수 있는 상황에서는 경로보다 유니 [followup] | GetEntity로 받은 엔티티가 nil일 때의 예외 처리 및 nil 체크 로직을 어떻게 작성하나요? [followup_answer] | `_EntityService:GetEntity` 함수는 매개변수로 전달한 ID에 해당하는 엔티티가 존재하지 않을 경우 `nil`을 반환합니다. 따라서 반환값을 사용하기 전에 반드시 `nil` 체크를 수행해야 합니다. ### nil 체크 로직 작성 방법 엔티티 참조 직후 반환값이 `nil`인지 확인하는 조건문을 작성합니다. `nil`인 경우 해당 로직을 중단하거나(`return`) 대체 처리를 수행합니다. ```lua void OnBeginPlay() { -- 매개 변수로 찾고자 하는 엔티티의 ID를 넘겨주면 해당 ID의 [scores] | [judge_reason] | [source_doc] | 매개 변수로 엔티티 ID를 넘겨주면 해당 ID의 엔티티를 반환하는 함수입니다. 엔티티의 계층 구조가 동적으로 변경되거나 엔티티의 이름이 바뀌면서 경로가 변경될 여지가 있으면, 유니크한 ID를 이용해 엔티티를 받아올 수 있는 GetEntity를 사용하는 것이 효율적입니다. * **매개 변수** | Parameter | Type | Description | | --- | --- | --- | | ID | string | 얻고자 하는 엔티티 ID를 넣어줍니다. 엔티티의 콘텍스트 메뉴에서 **Copy Entity I
[task] | single_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | RigidbodyComponent 같은 네이티브 컴포넌트와 내가 직접 만든 스크립트 컴포넌트는 엔티티를 통해 접근할 때 어떤 차이가 있나요? [answer] | 네이티브 컴포넌트와 직접 만든 스크립트 컴포넌트는 모두 **엔티티를 통해 접근**해야 한다는 점에서는 동일합니다. 하지만 접근 방식에 있어서는 다음과 같은 차이가 있습니다. **1. 네이티브 컴포넌트 접근** 네이티브 컴포넌트는 `Entity.컴포넌트 명` 형태로 접근합니다. 이때 컴포넌트 이름은 스크립트 에디터에서 자동 완성됩니다. 예를 들어, 내 플레이어 엔티티의 `RigidbodyComponent`에 접근하려면 `_UserService.LocalPlayer`로 엔티티를 가져온 뒤 `RigidbodyComponent` 속성을 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 컴포넌트는 엔티티를 작동시키는 구성품입니다. 그러므로 반드시 엔티티를 통해 컴포넌트로 접근해야 합니다. 일반적으로 **Entity.컴포넌트 명** 형태로 컴포넌트에 접근할 수 있습니다. 네이티브 컴포넌트는 스크립트 에디터에서 컴포넌트 명이 자동 완성됩니다. 다음은 내 플레이어 엔티티의 **RigidbodyComponent**에 접근하는 예시 코드입니다. ```lua [client only] void OnBeginPlay() { local myPlayerEntity = _UserService.LocalPlayer
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 엔티티의 충돌 [question] | ColliderType의 세 가지 형태(Box, Circle, Polygon)와 각 형태를 설정하는 주요 프로퍼티 이름을 표로 정리해서 출력하세요. [answer] | ColliderType의 세 가지 형태와 각 형태를 설정하는 주요 프로퍼티는 다음과 같습니다. | ColliderType | 설명 | 주요 프로퍼티 | | :--- | :--- | :--- | | **Box** | 충돌체를 사각형 형태로 설정합니다. | **BoxSize** (X: 가로 크기, Y: 세로 크기) | | **Circle** | 충돌체를 원 형태로 설정합니다. | **CircleRadius** (반지름 값) | | **Polygon** | 충돌체를 다각형으로 설정합니다. | **PolygonPoint** (원하는 모양 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 충돌 이벤트와 충돌 처리 방법에 대해 알아봅시다. ##### 참고 가이드 [Event System](https://mod-developers.nexon.com/docs?postId=73) [Entity Event System](https://mod-developers.nexon.com/docs?postId=176) # 충돌 **충돌**이란 충돌체를 포함하는 엔티티'의 충돌 영역이 서로 교차하는 것을 말합니다. 엔티티에 [TriggerComponent](/apiReference/Components/Trigge
[task] | two_turn [pass] | ⏳ 미판정 [title] | 엔티티와 컴포넌트 참조 [question] | _UserService.UserEntities 프로퍼티를 통해 접속한 모든 플레이어 엔티티를 딕셔너리 형태로 조회할 때, Key와 Value의 타입은 각각 무엇이며 이 딕셔너리를 순회하며 플레이어 이름을 출력하는 코드는 어떻게 작성하나요? [answer] | `_UserService.UserEntities` 프로퍼티는 게임에 접속해 있는 모든 플레이어 엔티티를 딕셔너리 형태로 반환하는 읽기 전용 프로퍼티입니다. * **Key 타입**: `string` (UserId) * **Value 타입**: `Entity` (PlayerEntity) 이 딕셔너리를 순회하며 플레이어 이름을 출력하는 코드는 다음과 같습니다. ```lua [server only] void PrintAllPlayerNames() { local playerEntitiesDic = _UserService. [followup] | _UserService.UserEntities 딕셔너리를 pairs()로 순회할 때 Key 값(UserId)과 Value 값(플레이어 엔티티)을 어떻게 조합하여 로그에 출력해야 하며, 이 프로퍼티가 읽기 전용인 이유에 대해 설명해 주세요. [followup_answer] | `_UserService.UserEntities` 딕셔너리를 `pairs()`로 순회할 때 Key 값(UserId)과 Value 값(플레이어 엔티티)을 조합하여 로그에 출력하는 방법은 다음과 같습니다. ```lua [server only] void PrintUserEntitiesName() { local playerEntitiesDic = _UserService.UserEntities -- 모든 플레이어를 순회하며 콘솔 창에 "플레이어 key 값/플레이어 이름" 형식으로 출력 for key, play [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] | 함수 매개 변수를 호출할 때 값 없이 빈 상태로 넘기면 어떤 값이 전달되며, 추가한 매개 변수를 삭제할 때 여러 개가 있는 경우 어떤 순서로 지워지나요? [answer] | 함수 매개 변수에 값을 넘기지 않고 빈 상태로 호출하면 **`nil`** 값이 전달됩니다. 추가한 매개 변수를 삭제할 때 여러 개의 매개 변수가 있는 경우, **오른쪽의 매개 변수부터 차례로** 삭제됩니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 함수에 대한 간략한 소개와 함께 함수의 선언과 정의, 호출에 대해 알아봅니다. # 메소드 소개 **컴포넌트**는 기본적으로 **프로퍼티**와 **메소드**로 구성됩니다. 그중 함수는 객체지향 프로그래밍에서 사용되는 용어로, 특정 액션을 수행하기 위한 코드들의 집합체라 할 수 있습니다. 메이플스토리 월드의 함수는 함수의 호출 주체가 누구냐에 따라 **기본 이벤트 메소드**와 **사용자 지정 메소드**로 나눌 수 있습니다. 기본 이벤트 함수는 게임 시작, 플레이 중, 게임 종료 시 등 특정 이벤트가 발생했을 때