[task] | single_turn [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | KeyDownEvent 핸들러를 추가할 때 InputService를 지정하지 않으면 왜 이벤트가 발생하지 않나요? [answer] | mLua 스크립트에서 이벤트 핸들러는 해당 이벤트를 발생시키는 **서비스(Service)** 와 연결되어야 합니다. `KeyDownEvent`는 키 입력을 담당하는 `InputService`에서 발생시키므로, 핸들러 블록 상단에 `[service: InputService]`를 명시적으로 지정하지 않으면 스크립트 엔진이 해당 이벤트를 어떤 서비스에서 온 것인지 알 수 없어 이벤트를 수신하지 못합니다. 따라서 키 입력 이벤트를 처리하기 위해서는 반드시 `[service: InputService]` 태그를 붙여야 합니다. 예를 들어, [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 스킬 호출 기능에 앞서 간단하게 키 입력을 받는 기능을 먼저 만들어보겠습니다. 1. **Workspace**에서 새 컴포넌트를 추가하고, 이름으로 **NewSkill**을 입력합니다. 2. **NewSkill** 컴포넌트에 키 입력 이벤트를 처리할 핸들러를 추가합니다. **[+]** 버튼을 눌러 **KeyDownEvent**를 추가합니다. 3. **HandleKeyDownEvent**의 코드를 다음과 같이 작성해 줍니다. ```lua [service: InputService]
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 발판 만들기 [question] | 새로운 발판 경로를 만드는 단계를 단계별 번호 목록으로 나열하세요. [answer] | 새로운 발판 경로를 만드는 단계는 다음과 같습니다. 1. 발판으로 사용할 스프라이트를 **Scene** 패널에 배치합니다. 2. 배치한 발판 엔티티의 프로퍼티 에디터에서 **CustomFootholdComponent**를 추가합니다. 3. **edgeLists**의 **Size**에 발판 시작점 개수를 입력합니다. 4. 해당 엔티티의 콘텍스트 메뉴에서 **Edit Foothold**를 클릭합니다. 5. 생성된 시작점을 원하는 위치로 이동시킵니다. 6. 해당 엔티티의 콘텍스트 메뉴에서 **Add Point**를 클릭해 연결점을 추가 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 여러 오브젝트를 사용해 발판을 만들어 게임의 보는 재미를 풍성하게 만들어봅시다. **FootholdComponent**와 **CustomFootholdComponent** 개념과 발판 편집 방법을 소개합니다. # Foothold 모델로 발판 만들기 **Foothold** 모델을 이용해 발판을 만드는 방법입니다. 타일이 아닌 **Foothold** 모델을 이용해 다채로운 길을 만들 수 있습니다. 1. **Preset List** 패널에서 **Foothold**를 선택합니다. 2. 원하는 모델을 선택해 **S
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | PlayEffectAttached 함수를 사용할 때 localPosition에 Vector3(0,0,0)을 넣으면 부모 엔티티와 완전히 같은 위치에 생성되는 것인가요? [answer] | 네, `PlayEffectAttached` 함수를 사용할 때 `localPosition`에 `Vector3(0,0,0)`을 넣으면 이펙트는 부모 엔티티의 위치를 기준으로 오프셋이 0이므로, 부모 엔티티와 동일한 위치에 생성됩니다. 참고로 `PlayEffectAttached`의 매개변수 중 `localPosition`은 "부모 엔티티의 position을 기준으로 얼마만큼 떨어진 곳에서 호출할 것인지"를 정의하는 값입니다. 따라서 기본값인 `Vector3(0,0,0)`을 전달하면 부모 엔티티와 같은 좌표에 이펙트가 배치되는 것입니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 메이플스토리 월드에서는 메이플스토리에서 사용되었던 수많은 이펙트 리소스들을 제공하고 있습니다. 그리고 우리는 이러한 이펙트들을 적절한 시점과 위치에 호출해 줌으로써 한층 더 멋진 연출을 구사할 수 있습니다. 이번 과정에서는 특정 키를 누를 때마다 스킬 이펙트가 노출되는 예제를 진행해봄으로써 스크립트를 통해 이펙트를 호출하는 방법에 대해 알아보도록 합니다. 다음 가이드를 먼저 학습하면 이번 과정을 진행하는 데 많은 도움이 될 것입니다. [스크립트 에디터 오리엔테이션](https://mod-developers.
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | PlayEffect 함수의 마지막 boolean 파라미터가 false일 때와 true일 때의 동작 차이는 무엇인가요? [answer] | 제공된 참고 문서에는 `_EffectService:PlayEffect` 함수의 매개변수 목록이나 마지막 boolean 파라미터가 `false`와 `true`일 때의 구체적인 동작 차이에 대한 설명이 포함되어 있지 않습니다. 문서에는 Q, W, E, R 키 입력 시 해당 파라미터를 `false`로 전달하는 코드 예제만 제시되어 있을 뿐, `true` 값에 대한 동작 정의나 매개변수 의미를 설명하는 내용은 없습니다. 따라서 해당 boolean 파라미터의 차이에 대해서는 문서 근거를 바탕으로 답변할 수 없습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 위에 이어서 이번에는 각 키를 입력할 때마다 다음의 스킬 이펙트가 호출되도록 만들어보겠습니다. 우선 **_EffectService**의 함수 중 `PlayEffect` 함수를 이용해 스크립트를 작성해보겠습니다. 1. **NewSkill** 컴포넌트의 **HandleKeyDownEvent**를 다음과 같이 수정해줍니다. ```lua [service: InputService] HandleKeyDownEvent(KeyDownEvent event) { -- Parameters
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 발판 만들기 [question] | CustomFootholdComponent의 edgeLists, Size, [ 숫자 ] 속성의 의미를 표로 정리하세요. [answer] | CustomFootholdComponent의 발판 경로를 정의하는 속성의 의미는 다음과 같습니다. | 속성 이름 | 의미 및 설명 | | :--- | :--- | | **edgeLists** | 발판의 **시작점**을 의미합니다.<br>시작점을 여러 개 만들면, 하나의 엔티티에 개별 발판을 입력한 수만큼 만들 수 있습니다. | | **Size** | 발판을 이루고 있는 **점의 개수**를 의미합니다.<br>`edgeLists`의 `Size`에 입력한 값만큼 **시작점**이 생성됩니다.<br>또한, `[ 숫자 ]`의 `Size`에 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 여러 오브젝트를 사용해 발판을 만들어 게임의 보는 재미를 풍성하게 만들어봅시다. **FootholdComponent**와 **CustomFootholdComponent** 개념과 발판 편집 방법을 소개합니다. # Foothold 모델로 발판 만들기 **Foothold** 모델을 이용해 발판을 만드는 방법입니다. 타일이 아닌 **Foothold** 모델을 이용해 다채로운 길을 만들 수 있습니다. 1. **Preset List** 패널에서 **Foothold**를 선택합니다. 2. 원하는 모델을 선택해 **S
[task] | code [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | InputService 의 KeyDownEvent 를 처리하여 Q 키 입력 시 이펙트를 호출하는 NewSkill 스크립트를 작성해줘 [answer] | 참고 문서에는 `InputService`의 `KeyDownEvent`를 처리하여 키 입력을 감지하는 방법(`HandleKeyDownEvent`, `event.key`, `KeyboardKey.Q` 등)은 자세히 설명되어 있습니다. 그러나, **"이펙트를 호출하는 구체적인 API(예: `PlayEffect`, `SpawnEffect` 등)"나 이펙트와 관련된 메서드/서비스 이름은 제공된 문서에 포함되어 있지 않습니다.** 따라서, 문서에 있는 정보만 사용하여 **Q 키 입력을 감지하고 로그를 출력하는** 부분까지만 작성해 드립니다 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 스킬 호출 기능에 앞서 간단하게 키 입력을 받는 기능을 먼저 만들어보겠습니다. 1. **Workspace**에서 새 컴포넌트를 추가하고, 이름으로 **NewSkill**을 입력합니다. 2. **NewSkill** 컴포넌트에 키 입력 이벤트를 처리할 핸들러를 추가합니다. **[+]** 버튼을 눌러 **KeyDownEvent**를 추가합니다. 3. **HandleKeyDownEvent**의 코드를 다음과 같이 작성해 줍니다. ```lua [service: InputService]
[task] | code [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | InputService 의 KeyDownEvent 를 처리하여 R 키 입력 시 이펙트를 호출하는 NewSkill 스크립트를 작성해줘 [answer] | 사용자가 요청한 `NewSkill` 스크립트는 `InputService`의 `KeyDownEvent`를 처리하여 **R 키**가 입력될 때 이펙트를 호출하도록 작성합니다. 참고 문서에는 키 입력 감지 로직(`HandleKeyDownEvent`)과 로컬 플레이어 체크 로직은 제공되지만, **구체적인 이펙트 생성 API(예: `_EffectService:SpawnEffect` 등)는 명시되어 있지 않습니다.** 따라서 문서에 근거하여 키 입력 처리 부분만 정확히 구현하고, 이펙트 호출 부분은 `self:SpawnEffect()`와 같 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 스킬 호출 기능에 앞서 간단하게 키 입력을 받는 기능을 먼저 만들어보겠습니다. 1. **Workspace**에서 새 컴포넌트를 추가하고, 이름으로 **NewSkill**을 입력합니다. 2. **NewSkill** 컴포넌트에 키 입력 이벤트를 처리할 핸들러를 추가합니다. **[+]** 버튼을 눌러 **KeyDownEvent**를 추가합니다. 3. **HandleKeyDownEvent**의 코드를 다음과 같이 작성해 줍니다. ```lua [service: InputService]
[task] | code [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | InputService 의 KeyDownEvent 를 처리하여 W 키 입력 시 이펙트를 호출하는 NewSkill 스크립트를 작성해줘 [answer] | 제공된 참고 문서에는 `InputService`의 `KeyDownEvent`를 사용하여 키 입력을 감지하는 방법과, 특정 키가 눌렸을 때 로그를 출력하거나 자체 메서드를 호출하는 구조가 명시되어 있습니다. 하지만, **이펙트를 실제로 생성하거나 호출하는 API(예: `SpawnEffect`, `PlayEffect` 등)에 대한 구체적인 함수명이나 사용법이 문서에 포함되어 있지 않습니다.** 따라서 "이펙트를 호출"하는 구체적인 코드 부분은 문서에 근거하여 작성할 수 없으며, 문서에 있는 정보로는 불가능합니다. 대신, 문서에 나와 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 스킬 호출 기능에 앞서 간단하게 키 입력을 받는 기능을 먼저 만들어보겠습니다. 1. **Workspace**에서 새 컴포넌트를 추가하고, 이름으로 **NewSkill**을 입력합니다. 2. **NewSkill** 컴포넌트에 키 입력 이벤트를 처리할 핸들러를 추가합니다. **[+]** 버튼을 눌러 **KeyDownEvent**를 추가합니다. 3. **HandleKeyDownEvent**의 코드를 다음과 같이 작성해 줍니다. ```lua [service: InputService]
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | `PlayEffect`와 `PlayEffectAttached`의 차이점을 스킬 이펙트 적용 관점에서 3문장 이내로 설명하세요. [answer] | `PlayEffect`는 지정된 위치에 이펙트를 고정시켜 버프 등 캐릭터와 항상 함께 있어야 하는 스킬에는 적합하지 않습니다. 반면 `PlayEffectAttached`는 특정 엔티티를 부모로 지정하여 이펙트가 캐릭터와 함께 이동하도록 붙여 놓을 수 있습니다. 따라서 캐릭터 이동 시 이펙트가 분리되지 않도록 하려면 `PlayEffectAttached`를 사용해야 합니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 위에서 살펴본 이펙트 호출 방법은 사실 스킬 이펙트에 적합한 방법은 아닙니다. 위의 예제처럼 구현하면 Q, W, E, R 키를 누른 후 캐릭터를 이동할 때 캐릭터가 이펙트를 벗어나 이동하게 됩니다. `PlayEffect`는 위에서 잠깐 언급한 것처럼 고정된 위치에 이펙트를 호출하는데 적합한 함수이기 때문에 버프류 스킬과 같이 항상 캐릭터 위에 떠 있어야 할 이펙트에는 적합하지 않습니다. 따라서 이러한 경우에 사용하는 함수가 바로 `PlayEffectAttached` 함수입니다. `PlayEffectAttached`의 경우 이펙트가
[task] | code [pass] | ⏳ 미판정 [title] | 데이터 편집 [question] | DataService:GetTable로 "NewDataSet"을 가져와 3행 2열의 셀 값을 추출하고, 해당 값이 "Start"와 동일할 경우 log 함수로 "게임 시작" 메시지를 출력하는 [server only] 스크립트를 작성해줘. [answer] | 요청하신 조건에 맞는 mLua 스크립트는 다음과 같습니다. ```lua Method: [server only] void OnBeginPlay() { local dataSet = _DataService:GetTable("NewDataSet") local cellValue = dataSet:GetCell(3, 2) if cellValue == "Start" then log("게임 시작") end } ``` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 데이터 셋을 이용해 데이터를 추가하거나 수정할 수 있습니다. 이번 가이드에서는 데이터의 생성 및 편집 방법, 스크립트로 데이터를 불러오는 방법에 대해 알아봅니다. # 데이터 셋 생성 및 데이터 에디터 열기 1. **Workspace - MyDesk**의 콘텍스트 메뉴에서 **Create DataSet**을 클릭합니다. 2. 생성된 데이터를 더블클릭하여 데이터 에디터를 엽니다. # 데이터 에디터 | 번호 | 설명 | | --- | --- | | | **컬럼 셀** 각 열의 데이터명, 즉 컬럼 명을 정의합
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 플레이어 카메라 제어 [question] | DeadZone과 SoftZone의 차이를 3문장 이내로 설명하세요. [answer] | DeadZone은 플레이어 아바타가 이동해도 카메라가 따라가지 않는 영역입니다. SoftZone은 DeadZone 바깥에 위치하며, 플레이어 아바타가 이 영역에 있으면 카메라가 화면 밖으로 벗어나지 않도록 추적하기 시작합니다. SoftZone 바깥으로 완전히 이동하면 카메라는 더 빠른 움직임으로 플레이어 아바타를 따라갑니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 게임의 메인 카메라는 항상 플레이어를 따라다닙니다. 메인 카메라를 제어하는 camera 컴포넌트는 MapleStoryPlayer 모델이 가지고 있으며 이 모델의 프로퍼티 에디터나 스크립트를 이용해 주요 값을 수정할 수 있습니다. 이번 과정에서는 Camera 컴포넌트를 프로퍼티 에디터를 통해 수정해보며 전반적인 기능을 알아보는 시간을 가져보도록 하겠습니다. # Camera 컴포넌트 접근 Workspace에서 DefaultPlayer 모델을 선택합니다. 프로퍼티 에디터에서 CameraComponent를 확인
[task] | code [pass] | ⏳ 미판정 [title] | 데이터 편집 [question] | DataService:GetTable을 사용해 "NewDataSet"의 2행 전체(1열~3열) 데이터를 조회하고, 각 셀의 값을 문자열로 연결하여 한 줄로 출력하는 [server only] 스크립트를 작성해줘. [answer] | ```lua Method: [server only] void OnBeginPlay() { local dataSet = _DataService:GetTable("NewDataSet") local row = 2 local cell1 = dataSet:GetCell(row, 1) local cell2 = dataSet:GetCell(row, 2) local cell3 = dataSet:GetCell(row, 3) log(tostring(cell1) .. ", " .. tostr [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 데이터 셋을 이용해 데이터를 추가하거나 수정할 수 있습니다. 이번 가이드에서는 데이터의 생성 및 편집 방법, 스크립트로 데이터를 불러오는 방법에 대해 알아봅니다. # 데이터 셋 생성 및 데이터 에디터 열기 1. **Workspace - MyDesk**의 콘텍스트 메뉴에서 **Create DataSet**을 클릭합니다. 2. 생성된 데이터를 더블클릭하여 데이터 에디터를 엽니다. # 데이터 에디터 | 번호 | 설명 | | --- | --- | | | **컬럼 셀** 각 열의 데이터명, 즉 컬럼 명을 정의합
[task] | code [pass] | ⏳ 미판정 [title] | 데이터 편집 [question] | DataService:GetTable을 호출하여 "NewDataSet" 데이터를 불러온 후, 1행 1열부터 5행 1열까지의 값을 순회하며 콘솔에 출력하는 [server only] 스크립트를 작성해줘. [answer] | `_DataService:GetTable("NewDataSet")`를 통해 데이터 테이블을 가져온 후, `GetRowCount()` 또는 직접 1부터 5까지 반복문을 돌리며 1열의 값을 `GetCell()`로 조회하고 `log()`로 출력하는 스크립트입니다. ```lua Method: [server only] void OnBeginPlay() { local dataSet = _DataService:GetTable("NewDataSet") for i = 1, 5 do local cellValue [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 데이터 셋을 이용해 데이터를 추가하거나 수정할 수 있습니다. 이번 가이드에서는 데이터의 생성 및 편집 방법, 스크립트로 데이터를 불러오는 방법에 대해 알아봅니다. # 데이터 셋 생성 및 데이터 에디터 열기 1. **Workspace - MyDesk**의 콘텍스트 메뉴에서 **Create DataSet**을 클릭합니다. 2. 생성된 데이터를 더블클릭하여 데이터 에디터를 엽니다. # 데이터 에디터 | 번호 | 설명 | | --- | --- | | | **컬럼 셀** 각 열의 데이터명, 즉 컬럼 명을 정의합
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | EffectService의 PlayEffect 함수에서 두 번째 인자로 전달해야 할 Entity 값은 무엇인가요? [answer] | `_EffectService:PlayEffect` 함수의 두 번째 인자로 전달해야 할 `Entity` 값은 **이펙트를 부착하거나 기준점으로 사용할 엔티티**입니다. 제공된 문서의 예제 코드에서 두 가지 경우를 확인할 수 있습니다. 1. **스스로의 엔티티 (`self.Entity`)**: 키 입력 이벤트 핸들러(`HandleKeyDownEvent`) 내에서 스크립트가 부착된 객체(예: 플레이어 캐릭터)의 현재 위치에 이펙트를 재생할 때 `self.Entity`를 전달합니다. ```lua _EffectSe [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 위에 이어서 이번에는 각 키를 입력할 때마다 다음의 스킬 이펙트가 호출되도록 만들어보겠습니다. 우선 **_EffectService**의 함수 중 `PlayEffect` 함수를 이용해 스크립트를 작성해보겠습니다. 1. **NewSkill** 컴포넌트의 **HandleKeyDownEvent**를 다음과 같이 수정해줍니다. ```lua [service: InputService] HandleKeyDownEvent(KeyDownEvent event) { -- Parameters
[task] | code [pass] | ⏳ 미판정 [title] | 데이터 편집 [question] | DataService:GetTable로 "NewDataSet"을 불러온 뒤, 4행 1열의 값을 숫자 타입으로 변환하여 10보다 크면 "PASS", 아니면 "FAIL"을 콘솔에 기록하는 [server only] 스크립트를 작성해줘. [answer] | `_DataService:GetTable`로 데이터를 불러온 뒤, 4행 1열의 셀 값을 가져와 숫자 타입으로 변환하는 로직을 작성했습니다. 가져온 값이 10보다 크면 `PASS`, 그렇지 않으면 `FAIL`을 콘솔에 출력합니다. ```lua Method: [server only] void OnBeginPlay() { local dataSet = _DataService:GetTable("NewDataSet") local cellValue = dataSet:GetCell(4, 1) local numValue = [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 데이터 셋을 이용해 데이터를 추가하거나 수정할 수 있습니다. 이번 가이드에서는 데이터의 생성 및 편집 방법, 스크립트로 데이터를 불러오는 방법에 대해 알아봅니다. # 데이터 셋 생성 및 데이터 에디터 열기 1. **Workspace - MyDesk**의 콘텍스트 메뉴에서 **Create DataSet**을 클릭합니다. 2. 생성된 데이터를 더블클릭하여 데이터 에디터를 엽니다. # 데이터 에디터 | 번호 | 설명 | | --- | --- | | | **컬럼 셀** 각 열의 데이터명, 즉 컬럼 명을 정의합
[task] | code [pass] | ⏳ 미판정 [title] | Data DB 저장 및 불러오기 [question] | _DataStorageService:GetGlobalDataStorage의 SetAsync 메서드에서 value를 문자열로 변환하여 저장하고, 이전에 같은 key로 저장된 값이 있을 경우 덮어쓰기되는 동작을 구현하는 스크립트를 작성해줘 [answer] | `_DataStorageService:GetGlobalDataStorage`를 통해 `GlobalDataStorage` 인스턴스를 가져온 뒤, `SetAsync` 메서드를 사용하면 데이터를 저장할 수 있습니다. 이 메서드는 비동기 방식으로 동작하며, 저장할 값(value)은 반드시 문자열(string) 타입으로 변환하여 전달해야 합니다. 동일한 `key` 값으로 `SetAsync`를 호출하면 이전에 저장된 데이터가 새로운 값으로 덮어쓰기됩니다. 저장 요청이 완료된 시점에 처리할 로직이 있다면 콜백 함수를 통해 구현할 수 있으며, [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 데이터의 저장은 GlobalDataStorage의 SetAsync를 활용해 할 수 있습니다. `SetAsync`는 매개 변수로 key와 value, 그리고 콜백 함수를 받는데, 저장할 데이터가 있으면 key와 value 매개 변수로 값을 넘겨 저장하게 됩니다. key는 매번 변경되어 저장되는 value 값을 불러오기 위한 용도로 사용됩니다. 따라서 key 값으로는 프로퍼티 명이나 혹은 저장된 value 값이 의미하는 것으로 입력해 주는 것이 좋습니다. 예를 들어 power라는 프로퍼티(또는 스탯)의 값을 저장한다면 key에는 "Po
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | EffectService를 호출할 때 언더스코어(_) 접두사가 붙는 이유는 무엇인가요? [answer] | mLua에서 `_EffectService`와 같이 언더스코어(`_`) 접두사가 붙는 이유는 해당 객체가 **서비스(Service)**이기 때문입니다. 메이플스토리 월드 스크립트 환경에서는 게임의 전역적인 기능(이펙트, 사운드, 엔티티 생성, 텔레포트, 사용자 정보 등)을 제공하는 시스템들을 '서비스'라고 부릅니다. 이러한 서비스 객체들은 특정 엔티티에 속한 컴포넌트가 아니라, 스크립트 어디서나 접근 가능한 전역 객체로 처리되며, 이를 구별하기 위해 이름 앞에 `_`를 붙입니다. 예를 들어, 참고 문서에서 사용된 서비스들은 다음과 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 위에 이어서 이번에는 각 키를 입력할 때마다 다음의 스킬 이펙트가 호출되도록 만들어보겠습니다. 우선 **_EffectService**의 함수 중 `PlayEffect` 함수를 이용해 스크립트를 작성해보겠습니다. 1. **NewSkill** 컴포넌트의 **HandleKeyDownEvent**를 다음과 같이 수정해줍니다. ```lua [service: InputService] HandleKeyDownEvent(KeyDownEvent event) { -- Parameters
[task] | code [pass] | ⏳ 미판정 [title] | 아이템 생성 및 삭제 [question] | TriggerEnterEvent 핸들러에서 event.TriggerBodyEntity의 InventoryComponent가 nil인지 검사하여 인벤토리가 없는 경우 즉시 리턴하고, 있는 경우에만 RedPotion, BluePotion, IronSword, IronShield, GreenShirts 중 하나를 랜덤으로 선택하여 인벤토리에 추가하는 GiftBox 스크립트를 작성해줘. [answer] | 요청하신 기능을 구현한 `GiftBox` 스크립트 컴포넌트입니다. `TriggerEnterEvent` 핸들러에서 `event.TriggerBodyEntity`의 `InventoryComponent`가 `nil`인지 검사하여 인벤토리가 없는 경우 즉시 리턴하고, 인벤토리가 있는 경우에만 지정된 아이템 목록에서 하나를 랜덤으로 선택해 `_ItemService:CreateItem`을 통해 추가하는 로직을 포함했습니다. ```lua Event Handler: [self] HandleTriggerEnterEvent(TriggerEnter [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이번에는 생성된 아이템을 표시할 인벤토리 UI를 추가합니다. 상단 메뉴에 버튼을 눌러 UI 에디터를 엽니다. **Preset List**에서 **[인벤토리]**, **[버튼모음]** UI를 추가합니다. 만일 **Inventory** 엔티티의 **UIInventory** 컴포넌트에 **InventoryBtnPath**가 비어있으면, 햄버거 메뉴를 열어 **Reset All Properties**를 선택합니다. 그러면 아래와 같이 정상적인 경로가 설정됩니다. # 아이템 엔티티 배치 및 기능 추가 버튼을 눌러 UI 편집모드를
[task] | two_turn [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | `_EffectService`의 `PlayEffect`와 `PlayEffectAttached` 함수의 매개변수 차이와 사용 시나리오를 비교해 주세요 [answer] | `_EffectService`의 `PlayEffect`와 `PlayEffectAttached` 함수는 모두 이펙트를 호출하지만, **좌표系的 기준(세계 좌표 vs 로컬 좌표)**과 **엔티티와의 연결 관계**에서 차이가 있습니다. ### 1. 매개변수 비교 | 구분 | `PlayEffect` | `PlayEffectAttached` | | :--- | :--- | :--- | | **1번째 인자** | `animationClipRUID` (이펙트 리소스 RUID) | `animationClipRUID` (이펙트 리소스 RUID) [followup] | `PlayEffectAttached`에서 `localPosition`을 0으로 설정해도 부모 엔티티의 이동에 따라 이펙트가 제대로 따라가지 않는 현상을 해결하기 위해 `isLoop` 설정이나 부모 엔티티 변경이 필요한지, 그리고 해당 문제를 해결하는 코드 예제를 작성해 주세요 [followup_answer] | 참고 문서에 따르면, `PlayEffectAttached`는 호출된 이펙트가 `parentEntity`의 **자식으로 생성**된다고 명시하고 있습니다. 따라서 `localPosition`을 `Vector3(0, 0, 0)`으로 설정하면 부모 엔티티와 **같은 위치**에 이펙트가 생성되며, 이후 부모 엔티티가 이동하거나 회전할 때 이펙트도 함께 따라가도록 설계되어 있습니다. **결론적으로, `isLoop` 설정 변경이나 부모 엔티티 변경은 이 문제(이펙트가 부모를 따라가지 않는 현상)를 해결하기 위해 필요하지 않습니다.** * [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 메이플스토리 월드에서는 메이플스토리에서 사용되었던 수많은 이펙트 리소스들을 제공하고 있습니다. 그리고 우리는 이러한 이펙트들을 적절한 시점과 위치에 호출해 줌으로써 한층 더 멋진 연출을 구사할 수 있습니다. 이번 과정에서는 특정 키를 누를 때마다 스킬 이펙트가 노출되는 예제를 진행해봄으로써 스크립트를 통해 이펙트를 호출하는 방법에 대해 알아보도록 합니다. 다음 가이드를 먼저 학습하면 이번 과정을 진행하는 데 많은 도움이 될 것입니다. [스크립트 에디터 오리엔테이션](https://mod-developers.
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | PlayEffect에서 위치를 지정할 때 Vector3(x, y, z)를 사용하는데, x와 y, z 값은 어디서 가져와야 하나요? [answer] | `_EffectService:PlayEffect`에서 위치 인자로 사용하는 `x`, `y`, `z` 값은 스크립트가 붙어 있는 엔티티의 현재 월드 좌표에서 가져옵니다. 이를 위해 `self.Entity.TransformComponent.Position`을 통해 현재 위치 벡터를 조회한 뒤, 해당 벡터의 `x`, `y`, `z` 컴포넌트를 각각 분리하여 변수에 저장하는 방식으로 구현합니다. 아래는 키 입력 시 현재 위치에 이펙트를 재생하는 `HandleKeyDownEvent` 예시입니다. ```lua Event Handler: [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 위에 이어서 이번에는 각 키를 입력할 때마다 다음의 스킬 이펙트가 호출되도록 만들어보겠습니다. 우선 **_EffectService**의 함수 중 `PlayEffect` 함수를 이용해 스크립트를 작성해보겠습니다. 1. **NewSkill** 컴포넌트의 **HandleKeyDownEvent**를 다음과 같이 수정해줍니다. ```lua [service: InputService] HandleKeyDownEvent(KeyDownEvent event) { -- Parameters
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 발판 만들기 [question] | FootholdDrag, FootholdForce, FootholdWalkSpeedFactor의 이름을 표로 정리하고 각 프로퍼티의 설명을 15자 이내로 요약하세요. [answer] | | 이름 | 설명 | | :--- | :--- | | FootholdDrag | 발판 마찰력 조절 | | FootholdForce | 좌우 방향 힘 가함 | | FootholdWalkSpeedFactor | 이동 속도 계수 조절 | [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 새롭게 만든 발판에 속성을 바꿔 크리에이터만의 독특한 발판으로 만들 수 있습니다. 각 프로퍼티 값을 조정해 특정 방향에서 나아갈 수 없는 발판, 특별히 느리게 이동하는 발판 등으로 활용해 재미를 더할 수 있습니다. | 이름 | 설명 | | --- | --- | | FootholdDrag | RigidbodyComponent가 포함된 Entity가 발판 위에 있을 때 적용되는 마찰력을 의미합니다. 값이 클수록 엔티티가 발판에서 미끌어지다 빠르게 감속해 정지합니다. 특정 지점에서 엔티티가 날아와 해당 값이 1과 10인 발판에 각각
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 발판 만들기 [question] | 발판의 시작점 선택 사항에 대해 '하나의 시작점'과 '여러 개의 시작점' 두 가지 경우의 장단점을 단계별 번호 목록으로 작성하세요. [answer] | 제공된 참고 문서에는 발판의 시작점을 '하나'로 만들지 '여러 개'로 만들지는 크리에이터의 선택 사항이라는 내용만 포함되어 있으며, 두 가지 경우의 구체적인 장단점에 대한 설명은 포함되어 있지 않습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 새롭게 만든 발판에 속성을 바꿔 크리에이터만의 독특한 발판으로 만들 수 있습니다. 각 프로퍼티 값을 조정해 특정 방향에서 나아갈 수 없는 발판, 특별히 느리게 이동하는 발판 등으로 활용해 재미를 더할 수 있습니다. | 이름 | 설명 | | --- | --- | | FootholdDrag | RigidbodyComponent가 포함된 Entity가 발판 위에 있을 때 적용되는 마찰력을 의미합니다. 값이 클수록 엔티티가 발판에서 미끌어지다 빠르게 감속해 정지합니다. 특정 지점에서 엔티티가 날아와 해당 값이 1과 10인 발판에 각각
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | 키보드 Q를 눌렀을 때 이펙트가 특정 좌표가 아닌 캐릭터 몸체에 부착되어 따라오도록 하려면 어떤 함수를 사용해야 하나요? [answer] | 키보드 Q를 눌렀을 때 이펙트가 캐릭터 몸체에 부착되어 따라오도록 하려면 `_EffectService`의 `PlayEffectAttached` 함수를 사용해야 합니다. `PlayEffect`는 지정된 좌표(`Vector3`)에 이펙트를 재생하는 반면, `PlayEffectAttached`는 특정 엔티티에 이펙트를 부착하여 엔티티의 이동과 함께 따라오게 합니다. 참고 문서에 제시된 `PlayEffect` 사용 예제와 동일한 구조로, Q 키 입력 시 `PlayEffectAttached`를 호출하는 mLua 스크립트는 다음과 같습니다 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 위에 이어서 이번에는 각 키를 입력할 때마다 다음의 스킬 이펙트가 호출되도록 만들어보겠습니다. 우선 **_EffectService**의 함수 중 `PlayEffect` 함수를 이용해 스크립트를 작성해보겠습니다. 1. **NewSkill** 컴포넌트의 **HandleKeyDownEvent**를 다음과 같이 수정해줍니다. ```lua [service: InputService] HandleKeyDownEvent(KeyDownEvent event) { -- Parameters
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 플레이어 카메라 제어 [question] | Damping, CameraOffSet, DutchAngle, Screen Offset 프로퍼티를 표로 정리해서 출력하세요. [answer] | | 프로퍼티 | 설명 | | :--- | :--- | | **Damping** | 플레이어 아바타가 데드존을 이탈하여 카메라의 빠른 움직임을 꺾어 이전과 이후를 부드럽게 이어주는 비율입니다. 이 값이 커지면 카메라가 플레이어 아바타를 추적하는 속도가 부드러워집니다. | | **CameraOffSet** | 카메라가 플레이어를 비추는 위치를 수정합니다. | | **DutchAngle** | 카메라의 회전 값을 설정합니다. 각도를 입력하여 카메라의 기울기를 조절할 수 있습니다. | | **Screen Offset** | 플레이어 아바타 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 게임의 메인 카메라는 항상 플레이어를 따라다닙니다. 메인 카메라를 제어하는 camera 컴포넌트는 MapleStoryPlayer 모델이 가지고 있으며 이 모델의 프로퍼티 에디터나 스크립트를 이용해 주요 값을 수정할 수 있습니다. 이번 과정에서는 Camera 컴포넌트를 프로퍼티 에디터를 통해 수정해보며 전반적인 기능을 알아보는 시간을 가져보도록 하겠습니다. # Camera 컴포넌트 접근 Workspace에서 DefaultPlayer 모델을 선택합니다. 프로퍼티 에디터에서 CameraComponent를 확인
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | `PlayEffectAttached` 함수의 매개변수 순서와 각 인자 값(이펙트 ID, 대상 엔티티, 위치, 회전, 스케일, 플래그)을 표로 정리하세요. [answer] | `PlayEffectAttached` 함수의 매개변수 순서와 각 인자의 의미를 아래 표와 같이 정리할 수 있습니다. | 순서 | 매개변수 | 설명 | 예시 값 | | :--- | :--- | :--- | :--- | | 1 | 이펙트 ID | 재생할 이펙트의 고유 식별자 (UUID 문자열) | `"f396262ddb6e4d5581360496bb4e9f86"` | | 2 | 대상 엔티티 | 이펙트가 부착될 부모 엔티티 (보통 `self.Entity`) | `self.Entity` | | 3 | 위치 | 대상 엔티티 기준 오프셋 위치 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 위에서 살펴본 이펙트 호출 방법은 사실 스킬 이펙트에 적합한 방법은 아닙니다. 위의 예제처럼 구현하면 Q, W, E, R 키를 누른 후 캐릭터를 이동할 때 캐릭터가 이펙트를 벗어나 이동하게 됩니다. `PlayEffect`는 위에서 잠깐 언급한 것처럼 고정된 위치에 이펙트를 호출하는데 적합한 함수이기 때문에 버프류 스킬과 같이 항상 캐릭터 위에 떠 있어야 할 이펙트에는 적합하지 않습니다. 따라서 이러한 경우에 사용하는 함수가 바로 `PlayEffectAttached` 함수입니다. `PlayEffectAttached`의 경우 이펙트가
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | 이펙트를 맵의 특정 좌표에 고정해서 호출할 때 instigator 매개변수로 어떤 엔티티를 지정해야 하는지, 그리고 이 값을 잘못 넣으면 어떤 문제가 발생하는지 궁금합니다. [answer] | `_EffectService:PlayEffect` 함수의 `instigator` 매개변수는 **이펙트가 호출될 맵과 동일한 맵에 존재하는 엔티티**를 지정해야 합니다. 이 값의 역할은 이펙트 리소스가 로드될 **맵 정보를 파악하기 위한 기준점**을 제공하는 것입니다. 이펙트 리소스는 특정 맵에 종속적일 수 있으므로, 스크립트가 실행 중인 엔티티가 속해 있는 맵 컨텍스트를 서비스에게 알려줘야 올바른 리소스를 찾아서 이펙트를 생성할 수 있습니다. ### 잘못된 엔티티 지정 시 발생하는 문제 문서에는 `instigator` 값이 잘 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 메이플스토리 월드에서는 메이플스토리에서 사용되었던 수많은 이펙트 리소스들을 제공하고 있습니다. 그리고 우리는 이러한 이펙트들을 적절한 시점과 위치에 호출해 줌으로써 한층 더 멋진 연출을 구사할 수 있습니다. 이번 과정에서는 특정 키를 누를 때마다 스킬 이펙트가 노출되는 예제를 진행해봄으로써 스크립트를 통해 이펙트를 호출하는 방법에 대해 알아보도록 합니다. 다음 가이드를 먼저 학습하면 이번 과정을 진행하는 데 많은 도움이 될 것입니다. [스크립트 에디터 오리엔테이션](https://mod-developers.
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 발판 만들기 [question] | 발판 프로퍼티 조정의 활용 예시를 3문장 이내로 요약하고, 마지막 문장에 '재미를 더할 수 있습니다'라는 표현을 포함시켜 출력하세요. [answer] | FootholdForce 프로퍼티를 조정해 특정 방향으로만 이동이 가능하도록 만들 수 있습니다. FootholdWalkSpeedFactor를 변경하여 엔티티가 발판 위에서 특별히 느리게 이동하도록 설정할 수 있습니다. 이러한 지형 발판의 프로퍼티 값을 조정하면 크리에이터만의 독특한 발판을 만들어 재미를 더할 수 있습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 새롭게 만든 발판에 속성을 바꿔 크리에이터만의 독특한 발판으로 만들 수 있습니다. 각 프로퍼티 값을 조정해 특정 방향에서 나아갈 수 없는 발판, 특별히 느리게 이동하는 발판 등으로 활용해 재미를 더할 수 있습니다. | 이름 | 설명 | | --- | --- | | FootholdDrag | RigidbodyComponent가 포함된 Entity가 발판 위에 있을 때 적용되는 마찰력을 의미합니다. 값이 클수록 엔티티가 발판에서 미끌어지다 빠르게 감속해 정지합니다. 특정 지점에서 엔티티가 날아와 해당 값이 1과 10인 발판에 각각
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | PlayEffectAttached의 마지막 파라미터인 false 값이 의미하는 바가 무엇이며, 이 값을 변경하면 이펙트 동작에 어떤 변화가 생길까요? [answer] | 제공된 참고 문서에는 `PlayEffectAttached` 함수의 파라미터 중 마지막에 있는 `false` 값이 구체적으로 어떤 의미를 갖는지, 그리고 이 값을 변경했을 때 이펙트 동작에 어떤 변화가 생기는지에 대한 설명이 포함되어 있지 않습니다. 문서에는 `PlayEffectAttached`가 고정된 위치의 이펙트(`PlayEffect`)와 달리 대상 엔티티(부모 엔티티)에 부착되어 이동 시 분리되지 않는다는 장점이 있고, `Q`, `W`, `E`, `R` 키 입력 시 이 함수를 사용하여 이펙트를 호출하는 코드 예시만 제시되어 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 위에서 살펴본 이펙트 호출 방법은 사실 스킬 이펙트에 적합한 방법은 아닙니다. 위의 예제처럼 구현하면 Q, W, E, R 키를 누른 후 캐릭터를 이동할 때 캐릭터가 이펙트를 벗어나 이동하게 됩니다. `PlayEffect`는 위에서 잠깐 언급한 것처럼 고정된 위치에 이펙트를 호출하는데 적합한 함수이기 때문에 버프류 스킬과 같이 항상 캐릭터 위에 떠 있어야 할 이펙트에는 적합하지 않습니다. 따라서 이러한 경우에 사용하는 함수가 바로 `PlayEffectAttached` 함수입니다. `PlayEffectAttached`의 경우 이펙트가
[task] | single_turn [pass] | ⏳ 미판정 [title] | 발판 만들기 [question] | RigidbodyComponent가 없는 엔티티는 FootholdDrag나 FootholdForce의 영향을 받지 않나요? [answer] | 네, 맞습니다. `FootholdDrag`와 `FootholdForce` 프로퍼티는 `RigidbodyComponent`가 포함된 Entity가 발판 위에 있을 때만 적용됩니다. 따라서 `RigidbodyComponent`가 없는 엔티티는 이러한 발판의 물리 속성(마찰력, 힘)의 영향을 받지 않습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 새롭게 만든 발판에 속성을 바꿔 크리에이터만의 독특한 발판으로 만들 수 있습니다. 각 프로퍼티 값을 조정해 특정 방향에서 나아갈 수 없는 발판, 특별히 느리게 이동하는 발판 등으로 활용해 재미를 더할 수 있습니다. | 이름 | 설명 | | --- | --- | | FootholdDrag | RigidbodyComponent가 포함된 Entity가 발판 위에 있을 때 적용되는 마찰력을 의미합니다. 값이 클수록 엔티티가 발판에서 미끌어지다 빠르게 감속해 정지합니다. 특정 지점에서 엔티티가 날아와 해당 값이 1과 10인 발판에 각각
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스킬 이펙트를 뿌려보자! [question] | 스킬 이펙트를 뿌리기 전에 키 입력을 먼저 학습해야 하는 이유와, 이 단계에서 로그 출력 대신 바로 이펙트 호출 로직을 작성해도 되는지 궁금합니다. [answer] | 키 입력을 먼저 학습하는 이유는 스킬 이펙트 호출의 **트리거(Trigger) 조건**을 명확히 정의하고, 해당 조건이 정상적으로 감지되는지 검증하기 위해서입니다. 참고 문서의 예제에서 보듯 `HandleKeyDownEvent` 핸들러 내에서 `event.key` 값을 확인하여 특정 키(예: `KeyboardKey.Q`, `KeyboardKey.W` 등)가 눌렸을 때만 로직이 실행되도록 분기 처리합니다. 이 단계에서 로그(`log`)를 출력하는 것은 해당 키 입력이 스크립트에 정확히 전달되고 있는지, 그리고 `KeyboardKey [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 스킬 호출 기능에 앞서 간단하게 키 입력을 받는 기능을 먼저 만들어보겠습니다. 1. **Workspace**에서 새 컴포넌트를 추가하고, 이름으로 **NewSkill**을 입력합니다. 2. **NewSkill** 컴포넌트에 키 입력 이벤트를 처리할 핸들러를 추가합니다. **[+]** 버튼을 눌러 **KeyDownEvent**를 추가합니다. 3. **HandleKeyDownEvent**의 코드를 다음과 같이 작성해 줍니다. ```lua [service: InputService]