[task] | instruction_following [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | 몬스터를 스폰할 때 필요한 Entry ID를 Workspace에서 복사하는 구체적인 단계를 번호 목록으로 정리해 주세요. [answer] | 몬스터를 스폰할 때 필요한 Entry ID를 Workspace에서 복사하는 구체적인 단계는 다음과 같습니다. 1. Workspace에 추가해 둔 몬스터 모델을 찾습니다. 2. 해당 몬스터 모델에서 우클릭하여 컨텍스트 메뉴를 엽니다. 3. 컨텍스트 메뉴에서 `Copy Entry ID`를 선택합니다. 4. 클립보드에 복사된 Entry ID를 확인하고, 스크립트의 `_SpawnService:SpawnByModelId` 함수의 첫 번째 매개 변수 위치("Entry ID" 부분)에 붙여넣습니다. 참고로 복사한 Entry ID에서 `mod [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이제 스크립트를 통해 몬스터 스폰 기능을 만들어보겠습니다. 우선은 특정 좌표에 몬스터를 스폰해 보고 점차 기능을 확장해 봅시다. 1. 새 스크립트 컴포넌트 **MonsterSpawn**을 생성합니다. 2. **MonsterSpawn** 스크립트를 열어 `SpawnMonster()` 함수를 추가합니다. 3. `SpawnMonster()` 함수를 다음과 같이 작성합니다. ```lua void SpawnMonster() { local parent = _EntityServ
[task] | two_turn [pass] | ⏳ 미판정 [title] | Entity Event System [question] | Entity Event System에서 컴포넌트가 엔티티를 중계자로 사용하여 이벤트를 주고받는 기본 원리가 무엇이며, 자기 자신과 다른 엔티티(맵/월드)에 이벤트를 연결하는 방식의 차이는 무엇인가요? [answer] | Entity Event System의 기본 원리와 이벤트 연결 방식에 대해 설명해 드립니다. ### 1. 기본 원리: 엔티티를 중계자로 사용하는 방식 Entity Event System에서 컴포넌트는 **엔티티(Entity)를 중계자(Mediator)로** 사용하여 이벤트를 제어합니다. * **이벤트 등록 및 발생:** 각 컴포넌트는 자신이 속해 있는 엔티티를 통해 이벤트 핸들러를 등록하고, 이벤트를 발생시킵니다. * **전송 과정:** 이벤트 발생자(Sender) 역시 엔티티를 통해 이벤트를 발생시킵니다. 이후 해당 [followup] | `SunriseEvent` 스크립트에서 `Property: boolean isSunrise = false`를 선언한 후, 이 이벤트를 `VampireComponent`와 `HunterComponent`에서 각각 수신하기 위해 필요한 Event Handler 블록의 정확한 코드 구조와 등록 방법은 무엇인가요? [followup_answer] | 참고 문서에는 `SunriseEvent`의 `isSunrise` 속성 선언 방법과 `VampireComponent`, `HunterComponent`를 생성하여 NPC에 추가하는 절차만 명시되어 있으며, **이 두 컴포넌트에서 `SunriseEvent`를 수신하기 위한 구체적인 Event Handler 코드 구조나 등록 방법은 포함되어 있지 않습니다.** 문서에 제시된 예제 코드는 `HitEvent`와 `ButtonClickEvent`의 처리 방식만 보여줄 뿐, 커스텀 이벤트 타입(`SunriseEvent`)을 핸들러로 등록하는 [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 메이플스토리 월드에서는 Entity Event System을 사용해 이벤트를 제어할 수 있습니다. 이번 시간에는 Entity Event System을 이용해 "뱀파이어 vs 헌터"의 게임 요소 중 하나를 만들어봅시다. 다음 가이드를 먼저 학습하면 이번 과정을 이해하는 데 많은 도움이 됩니다. [Event System](https://mod-developers.nexon.com/docs?postId=73) # Entity Event System 이벤트를 받고 보내려면 먼저 Entity Event System을
[task] | single_turn [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | 몬스터 스폰 시 특정 영역 내 랜덤한 위치를 지정하기 위해 어떤 좌표 계산 로직을 적용해야 하나요? [answer] | 제공된 문서에는 몬스터 스폰 시 "특정 영역 내 랜덤한 위치"를 지정하기 위한 구체적인 좌표 계산 로직이나 코드 예제가 포함되어 있지 않습니다. 문서에서는 스폰 규칙으로 "스폰 위치: 특정 영역 내 랜덤한 위치"를 언급하고 있으며, `_SpawnService:SpawnByModelId`를 사용하여 몬스터를 생성하는 구조는 제시되어 있지만, 랜덤 좌표를 어떻게 산출하는지(예: 최소/최대 x, y 좌표 설정 후 `math.random` 사용 등)에 대한 설명은 없습니다. 따라서 이 질문에 대한 정확한 답변은 문서 내 정보만으로는 불가 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 몬스터를 스폰한 뒤, 몬스터를 처치하면 아이템을 드랍하고 이 아이템을 인벤토리에 저장하는 일련의 과정을 구현해 봅시다. > 본 가이드는 아래의 순서로 이어지는 과정입니다. > **▶ 1편.** [**몬스터를 스폰해보자**](/docs?postId=204) > 2편. [몬스터 드랍 아이템과 인벤토리 UI 만들기](/docs?postId=943) > 3편. [인벤토리 스크립트 작성하기](/docs?postId=942) > 4편. [인벤토리 UI 스크립트 작성하기](/docs?postId=946) > 5편. [아이템
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스크립트 디버그 [question] | Watch Expression에 값을 등록할 때, 함수 내부의 로컬 변수와 컴포넌트의 프로퍼티는 각각 어떤 형식으로 이름을 입력해야 하나요? [answer] | Watch Expression에 값을 등록할 때, 함수 내부의 로컬 변수와 컴포넌트의 프로퍼티는 다음과 같은 형식으로 이름을 입력해야 합니다. * **함수 내부의 로컬 변수**: **변수 이름** 그대로 입력합니다. * **컴포넌트의 프로퍼티**: **`self.프로퍼티 명`** 형식으로 입력합니다. 예를 들어, 프로퍼티 `Power`의 값을 추적하려면 `self.Power`라고 입력하면 됩니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 중단점을 설정한 코드를 확인했을 때 문제가 없다면, 혹은 해당 코드 아래 줄의 상태도 함께 확인하고 싶다면 어떻게 해야 할까요? 확인하고자 하는 모든 코드 라인에 중단점을 설정할 수도 없고, 매번 디버그 시작/중지를 반복하며 중단점 설정 해제를 반복하는 것도 비효율적입니다. 디버깅 중 중단점에서 플레이가 멈춘 뒤, 중단점이 설정된 라인 이후로 코드를 실행하는 방법이 있습니다. **프로시저 단위 실행**, **한 단계씩 코드 실행** 등을 통해 단위별로 코드를 실행하며 코드의 상태나 흐름을 파악할 수 있습니다. 단위별 코드 실행은 디
[task] | single_turn [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | 최대 10마리 제한과 5초 주기 리스폰 규칙을 구현할 때, 맵 내 현재 몬스터 수를 체크하는 코드는 어디에 작성해야 하나요? [answer] | 제공된 참고 문서에는 "몬스터를 스폰해보자"라는 제목의 1편 가이드가 포함되어 있으며, 여기에는 몬스터 처치 시 아이템 드랍 및 스폰(`DropItem`, `OnMonsterDestroy`)과 관련된 예제 코드가 있습니다. 하지만 질문하신 **"최대 10마리 제한"**과 **"5초 주기 리스폰"** 규칙을 구현하기 위해 **맵 내 현재 몬스터 수를 체크하는 코드**에 대한 구체적인 예제나 설명은 제공된 문서에 포함되어 있지 않습니다. 문서에는 리스폰 규칙(최대 10마리, 5초 주기)이 텍스트로 언급되어 있지만, 이를 구현하는 실 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 몬스터를 스폰한 뒤, 몬스터를 처치하면 아이템을 드랍하고 이 아이템을 인벤토리에 저장하는 일련의 과정을 구현해 봅시다. > 본 가이드는 아래의 순서로 이어지는 과정입니다. > **▶ 1편.** [**몬스터를 스폰해보자**](/docs?postId=204) > 2편. [몬스터 드랍 아이템과 인벤토리 UI 만들기](/docs?postId=943) > 3편. [인벤토리 스크립트 작성하기](/docs?postId=942) > 4편. [인벤토리 UI 스크립트 작성하기](/docs?postId=946) > 5편. [아이템
[task] | two_turn [pass] | ⏳ 미판정 [title] | 엔티티를 탐색하는 EntityService [question] | EntityService로 엔티티를 탐색하는 함수들 중 GetEntityByPath()와 GetEntitiesByPath()의 차이점과 각각 언제 사용하면 좋은지 설명해 주세요. [answer] | `EntityService`의 `GetEntityByPath()`와 `GetEntitiesByPath()`는 모두 월드 경로(path)를 기반으로 엔티티를 탐색하지만, 반환하는 결과의 개수와 사용 목적에 차이가 있습니다. ### 1. GetEntityByPath() * **기능**: 전달한 월드 경로와 **일치하는 단일 엔티티**를 반환합니다. * **동작 방식**: 해당 경로에 일치하는 엔티티가 2개 이상 존재하는 경우, **가장 먼저 찾은 엔티티 하나**만 반환합니다. * **사용 시점**: * 월드 경로 [followup] | GetEntitiesByPath()로 반환된 배열에서 특정 조건(예: 위치가 플레이어 근처)에 맞는 엔티티만 필터링해서 처리하는 코드 예제를 만들어 주세요. [followup_answer] | 참고 문서에 제공된 `EntityService`의 API 및 이벤트 목록에는 엔티티의 **위치(Position)를 직접 조회하거나 비교하기 위한 API가 명시되어 있지 않습니다.** 또한 `Entity` 객체의 프로퍼티로서 `Position`을 직접 접근하는 문법도 문서에 포함되어 있지 않습니다. 따라서 제공된 참고 문서의 범위 내에서 '위치 기반 필터링' 코드를 작성할 수 있는 API가 없습니다. 대신, 문서에 명시된 기능들을 조합하여 **특정 경로로 생성된 모든 엔티티를 가져온 후, 각 엔티티의 이름(Name)이나 ID를 기 [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 월드를 제작하다 보면 특정 엔티티를 탐색하여 받아오거나, 혹은 관련 있는 여러 엔티티를 한 번에 받아야 하는 상황이 자주 발생합니다. 이럴 때 [**EntityService**](/apiReference/Services/EntityService)를 활용할 수 있습니다. **EntityService**는 엔티티 탐색, 삭제, 유효성 체크 등의 기능을 제공하고 있습니다. 이번 과정에서는 **EntityService**에서 제공하는 기능의 사용법을 하나씩 알아보도록 하겠습니다. **테스트 환경** **common
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스크립트 디버그 [question] | Call Stack 패널을 열어봤는데, 현재 디버깅 중인 함수가 어떤 순서로 호출되었는지와 실행 공간을 어떻게 확인할 수 있나요? [answer] | Call Stack 패널은 현재 디버깅 중인 함수가 어디서부터 호출되었는지를 확인하는 데 사용됩니다. 내비게이션 메뉴의 **Panels - Debug - Call Stack**을 클릭해 엽니다. Call Stack을 열면, `Method3` 내부를 디버깅 중일 때 `OnBeginPlay` 함수를 시작으로 `Method1`, `Method2`를 거쳐 `Method3`까지 호출된 순서와 실행 공간을 확인할 수 있습니다. 이를 통해 함수 호출의 흐름과 각 함수가 어떤 실행 공간(server, client 등)에서 실행되고 있는지 파악할 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 중단점을 설정한 코드를 확인했을 때 문제가 없다면, 혹은 해당 코드 아래 줄의 상태도 함께 확인하고 싶다면 어떻게 해야 할까요? 확인하고자 하는 모든 코드 라인에 중단점을 설정할 수도 없고, 매번 디버그 시작/중지를 반복하며 중단점 설정 해제를 반복하는 것도 비효율적입니다. 디버깅 중 중단점에서 플레이가 멈춘 뒤, 중단점이 설정된 라인 이후로 코드를 실행하는 방법이 있습니다. **프로시저 단위 실행**, **한 단계씩 코드 실행** 등을 통해 단위별로 코드를 실행하며 코드의 상태나 흐름을 파악할 수 있습니다. 단위별 코드 실행은 디
[task] | single_turn [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | _spawnService:SpawnByModelId 호출 시 모델의 Entry ID를 Workspace에 추가하지 않으면 어떤 문제가 발생하나요? [answer] | `_SpawnService:SpawnByModelId` 함수를 호출할 때 모델의 Entry ID를 Workspace에 추가하지 않으면, 해당 모델을 기반으로 한 엔티티를 생성할 수 없습니다. 이 함수는 엔티티로 생성할 모델이 반드시 Workspace에 추가되어 있어야 하며, 추가된 모델의 Entry ID를 매개 변수로 받아 동작합니다. 따라서 Workspace에 존재하지 않는 Entry ID를 사용하면 정상적으로 스폰되지 않습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이제 스크립트를 통해 몬스터 스폰 기능을 만들어보겠습니다. 우선은 특정 좌표에 몬스터를 스폰해 보고 점차 기능을 확장해 봅시다. 1. 새 스크립트 컴포넌트 **MonsterSpawn**을 생성합니다. 2. **MonsterSpawn** 스크립트를 열어 `SpawnMonster()` 함수를 추가합니다. 3. `SpawnMonster()` 함수를 다음과 같이 작성합니다. ```lua void SpawnMonster() { local parent = _EntityServ
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 점프대 만들기 [question] | TriggerComponent를 확장하여 충돌 시 캐릭터에게 힘을 가하는 기능을 구현하는 절차를 단계별 번호 목록으로 정리하세요. [answer] | TriggerComponent를 확장하여 충돌 시 캐릭터에게 힘을 가하는 기능을 구현하는 절차는 다음과 같습니다. 1. **Preset List에서 스프링 모델 배치하기** - Preset List에서 스프링 모양의 모델(`object-4575`)을 찾아 맵에 배치합니다. 2. **TriggerComponent 확장하여 Spring 스크립트 생성하기** - Workspace에서 `TriggerComponent`를 검색합니다. - `TriggerComponent`의 콘텍스트 메뉴에서 **Extend**를 클릭합니다 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 점프대에 닿으면 캐릭터가 높이 솟아오르는 점프대를 만들어 봅니다. 이번 예제를 통해 확장 스크립트 작성법과 스크립트를 통해 물체와의 충돌 및 충돌 시 처리, 그리고 물체에 물리적인 힘을 가하는 방법에 대해 알아봅니다. 추가로 컴포넌트에 프로퍼티를 추가하고, 오브젝트별로 다른 프로퍼티 값을 설정하는 방법을 알아봅니다. # 점프대 배치하기 1. **Preset List**에서 스프링 모양의 모델(object-4575)을 찾아 맵에 배치합니다. # TriggerComponent로 충돌 기능 활용하기 물체와
[task] | single_turn [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | Copy Entry ID로 복사한 값에 model:// 접두사가 포함되어 있어도 스크립트에서 정상적으로 작동하나요? [answer] | 네, `model://` 접두사가 포함되어 있어도 정상적으로 작동합니다. 참고 문서에 따르면, `Copy Entry ID`를 통해 복사한 값의 `model://` 부분을 삭제하더라도 정상 작동한다고 명시되어 있습니다. 이는 `model://` 접두사가 있어도 없이도 `_SpawnService:SpawnByModelId` 함수가 해당 모델 ID를 인식하여 스폰할 수 있음을 의미합니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이제 스크립트를 통해 몬스터 스폰 기능을 만들어보겠습니다. 우선은 특정 좌표에 몬스터를 스폰해 보고 점차 기능을 확장해 봅시다. 1. 새 스크립트 컴포넌트 **MonsterSpawn**을 생성합니다. 2. **MonsterSpawn** 스크립트를 열어 `SpawnMonster()` 함수를 추가합니다. 3. `SpawnMonster()` 함수를 다음과 같이 작성합니다. ```lua void SpawnMonster() { local parent = _EntityServ
[task] | code [pass] | ⏳ 미판정 [title] | Entity Event System [question] | SunriseEvent를 map01 엔티티를 통해 중계하도록 HunterComponent와 VampireComponent의 이벤트 핸들러 설정을 작성해줘: 두 컴포넌트 모두 [entity: map01(/maps/map01)] 경로로 지정된 HandlerSunriseEvent(SunriseEvent event) 핸들러를 구현하여 event.isSunrise 값을 각자의 self.isSunrise 프로퍼티에 저장한다. [answer] | 요청하신 `HunterComponent`와 `VampireComponent`의 `SunriseEvent` 핸들러 설정은 아래 코드와 같습니다. 두 컴포넌트 모두 이벤트 중계자를 `map01` 엔티티(`/maps/map01`)로 지정하고, 이벤트의 `isSunrise` 값을 각자의 `isSunrise` 프로퍼티에 저장하도록 구현되어 있습니다. ```lua Property: [Sync] boolean isSunrise = false [Sync] number Hp = 0 Method: [server only] void OnUpdate [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | **HunterComponent**, **VampireComponent** 스크립트를 작성해 봅시다. 우선 두 컴포넌트 모두 **SunriseEvent**를 받도록 해야 합니다. 1. **HunterComponent**, **VampireComponent** 스크립트를 엽니다. **Event Handler**에서 **[+]** 버튼을 누르고, **SunriseEvent**를 추가합니다. 2. **SunriseEvent**의 중계 엔티티를 **map01**으로 설정해야 합니다. 다음과 같이 핸들러 상단의 이벤트 중계자를 **ma
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스크립트 디버그 [question] | F10과 F11을 사용해서 코드를 한 줄씩 실행할 때, 포커싱된 라인에 함수가 있는 경우 두 버튼의 동작 방식은 어떻게 다른가요? [answer] | F10(프로시저 단위 실행)과 F11(한 단계씩 코드 실행)은 모두 코드를 한 줄씩 실행하지만, 포커싱된 라인에 함수가 있을 때의 동작 방식이 다릅니다. * **F10 (프로시저 단위 실행)**: 포커싱된 라인에 함수가 있으면 해당 함수를 실행한 것으로 간주하고, 함수 내부로 들어가지 않고 바로 **다음 줄**로 넘어갑니다. * **F11 (한 단계씩 코드 실행)**: 포커싱된 라인에 함수가 있으면 해당 함수 **내부로 들어가서** 함수 내 코드를 한 줄씩 실행합니다. 즉, F10은 함수를 하나의 블랙박스로 보고 건너뛰는 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 중단점을 설정한 코드를 확인했을 때 문제가 없다면, 혹은 해당 코드 아래 줄의 상태도 함께 확인하고 싶다면 어떻게 해야 할까요? 확인하고자 하는 모든 코드 라인에 중단점을 설정할 수도 없고, 매번 디버그 시작/중지를 반복하며 중단점 설정 해제를 반복하는 것도 비효율적입니다. 디버깅 중 중단점에서 플레이가 멈춘 뒤, 중단점이 설정된 라인 이후로 코드를 실행하는 방법이 있습니다. **프로시저 단위 실행**, **한 단계씩 코드 실행** 등을 통해 단위별로 코드를 실행하며 코드의 상태나 흐름을 파악할 수 있습니다. 단위별 코드 실행은 디
[task] | code [pass] | ⏳ 미판정 [title] | Entity Event System [question] | 해가 뜨면 헌터는 체력이 200까지 증가하고 뱀파이어는 체력이 0까지 감소하도록 동작하는 HunterComponent와 VampireComponent의 서버 사이드 로직을 작성해줘: [server Only] OnUpdate(number delta)에서 self.isSunrise가 true일 때 HunterComponent는 self.Hp를 delta만큼 증가시켜 200 초과 시 200으로 고정하고, VampireComponent는 self.Hp를 delta만큼 감소시켜 0 미만 시 0으로 고정하며 각각의 현재 Hp 값을 log()로 [answer] | 요청하신 `HunterComponent`와 `VampireComponent`의 서버 사이드 로직을 포함한 전체 스크립트는 다음과 같습니다. 두 컴포넌트 모두 `SunriseEvent`를 수신하여 `isSunrise` 상태를 관리하고, `OnUpdate`에서 해당 상태에 따라 HP를 증감 처리합니다. ### HunterComponent ```lua Property: [Sync] boolean isSunrise = false [Sync] number Hp = 0 Method: [server only] void OnUpdate(n [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | **HunterComponent**, **VampireComponent** 스크립트를 작성해 봅시다. 우선 두 컴포넌트 모두 **SunriseEvent**를 받도록 해야 합니다. 1. **HunterComponent**, **VampireComponent** 스크립트를 엽니다. **Event Handler**에서 **[+]** 버튼을 누르고, **SunriseEvent**를 추가합니다. 2. **SunriseEvent**의 중계 엔티티를 **map01**으로 설정해야 합니다. 다음과 같이 핸들러 상단의 이벤트 중계자를 **ma
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | GetRandomPosition 함수의 매개변수 spawnCount 타입과 리턴 타입을 10자 이내로 간결하게 설명하세요. [answer] | 매개변수: number, 리턴: table [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이번에는 5초마다 한 마리씩 스폰하는 것이 아니라, 5초마다 현재 몬스터 수량을 체크하여 최대 몬스터 수량보다 부족한 만큼 생성하도록 수정해 봅시다. 1. **MonsterSpawn**의 `GetRandomPosition()` 함수에 매개 변수를 하나 추가합니다. 2. 매개 변수 타입은 **number**로, 이름은 **spawnCount**로 설정하고, 리턴 타입을 **table**로 변경합니다. 함수는 다음과 같이 수정합니다. ```lua table GetRandomPosition(nu
[task] | code [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | OnBeginPlay() 에서 초기 몬스터를 스폰하고 이후 주기적으로 스폰 규칙을 체크하는 생명주기 메서드를 설정하는 스크립트를 작성해줘 [answer] | 제시된 참고 문서에는 `OnBeginPlay()`에서 초기 몬스터를 스폰하거나, 주기적으로 스폰 규칙(맵 내 몬스터 수 체크, 부족한 수량만큼 리스폰 등)을 체크하는 구체적인 mLua 코드 예제나 관련 API 사용법이 포함되어 있지 않습니다. 문서에는 `_TimerService:SetTimer`와 `_TimerService:SetTimerOnce`를 사용하여 타이머를 설정하는 예제와, `OnUpdate`에서 드랍 아이템 처리를 하는 로직만 제시되어 있을 뿐, 몬스터 스폰 서비스(예: `_SpawnService` 등)를 이용해 몬스 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 몬스터를 스폰한 뒤, 몬스터를 처치하면 아이템을 드랍하고 이 아이템을 인벤토리에 저장하는 일련의 과정을 구현해 봅시다. > 본 가이드는 아래의 순서로 이어지는 과정입니다. > **▶ 1편.** [**몬스터를 스폰해보자**](/docs?postId=204) > 2편. [몬스터 드랍 아이템과 인벤토리 UI 만들기](/docs?postId=943) > 3편. [인벤토리 스크립트 작성하기](/docs?postId=942) > 4편. [인벤토리 UI 스크립트 작성하기](/docs?postId=946) > 5편. [아이템
[task] | single_turn [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | _spawnService:SpawnByModelId의 네 번째 인자인 parent에 엔티티를 전달하지 않으면 몬스터가 어디에 생성되나요? [answer] | 제공된 참고 문서에는 `_SpawnService:SpawnByModelId` 함수의 네 번째 인자인 `parent`에 엔티티를 전달하지 않았을 때의 동작(기본 생성 위치 또는 루트 엔티티 연결 여부)에 대한 정보가 포함되어 있지 않습니다. 문서에는 `parent` 인자를 사용하여 특정 엔티티(예: `/maps/map01` 또는 다른 스폰된 엔티티)를 부모로 지정하는 방법만 설명되어 있으며, 해당 인자를 생략했을 때의 세부 동작은 언급되어 있지 않습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이제 스크립트를 통해 몬스터 스폰 기능을 만들어보겠습니다. 우선은 특정 좌표에 몬스터를 스폰해 보고 점차 기능을 확장해 봅시다. 1. 새 스크립트 컴포넌트 **MonsterSpawn**을 생성합니다. 2. **MonsterSpawn** 스크립트를 열어 `SpawnMonster()` 함수를 추가합니다. 3. `SpawnMonster()` 함수를 다음과 같이 작성합니다. ```lua void SpawnMonster() { local parent = _EntityServ
[task] | single_turn [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | OnBeginPlay 함수 내에서 self:SpawnMonster()를 호출할 때 [server only] 속성이 왜 필요한가요? [answer] | `[server only]` 속성이 필요한 이유는 `_SpawnService:SpawnByModelId`와 같은 엔티티 생성(스폰) 기능이 서버에서만 실행되어야 하기 때문입니다. 메이플스토리 월드에서 몬스터를 스폰하는 `_SpawnService`의 메서드는 서버 측 로직으로 처리됩니다. 따라서 `SpawnMonster()` 함수 내에서 `_SpawnService`를 호출하려면, 이 함수를 호출하는 진입점인 `OnBeginPlay()`에 `[server only]` 속성을 부여하여 서버 환경에서만 실행되도록 명시해야 합니다. 참고 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이제 스크립트를 통해 몬스터 스폰 기능을 만들어보겠습니다. 우선은 특정 좌표에 몬스터를 스폰해 보고 점차 기능을 확장해 봅시다. 1. 새 스크립트 컴포넌트 **MonsterSpawn**을 생성합니다. 2. **MonsterSpawn** 스크립트를 열어 `SpawnMonster()` 함수를 추가합니다. 3. `SpawnMonster()` 함수를 다음과 같이 작성합니다. ```lua void SpawnMonster() { local parent = _EntityServ
[task] | two_turn [pass] | ⏳ 미판정 [title] | 점프대 만들기 [question] | TriggerComponent를 확장하여 충돌 시 특정 액션을 처리하는 확장 스크립트 작성 방법은 무엇인가요? [answer] | `TriggerComponent`를 확장하여 충돌 시 특정 액션을 처리하는 확장 스크립트를 작성하는 과정은 다음과 같습니다. **1. 확장 스크립트 생성** 1. **Workspace**에서 `TriggerComponent`를 검색합니다. 2. `TriggerComponent`의 컨텍스트 메뉴에서 **Extend**를 클릭합니다. 3. 새 스크립트 컴포넌트 이름을 설정합니다(예: `Spring`). 4. 생성된 스크립트를 더블 클릭하여 스크립트 에디터를 엽니다. **2. 충돌 이벤트 처리 메서드 작성** 충돌 감지 이벤트가 발생 [followup] | Spring 스크립트에서 OnEnterTriggerBody 함수가 충돌한 대상이 아닌 일반 오브젝트일 때 nil 체크 로직이 어떻게 동작하며, SetForce의 값이 음수일 경우 어떤 물리 효과가 발생하나요? [followup_answer] | Spring 스크립트의 `OnEnterTriggerBody` 함수에서 nil 체크 로직과 `SetForce`의 음수 값이 갖는 물리 효과는 다음과 같이 동작합니다. **1. nil 체크 로직 동작** 함수 내부에서 충돌한 대상(`enterEvent.TriggerBodyEntity`)의 `RigidbodyComponent`와 `PlayerControllerComponent`를 각각 조회합니다. * **RigidbodyComponent 확인**: `local rigidbody = player.RigidbodyComponent`로 [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 점프대에 닿으면 캐릭터가 높이 솟아오르는 점프대를 만들어 봅니다. 이번 예제를 통해 확장 스크립트 작성법과 스크립트를 통해 물체와의 충돌 및 충돌 시 처리, 그리고 물체에 물리적인 힘을 가하는 방법에 대해 알아봅니다. 추가로 컴포넌트에 프로퍼티를 추가하고, 오브젝트별로 다른 프로퍼티 값을 설정하는 방법을 알아봅니다. # 점프대 배치하기 1. **Preset List**에서 스프링 모양의 모델(object-4575)을 찾아 맵에 배치합니다. # TriggerComponent로 충돌 기능 활용하기 물체와
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스크립트 디버그 [question] | 디버깅 중 특정 변수의 값이 어떻게 변하는지 계속 마우스 오버로 확인하는 대신, 더 효율적으로 추적할 수 있는 기능은 무엇이며 어디서 열 수 있나요? [answer] | 디버깅 중 특정 변수나 프로퍼티의 값 변화를 효율적으로 추적하기 위해 **Watch Expression** 기능을 사용할 수 있습니다. 이 패널을 열려면 내비게이션 메뉴에서 **Panels - Debug - Watch Expression**을 클릭하면 됩니다. **사용 방법:** 1. 디버깅을 시작하고 코드가 실행되는 상태에서 **Watch Expression** 패널의 **Add Expression** 입력창에 추적할 대상의 이름을 입력합니다. - **함수 내부의 로컬 변수**인 경우: 변수 이름 그대로 입력 (예: `t [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 중단점을 설정한 코드를 확인했을 때 문제가 없다면, 혹은 해당 코드 아래 줄의 상태도 함께 확인하고 싶다면 어떻게 해야 할까요? 확인하고자 하는 모든 코드 라인에 중단점을 설정할 수도 없고, 매번 디버그 시작/중지를 반복하며 중단점 설정 해제를 반복하는 것도 비효율적입니다. 디버깅 중 중단점에서 플레이가 멈춘 뒤, 중단점이 설정된 라인 이후로 코드를 실행하는 방법이 있습니다. **프로시저 단위 실행**, **한 단계씩 코드 실행** 등을 통해 단위별로 코드를 실행하며 코드의 상태나 흐름을 파악할 수 있습니다. 단위별 코드 실행은 디
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 프로퍼티 [question] | 문서에 제시된 각 타입의 코드 예시에서 초깃값과 최종 log 출력값이 일치하는지 3문장 이내로 검증하세요. [answer] | string, number, integer, boolean의 네 가지 예시 모두 초깃값과 연산 로직을 따랐을 때 최종 log 출력값과 정확히 일치합니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 이번 과정에서는 메이플스토리 월드의 프로퍼티가 무엇인지 알아봅니다. 또한 프로퍼티 선언 및 초깃값 설정, 프로퍼티 동기화 방법 등 프로퍼티 관련 정보를 살펴보겠습니다. # MSW의 프로퍼티 프로퍼티는 컴포넌트의 멤버 변수로써, 엔티티 별로 다른 값을 가질 수 있습니다. 프로퍼티는 세 가지 특징이 있습니다. * 루아 변수와 달리 메이플스토리 월드의 프로퍼티는 선언할 때 타입을 설정하고, 값을 대입하거나 참조할 수 있습니다. * 컴포넌트 내 외부에서 프로퍼티에 접근할 수 있고, 각 함수에서 값을 읽거나 쓸 수
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점프대 만들기 [question] | TriggerComponent의 OnEnterTriggerBody 이벤트는 캐릭터가 점프대 영역에 들어갈 때만 발생하고, 이미 안에 있는 상태에서 벗어나거나 다시 들어오는 상황에서는 처리되지 않는 건가요? [answer] | 제시된 참고 문서에는 `TriggerComponent`의 `OnEnterTriggerBody` 이벤트가 **캐릭터가 점프대 영역에 "들어갈 때"만** 발생한다는 내용만 명시되어 있습니다. 문서에는 이미 안에 있는 상태에서 벗어나거나(`Exit`), 다시 들어오는 상황(`Re-enter`)에 대한 별도의 이벤트 처리나 동작 방식에 대한 정보가 포함되어 있지 않습니다. 따라서 해당 상황에서의 구체적인 동작 여부는 문서 근거로 답변할 수 없습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 점프대에 닿으면 캐릭터가 높이 솟아오르는 점프대를 만들어 봅니다. 이번 예제를 통해 확장 스크립트 작성법과 스크립트를 통해 물체와의 충돌 및 충돌 시 처리, 그리고 물체에 물리적인 힘을 가하는 방법에 대해 알아봅니다. 추가로 컴포넌트에 프로퍼티를 추가하고, 오브젝트별로 다른 프로퍼티 값을 설정하는 방법을 알아봅니다. # 점프대 배치하기 1. **Preset List**에서 스프링 모양의 모델(object-4575)을 찾아 맵에 배치합니다. # TriggerComponent로 충돌 기능 활용하기 물체와
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | SpawnMonster 함수 내에서 MonsterArray에 새 몬스터를 저장할 때 사용되는 인덱스 계산 로직을 코드만 출력하고 설명은 주석으로 작성하세요. [answer] | ```lua local nextNum = #self.MonsterArray + 1 -- 현재 MonsterArray의 길이에서 1을 더하여 새 몬스터를 저장할 인덱스를 계산합니다. self.MonsterArray[nextNum] = _SpawnService:SpawnByModelId( "Entry ID", "SpawnedMonster", positions[i], parent) ``` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이번에는 5초마다 한 마리씩 스폰하는 것이 아니라, 5초마다 현재 몬스터 수량을 체크하여 최대 몬스터 수량보다 부족한 만큼 생성하도록 수정해 봅시다. 1. **MonsterSpawn**의 `GetRandomPosition()` 함수에 매개 변수를 하나 추가합니다. 2. 매개 변수 타입은 **number**로, 이름은 **spawnCount**로 설정하고, 리턴 타입을 **table**로 변경합니다. 함수는 다음과 같이 수정합니다. ```lua table GetRandomPosition(nu
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 프로퍼티 [question] | 프로퍼티 선언 시 필수로 설정해야 하는 4가지 항목을 단계별 번호 목록으로 나열하세요. [answer] | 프로퍼티를 선언할 때 필수로 설정해야 하는 4가지 항목은 다음과 같습니다. 1. 프로퍼티 이름 2. 타입 3. 초깃값 4. 서버-클라이언트 간 동기화 여부 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 이번 과정에서는 메이플스토리 월드의 프로퍼티가 무엇인지 알아봅니다. 또한 프로퍼티 선언 및 초깃값 설정, 프로퍼티 동기화 방법 등 프로퍼티 관련 정보를 살펴보겠습니다. # MSW의 프로퍼티 프로퍼티는 컴포넌트의 멤버 변수로써, 엔티티 별로 다른 값을 가질 수 있습니다. 프로퍼티는 세 가지 특징이 있습니다. * 루아 변수와 달리 메이플스토리 월드의 프로퍼티는 선언할 때 타입을 설정하고, 값을 대입하거나 참조할 수 있습니다. * 컴포넌트 내 외부에서 프로퍼티에 접근할 수 있고, 각 함수에서 값을 읽거나 쓸 수
[task] | code [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | 지정된 영역 내에서 랜덤한 Vector3 좌표를 생성하여 _SpawnService 에 전달하는 로직을 구현하는 스크립트를 작성해줘 [answer] | 제공된 문서에는 `_SpawnService`를 통해 몬스터를 스폰하는 방법(`SpawnByEntityTemplate`, `SpawnByModelId`)과 `OnBeginPlay`에서 특정 좌표(`Vector3(0,0,0)`)를 전달하는 예시는 포함되어 있습니다. 하지만, **"지정된 영역 내에서 랜덤한 Vector3 좌표를 생성하는 구체적인 API나 함수(예: Random, GetRandomVector, Area Bounds 등)"에 대한 설명은 문서에 없습니다.** 따라서 문서에 명시되지 않은 랜덤 좌표 생성 API를 지어내어 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 몬스터를 스폰한 뒤, 몬스터를 처치하면 아이템을 드랍하고 이 아이템을 인벤토리에 저장하는 일련의 과정을 구현해 봅시다. > 본 가이드는 아래의 순서로 이어지는 과정입니다. > **▶ 1편.** [**몬스터를 스폰해보자**](/docs?postId=204) > 2편. [몬스터 드랍 아이템과 인벤토리 UI 만들기](/docs?postId=943) > 3편. [인벤토리 스크립트 작성하기](/docs?postId=942) > 4편. [인벤토리 UI 스크립트 작성하기](/docs?postId=946) > 5편. [아이템
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | `GetCurMonsterCount()` 함수가 무효화된 엔티티를 제거하고 유효한 몬스터 수를 반환하는 과정을 `table.remove`와 `isvalid` 사용 예시를 포함해 3문장 이내로 설명하세요. [answer] | `GetCurMonsterCount()` 함수는 `isvalid`로 엔티티가 유효한지 확인하며, 무효화된 항목은 `table.remove`를 통해 배열에서 제거합니다. 이후 남은 유효한 몬스터 개수를 `#self.MonsterArray`로 계산하여 반환합니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이번에는 5초마다 몬스터를 한 마리씩 추가로 스폰하되, 최대 10개까지만 생성하는 기능을 만들어보겠습니다. 1. **MonsterSpawn**을 열고 프로퍼티를 추가합니다. ```lua Property: [Sync] number MaxSpawnCount = 10 [Sync] number Time = 0 [None] table MonsterArray = {} ``` 2. `OnBeginPlay()` 함수를 다음과 같이 수정합니다. ```lua
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | OnUpdate 함수에서 몬스터 스폰이 실행되기까지 충족해야 하는 조건들을 단계별 번호 목록으로 정리하세요. [answer] | `OnUpdate` 함수에서 몬스터 스폰이 실행되기 위해 충족해야 하는 조건은 다음과 같습니다. 1. `self.Time` 값이 5 이상이어야 합니다. (5초 이상 경과) 2. `self:GetCurMonsterCount()` 함수가 실행된 결과가 `nil`이 아니어야 합니다. 3. `self.MaxSpawnCount`에서 현재 몬스터 수량(`curMonsterCnt`)을 뺀 값인 `spawnCount`가 0보다 커야 합니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이번에는 5초마다 한 마리씩 스폰하는 것이 아니라, 5초마다 현재 몬스터 수량을 체크하여 최대 몬스터 수량보다 부족한 만큼 생성하도록 수정해 봅시다. 1. **MonsterSpawn**의 `GetRandomPosition()` 함수에 매개 변수를 하나 추가합니다. 2. 매개 변수 타입은 **number**로, 이름은 **spawnCount**로 설정하고, 리턴 타입을 **table**로 변경합니다. 함수는 다음과 같이 수정합니다. ```lua table GetRandomPosition(nu
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 프로퍼티 [question] | 프로퍼티의 string, number, integer, boolean 타입별 특징을 4행짜리 표로 정리하세요. [answer] | | 타입 | 특징 | | :--- | :--- | | string | 문자열 값을 받으며, `..` 연산자를 이용해 문자열을 연결할 수 있습니다. | | number | 정수, 실수 상관없이 모든 숫자 값을 받을 수 있습니다. | | integer | 정숫값을 받으며, 실숫값을 대입하면 소수부는 버리고 정수 부분만 유지됩니다. | | boolean | `true` 또는 `false` 값을 할당할 수 있습니다. | [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 이번 과정에서는 메이플스토리 월드의 프로퍼티가 무엇인지 알아봅니다. 또한 프로퍼티 선언 및 초깃값 설정, 프로퍼티 동기화 방법 등 프로퍼티 관련 정보를 살펴보겠습니다. # MSW의 프로퍼티 프로퍼티는 컴포넌트의 멤버 변수로써, 엔티티 별로 다른 값을 가질 수 있습니다. 프로퍼티는 세 가지 특징이 있습니다. * 루아 변수와 달리 메이플스토리 월드의 프로퍼티는 선언할 때 타입을 설정하고, 값을 대입하거나 참조할 수 있습니다. * 컴포넌트 내 외부에서 프로퍼티에 접근할 수 있고, 각 함수에서 값을 읽거나 쓸 수
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | 몬스터 스폰 관련 프로퍼티(`MaxSpawnCount`, `Time`, `MonsterArray`)의 선언부만 [Sync]/[None] 속성 포함하여 코드 블록으로 출력하고 설명은 주석으로 처리하세요. [answer] | ```lua Property: [Sync] number MaxSpawnCount = 10 -- 최대 스폰할 몬스터 수 [Sync] number Time = 0 -- 스폰 간격 타이머 [None] table MonsterArray = {} -- 스폰된 몬스터 엔티티를 저장하는 테이블 ``` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이번에는 5초마다 몬스터를 한 마리씩 추가로 스폰하되, 최대 10개까지만 생성하는 기능을 만들어보겠습니다. 1. **MonsterSpawn**을 열고 프로퍼티를 추가합니다. ```lua Property: [Sync] number MaxSpawnCount = 10 [Sync] number Time = 0 [None] table MonsterArray = {} ``` 2. `OnBeginPlay()` 함수를 다음과 같이 수정합니다. ```lua
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스크립트 디버그 [question] | 중단점에서 멈춘 상태에서 다음 중단점까지 이동하는 F5 단축키와, 한 단계씩 코드 실행하는 F11 단축키의 차이점은 무엇인가요? [answer] | 중단점에서 멈춘 상태에서 **F5(다음 중단점까지 이동)** 와 **F11(한 단계씩 코드 실행)** 의 주요 차이점은 다음과 같습니다. 1. **실행 범위**: * **F5 (다음 중단점까지 이동)**: 현재 라인에서 **다음으로 설정된 중단점 라인까지** 있는 모든 코드를 연속으로 실행합니다. 중간에 다른 중단점이 없다면 프로시저(함수)가 끝나거나 스크립트가 끝날 때까지 실행될 수 있습니다. * **F11 (한 단계씩 코드 실행)**: 코드를 **한 줄씩만** 실행합니다. 다음 줄로 넘어가기 전에 다시 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 중단점을 설정한 코드를 확인했을 때 문제가 없다면, 혹은 해당 코드 아래 줄의 상태도 함께 확인하고 싶다면 어떻게 해야 할까요? 확인하고자 하는 모든 코드 라인에 중단점을 설정할 수도 없고, 매번 디버그 시작/중지를 반복하며 중단점 설정 해제를 반복하는 것도 비효율적입니다. 디버깅 중 중단점에서 플레이가 멈춘 뒤, 중단점이 설정된 라인 이후로 코드를 실행하는 방법이 있습니다. **프로시저 단위 실행**, **한 단계씩 코드 실행** 등을 통해 단위별로 코드를 실행하며 코드의 상태나 흐름을 파악할 수 있습니다. 단위별 코드 실행은 디
[task] | two_turn [pass] | ⏳ 미판정 [title] | 프로퍼티 [question] | 메이플스토리 월드에서 프로퍼티의 주요 특징과 루아 변수와의 차이점에 대해 설명해 주세요. [answer] | 메이플스토리 월드에서 프로퍼티는 컴포넌트의 멤버 변수로써, 엔티티별로 서로 다른 값을 가질 수 있습니다. 프로퍼티는 일반적인 루아 변수와 비교했을 때 다음 세 가지 주요 특징과 차이점을 가지고 있습니다. 1. **타입 지정 필수**: 루아 변수와 달리 메이플스토리 월드의 프로퍼티는 선언 시점에 반드시 타입을 설정해야 합니다. 이는 프로퍼티 값의 전달과 동기화를 위해 필수적인 과정입니다. 2. **외부 접근 가능**: 컴포넌트 내부뿐만 아니라 외부에서도 프로퍼티에 접근할 수 있습니다. 또한, 각 함수 내에서 프로퍼티의 값을 읽거나 [followup] | integer 타입의 프로퍼티에 실숫값을 대입했을 때 소수부가 어떻게 처리되는지 코드 예시로 확인하고 싶습니다. [followup_answer] | integer 타입의 프로퍼티에 실숫값을 대입하면 소수부가 버려지고 정수 부분만 저장됩니다. 예를 들어 3.28을 대입하면 3이 저장됩니다. 다음은 이를 확인할 수 있는 mLua 코드 예제입니다. ```lua Property: [Sync] integer IntegerProperty = 100 Method: [Server Only] void OnBeginPlay() { self.IntegerProperty = self.IntegerProperty + 83 log(self.IntegerProperty) --콘솔 창에 [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 이번 과정에서는 메이플스토리 월드의 프로퍼티가 무엇인지 알아봅니다. 또한 프로퍼티 선언 및 초깃값 설정, 프로퍼티 동기화 방법 등 프로퍼티 관련 정보를 살펴보겠습니다. # MSW의 프로퍼티 프로퍼티는 컴포넌트의 멤버 변수로써, 엔티티 별로 다른 값을 가질 수 있습니다. 프로퍼티는 세 가지 특징이 있습니다. * 루아 변수와 달리 메이플스토리 월드의 프로퍼티는 선언할 때 타입을 설정하고, 값을 대입하거나 참조할 수 있습니다. * 컴포넌트 내 외부에서 프로퍼티에 접근할 수 있고, 각 함수에서 값을 읽거나 쓸 수