[task] | two_turn [pass] | ⏳ 미판정 [title] | 엔티티를 탐색하는 EntityService [question] | EntityService를 활용해 엔티티의 생성과 삭제 이벤트를 실시간으로 감지하려면 어떤 구조의 스크립트를 작성해야 하나요? [answer] | EntityService를 활용해 엔티티의 생성과 삭제 이벤트를 실시간으로 감지하려면, `Event Handler` 블록에 `[service: EntityService]` 태그를 붙여 `HandleEntityCreateEvent`와 `HandleEntityDestroyEvent` 핸들러를 구현해야 합니다. 이벤트 핸들러는 각각 `EntityCreateEvent`와 `EntityDestroyEvent` 타입의 이벤트 객체를 매개변수로 받으며, 해당 이벤트 객체의 `Entity` 프로퍼티를 통해 이벤트가 발생한 엔티티에 대한 정보(예 [followup] | HandleEntityDestroyEvent 핸들러에서 삭제 대기 중인 엔티티의 정보에 접근하여 특정 이름의 엔티티 삭제 로그를 출력하는 코드 예시를 보여주세요. [followup_answer] | `HandleEntityDestroyEvent` 핸들러에서 삭제 대기 중인 엔티티의 정보에 접근하여 특정 이름의 엔티티 삭제 로그를 출력하는 코드 예시는 다음과 같습니다. ```lua Event Handler: [service: EntityService] HandleEntityDestroyEvent(EntityDestroyEvent event) { -- Parameters local Entity = event.Entity ------------------------------------------------- [scores] | [judge_reason] | [source_doc] | 엔티티가 삭제될 때 발생하는 이벤트입니다. **Entity Event Handler**에서 핸들러를 추가할 수 있습니다. 이벤트 핸들러의 매개 변수로 이벤트가 전송되며, 이벤트에는 삭제 대기 중인 엔티티가 정보가 포함되어 있습니다. ```lua Method: [server only] void OnBeginPlay() { local monsterTemplate = _EntityService:GetEntityByPath("/maps/map01/monster-1") -- "spawnedMonster"라는 이름의 몬
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스크립트 디버그 [question] | 디버그 모드에서 변수의 현재 값과 타입을 확인하고 싶은데, 마우스 오버만으로도 모든 정보가 보이나 아니면 다른 도구가 필요하나요? [answer] | 디버그 모드에서 변수의 현재 값과 타입은 마우스 오버만으로 간단하게 확인할 수 있습니다. 실행된 코드 라인에서 변수나 프로퍼티에 마우스를 올리면 툴팁이 표시되며, **할당된 값**, **실행 공간**, **타입** 등의 정보가 함께 나옵니다. 더 자세한 분석이 필요할 경우에는 **Watch Expression** 같은 툴을 활용할 수도 있지만, 기본적인 값과 타입 확인 목적이라면 마우스 오버 기능만으로도 충분합니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 중단점을 비활성화할 때는 마우스 왼쪽 버튼을 클릭합니다. 비활성화된 중단점은 ![[object Object]](https://mod-file.dn.nexoncdn.co.kr/bbs/1769135859948681fdb075cef4ee7ab4fed9f2f4d4ebd.png "breakpoint4"), ![[object Object]](https://mod-file.dn.nexoncdn.co.kr/bbs/1769135881421982425439c154f54a9f5db45be1c38a6.png "breakpoint5") 로 표시되며, **
[task] | two_turn [pass] | ⏳ 미판정 [title] | Entity Event System [question] | 맵 엔티티와 월드 엔티티가 서로 이벤트를 주고받는 구조에서, 특정 NPC 엔티티(`Vampire`, `Hunter`)가 아닌 맵 레벨에서 `SunriseEvent`를 발생시키고 NPC들이 이를 수신하도록 설계하려면, 이벤트 발생 측(맵/월드)과 수신 측(NPC)의 Event Handler 등록 대상 엔티티 경로(Path)를 어떻게 설정해야 하나요? [answer] | 제공된 참고 문서에는 `SunriseEvent`의 생성 방법(Property 정의)과 NPC 엔티티에 컴포넌트를 부착하는 절차, 그리고 자기 자신의 엔티티(`[self]`)에 이벤트를 연결하는 기본 개념과 `HitEvent`, `ButtonClickEvent` 처리 예제만 포함되어 있습니다. 문서에는 맵 엔티티나 월드 엔티티의 구체적 경로(Path) 값(예: `/maps/map01`, `/world` 등)이 명시되어 있지 않으며, 다른 엔티티의 경로를 인수로 전달하여 이벤트를 발생시키거나 수신하는 구체적인 API 호출 문법(예: [followup] | `_EntityService:GetEntityByPath`를 사용하여 특정 NPC 엔티티를 참조하고, 해당 엔티티에 직접 이벤트를 발생시키거나 핸들러를 동적으로 등록/해제하는 mLua 코드 패턴과, 이렇게 할 때 발생할 수 있는 엔티티가 존재하지 않을 경우의 예외 처리 방법은 무엇인가요? [followup_answer] | 제공된 참고 문서에는 `_EntityService:GetEntityByPath` API에 대한 설명, 해당 메서드 사용 예제, 이벤트 핸들러를 동적으로 등록하거나 해제하는 코드 패턴, 그리고 엔티티가 존재하지 않을 경우의 예외 처리 방법에 대한 정보가 포함되어 있지 않습니다. 문서에는 `SunriseEvent` 타입 생성 방법, NPC 엔티티에 컴포넌트를 부착하는 에디터 단계 절차, 그리고 `[self]` 지정자를 사용하여 자기 자신의 엔티티에 발생한 이벤트를 처리하는 정적 핸들러 예제(`HandleHitEvent`, `Handl [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] | 비활성화된 중단점은 **BreakPoint Settings** 창에서 다시 활성화할 수 있습니다. 마우스 왼쪽 버튼을 한 번 클릭하면 중단점이 비활성화되며, 이 상태의 중단점은 화면에서 특별히 표시(예: `![[object Object]]` 이미지 참조)됩니다. 비활성화된 중단점을 다시 켜려면 해당 **BreakPoint Settings** 창을 열어 설정을 변경하시면 됩니다. 참고로, 중단점을 완전히 제거하고 싶다면 마우스 왼쪽 버튼을 2번(더블 클릭) 누르면 해제됩니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 중단점을 비활성화할 때는 마우스 왼쪽 버튼을 클릭합니다. 비활성화된 중단점은 ![[object Object]](https://mod-file.dn.nexoncdn.co.kr/bbs/1769135859948681fdb075cef4ee7ab4fed9f2f4d4ebd.png "breakpoint4"), ![[object Object]](https://mod-file.dn.nexoncdn.co.kr/bbs/1769135881421982425439c154f54a9f5db45be1c38a6.png "breakpoint5") 로 표시되며, **
[task] | two_turn [pass] | ⏳ 미판정 [title] | 스크립트 디버그 [question] | 디버그 모드에서 실행 중인 코드 라인의 변수 값을 확인하는 가장 간단한 방법은 무엇인가요? [answer] | 디버그 모드에서 실행 중인 코드 라인의 변수 값을 확인하는 가장 간단한 방법은 해당 변수나 프로퍼티에 **마우스 오버**를 하는 것입니다. 이렇게 하면 툴팁이 표시되어 해당 변수의 **할당된 값**, **실행 공간**, **타입** 등의 정보를 즉시 확인할 수 있습니다. 보다 상세한 확인이 필요할 때는 **Watch Expression** 같은 툴을 활용할 수도 있습니다. [followup] | Watch Expression 툴을 사용하지 않고 마우스 오버로 값을 볼 때, 툴팁에 표시되는 정보(할당된 값, 실행 공간, 타입 등)는 어떻게 해석하나요? [followup_answer] | 참고 문서에는 마우스 오버 시 툴팁에 **할당된 값**, **실행 공간**, **타입** 등의 정보가 표시된다는 사실과, 매개 변수로 받은 `delta`의 값 등을 확인할 수 있다는 예시만 나와 있습니다. 하지만 툴팁에 표시되는 각 항목(할당된 값, 실행 공간, 타입)의 구체적인 의미나 해석 방법은 문서에 설명되어 있지 않습니다. 따라서 각 정보가 어떻게 해석되어야 하는지에 대해서는 답변해 드리기 어렵습니다. [scores] | [judge_reason] | [source_doc] | 중단점을 비활성화할 때는 마우스 왼쪽 버튼을 클릭합니다. 비활성화된 중단점은 ![[object Object]](https://mod-file.dn.nexoncdn.co.kr/bbs/1769135859948681fdb075cef4ee7ab4fed9f2f4d4ebd.png "breakpoint4"), ![[object Object]](https://mod-file.dn.nexoncdn.co.kr/bbs/1769135881421982425439c154f54a9f5db45be1c38a6.png "breakpoint5") 로 표시되며, **
[task] | two_turn [pass] | ⏳ 미판정 [title] | 스크립트 디버그 [question] | 중단점을 비활성화하거나 해제하는 마우스 조작법은 어떻게 되나요? [answer] | 중단점을 비활성화하거나 해제하는 마우스 조작법은 다음과 같습니다. * **비활성화**: 중단점에 **마우스 왼쪽 버튼을 1번 클릭**하면 비활성화됩니다. * **해제**: 중단점에 **마우스 왼쪽 버튼을 2번 클릭**(더블 클릭)하면 중단점이 완전히 해제됩니다. 비활성화된 중단점은 `BreakPoint Settings` 창에서 다시 활성화할 수 있습니다. [followup] | 마우스 왼쪽 버튼을 2번 눌러 중단점을 해제할 경우, BreakPoint Settings 창과 Breakpoints 패널에서 해당 상태가 어떻게 표시되는지 설명해주세요. [followup_answer] | 참고 문서에는 마우스 왼쪽 버튼을 2번 눌러 중단점을 해제했을 때 `BreakPoint Settings` 창과 `Breakpoints` 패널에 해당 상태가 어떻게 표시되는지에 대한 구체적인 정보가 포함되어 있지 않습니다. 문서에는 마우스 왼쪽 버튼 2번 클릭 시 중단점이 "해제"된다는 사실과, `Breakpoints` 패널에서 설정된 중단점 목록(Entry, Method, Line)을 조회하거나 삭제(`Remove`), 이동(`Move`)할 수 있다는 내용만 설명하고 있을 뿐, 해제된 중단점이 UI에 어떻게 비추적되는지(예: 목록 [scores] | [judge_reason] | [source_doc] | 중단점을 비활성화할 때는 마우스 왼쪽 버튼을 클릭합니다. 비활성화된 중단점은 ![[object Object]](https://mod-file.dn.nexoncdn.co.kr/bbs/1769135859948681fdb075cef4ee7ab4fed9f2f4d4ebd.png "breakpoint4"), ![[object Object]](https://mod-file.dn.nexoncdn.co.kr/bbs/1769135881421982425439c154f54a9f5db45be1c38a6.png "breakpoint5") 로 표시되며, **
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 점프대 만들기 [question] | OnEnterTriggerBody 함수 내에서 캐릭터의 이동 방향을 판별하고 물리적인 힘을 가하는 핵심 코드만 출력하고, 설명은 주석으로만 작성하세요. [answer] | ```lua Method: [server] void OnEnterTriggerBody (TriggerEnterEvent enterEvent) { __base:OnEnterTriggerBody(enterEvent) -- 충돌한 대상(플레이어)을 받아옵니다. local player = enterEvent.TriggerBodyEntity -- RigidbodyComponent가 없으면 함수를 종료합니다. local rigidbody = player.RigidbodyComponent if rigidbody == nil t [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 점프대에 닿으면 캐릭터가 높이 솟아오르는 점프대를 만들어 봅니다. 이번 예제를 통해 확장 스크립트 작성법과 스크립트를 통해 물체와의 충돌 및 충돌 시 처리, 그리고 물체에 물리적인 힘을 가하는 방법에 대해 알아봅니다. 추가로 컴포넌트에 프로퍼티를 추가하고, 오브젝트별로 다른 프로퍼티 값을 설정하는 방법을 알아봅니다. # 점프대 배치하기 1. **Preset List**에서 스프링 모양의 모델(object-4575)을 찾아 맵에 배치합니다. # TriggerComponent로 충돌 기능 활용하기 물체와
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티를 탐색하는 EntityService [question] | _EntityService 서비스의 HandleEntityCreateEvent와 HandleEntityDestroyEvent 핸들러를 구현하여, 이름이 "testTarget"인 엔티티가 생성되거나 삭제될 때만 log로 해당 이벤트를 출력하는 스크립트를 작성해줘 [answer] | ```lua Event Handler: [service: EntityService] HandleEntityCreateEvent(EntityCreateEvent event) { local Entity = event.Entity if Entity.Name ~= "testTarget" then return end log("CreatedEntity : "..Entity.Name) } [service: EntityService] HandleEntityDestroyEvent(Ent [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 엔티티가 삭제될 때 발생하는 이벤트입니다. **Entity Event Handler**에서 핸들러를 추가할 수 있습니다. 이벤트 핸들러의 매개 변수로 이벤트가 전송되며, 이벤트에는 삭제 대기 중인 엔티티가 정보가 포함되어 있습니다. ```lua Method: [server only] void OnBeginPlay() { local monsterTemplate = _EntityService:GetEntityByPath("/maps/map01/monster-1") -- "spawnedMonster"라는 이름의 몬
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티를 탐색하는 EntityService [question] | _EntityService 서비스의 HandleEntityDestroyEvent에서 이벤트 매개변수 event.Entity의 Name을 확인하여 특정 이름의 엔티티가 삭제 대기 상태일 때에만 log 메시지를 출력하는 스크립트를 작성해줘 [answer] | ```lua Event Handler: [service: EntityService] HandleEntityDestroyEvent(EntityDestroyEvent event) { -- Parameters local Entity = event.Entity -------------------------------------------------------- -- 특정 이름("targetEntity")의 엔티티가 삭제 대기 상태일 때에만 로그 출력 if Entity.Name == "target [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 엔티티가 삭제될 때 발생하는 이벤트입니다. **Entity Event Handler**에서 핸들러를 추가할 수 있습니다. 이벤트 핸들러의 매개 변수로 이벤트가 전송되며, 이벤트에는 삭제 대기 중인 엔티티가 정보가 포함되어 있습니다. ```lua Method: [server only] void OnBeginPlay() { local monsterTemplate = _EntityService:GetEntityByPath("/maps/map01/monster-1") -- "spawnedMonster"라는 이름의 몬
[task] | two_turn [pass] | ⏳ 미판정 [title] | 엔티티를 탐색하는 EntityService [question] | EntityService로 특정 모델이나 태그를 가진 엔티티들을 어떻게 검색할 수 있나요? [answer] | `EntityService`를 사용하면 모델 ID, 모델 객체, 특정 엔티티의 원형 모델, 또는 태그를 기준으로 엔티티를 검색할 수 있습니다. 각 메서드의 특징과 사용법은 다음과 같습니다. ### 1. 모델 기반 검색 특정 모델로부터 생성된 모든 엔티티를 찾고 싶을 때 사용하며, 수많은 엔티티가 배치된 상황에서 동일 모델의 NPC나 몬스터 등을 일괄적으로 제어할 때 유용합니다. * **`GetEntitiesSpawnedByModelId(number modelId)`**: 모델 ID와 일치하는 모델로부터 생성된 모든 엔티티를 [followup] | `GetEntitiesSpawnedByModelId`와 `GetEntitiesByTag`를 사용할 때 반환값을 어떻게 처리하고, `GetEntityByTag`가 여러 엔티티 중 하나만 반환하는 이유와 그 제한 사항을 설명해 주세요. [followup_answer] | `GetEntitiesSpawnedByModelId`와 `GetEntitiesByTag`는 조건에 맞는 **여러 개의 엔티티**를 반환하므로, 반환값은 테이블(배열/딕셔너리) 형태로 처리해야 합니다. 반면, `GetEntityByTag`는 단일 엔티티를 반환하지만 특정 제한 사항이 있어 주의가 필요합니다. ### 1. 복수 엔티티 반환값 처리 (`GetEntitiesSpawnedByModelId`, `GetEntitiesByTag`) 이 두 메서드는 조건과 일치하는 모든 엔티티를 테이블 형태로 반환합니다. 따라서 `for` 루프 [scores] | [judge_reason] | [source_doc] | 모델 ID와 일치하는 모델로부터 생성된 모든 엔티티를 반환합니다. 다음과 같이 수많은 엔티티가 배치된 상황에서 NPC와 같이 동일 모델로부터 생성된 모든 엔티티를 받고 싶을 때 유용하게 사용됩니다. 특정 엔티티에 접근하여 모델을 받은 뒤, 해당 모델로부터 생성된 모든 엔티티를 받을 수 있습니다. ```lua void GetEntitiesSpawnedByModelIdExample() { local modelId = _EntityService:GetEntityByPath("/maps/map02/npc-5396_1").Mode
[task] | code [pass] | ⏳ 미판정 [title] | 엔티티를 탐색하는 EntityService [question] | _OnBeginPlay에서 _EntityService:GetEntityByPath로 엔티티를 가져와 _SpawnService:SpawnByEntityTemplate으로 "testTarget" 이름의 엔티티를 스폰한 뒤, _TimerService:SetTimerOnce를 이용해 3초 후 _EntityService:Destroy로 삭제하는 스크립트를 작성해줘 [answer] | 요청하신 조건(엔티티 조회 → 스폰 → 3초 후 삭제)을 만족하는 mLua 스크립트입니다. ```lua Method: [server only] void OnBeginPlay() { local monsterTemplate = _EntityService:GetEntityByPath("/maps/map01/monster-1") -- "testTarget"라는 이름의 엔티티 스폰 local spawnedEntity = _SpawnService:SpawnByEntityTemplate(monsterTemplat [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 엔티티가 삭제될 때 발생하는 이벤트입니다. **Entity Event Handler**에서 핸들러를 추가할 수 있습니다. 이벤트 핸들러의 매개 변수로 이벤트가 전송되며, 이벤트에는 삭제 대기 중인 엔티티가 정보가 포함되어 있습니다. ```lua Method: [server only] void OnBeginPlay() { local monsterTemplate = _EntityService:GetEntityByPath("/maps/map01/monster-1") -- "spawnedMonster"라는 이름의 몬
[task] | code [pass] | ⏳ 미판정 [title] | 점프대 만들기 [question] | TriggerComponent를 상속받아 OnEnterTriggerBody 이벤트 핸들러에서 enterEvent.TriggerBodyEntity 의 RigidbodyComponent 와 PlayerControllerComponent 를 확인하고, PlayerControllerComponent.LookDirectionX 에 따라 Vector2(10,10) 또는 Vector2(-10,10) 값으로 RigidbodyComponent:SetForce 를 호출해 캐릭터를 밀어내는 Spring 스크립트를 작성해줘 [answer] | TriggerComponent를 확장하여 `OnEnterTriggerBody` 오버라이드를 통해 충돌한 플레이어의 `RigidbodyComponent`와 `PlayerControllerComponent`를 확인하고, 바라보는 방향(`LookDirectionX`)에 따라 힘(`SetForce`)을 가하는 `Spring` 스크립트입니다. ```lua Method: [server] void OnEnterTriggerBody (TriggerEnterEvent enterEvent) { __base:OnEnterTriggerBody( [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 점프대에 닿으면 캐릭터가 높이 솟아오르는 점프대를 만들어 봅니다. 이번 예제를 통해 확장 스크립트 작성법과 스크립트를 통해 물체와의 충돌 및 충돌 시 처리, 그리고 물체에 물리적인 힘을 가하는 방법에 대해 알아봅니다. 추가로 컴포넌트에 프로퍼티를 추가하고, 오브젝트별로 다른 프로퍼티 값을 설정하는 방법을 알아봅니다. # 점프대 배치하기 1. **Preset List**에서 스프링 모양의 모델(object-4575)을 찾아 맵에 배치합니다. # TriggerComponent로 충돌 기능 활용하기 물체와
[task] | two_turn [pass] | ⏳ 미판정 [title] | 스크립트 디버그 [question] | 중단점을 여러 라인에 설정했을 때 Breakpoints 패널을 통해 관리하는 방법은 무엇인가요? [answer] | 중단점을 여러 라인에 설정했을 때 **Breakpoints** 패널을 통해 관리하는 방법은 다음과 같습니다. 1. **패널 열기**: 내비게이션 메뉴에서 **Panels - Debug - Breakpoints**를 클릭해 패널을 엽니다. 2. **중단점 확인**: 패널에는 설정된 모든 중단점의 정보가 목록으로 표시됩니다. - **Entry**: 중단점이 설정된 스크립트 컴포넌트 또는 스크립트 로직의 이름 - **Method**: Entry 내에서 중단점이 설정된 Method 이름 - **Line**: Method [followup] | Breakpoints 패널에서 특정 중단점의 위치로 이동하거나 삭제하는 구체적인 조작 단계를 알려주세요. [followup_answer] | Breakpoints 패널에서 특정 중단점의 위치로 이동하거나 삭제하는 구체적인 조작 단계는 다음과 같습니다. ### 중단점으로 이동 1. **Breakpoints** 패널을 엽니다 (내비게이션 메뉴의 **Panels - Debug - Breakpoints** 클릭). 2. 이동하고자 하는 중단점 목록 항목을 **더블 클릭**합니다. - 또는, 해당 중단점 항목에서 **콘텍스트 메뉴**(우클릭 등)를 열어 **Move**를 클릭합니다. 3. 에디터가 해당 중단점이 설정된 스크립트의 특정 라인 위치로 자동 이동합니다. ### [scores] | [judge_reason] | [source_doc] | 중단점을 비활성화할 때는 마우스 왼쪽 버튼을 클릭합니다. 비활성화된 중단점은 ![[object Object]](https://mod-file.dn.nexoncdn.co.kr/bbs/1769135859948681fdb075cef4ee7ab4fed9f2f4d4ebd.png "breakpoint4"), ![[object Object]](https://mod-file.dn.nexoncdn.co.kr/bbs/1769135881421982425439c154f54a9f5db45be1c38a6.png "breakpoint5") 로 표시되며, **
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | `SpawnMonster()` 함수에서 몬스터를 스폰하기 위해 사용하는 서비스 객체 이름과 해당 함수의 실행 공간([server only] 등)을 한 줄로 답변하세요. [answer] | 서비스 객체 이름은 `_SpawnService`이며, 해당 함수의 실행 공간은 `[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] | Entity Event System [question] | Entity Event System을 이용해 특정 시간마다 해가 뜨고 지는 로직을 구현하려면 어떤 스크립트 컴포넌트를 만들어야 하며, `OnUpdate`에서 어떻게 시간 관리를 하는가 [answer] | 특정 시간마다 해가 뜨고 지는 로직을 구현하기 위해서는 **TimeManager**라는 이름의 스크립트 컴포넌트를 만들어야 합니다. 이 컴포넌트는 `OnUpdate` 함수를 통해 매 프레임의 시간 간격(`delta`)을 누적하여 시간을 관리합니다. 구체적인 구현 방식은 다음과 같습니다. 1. **TimeManager 컴포넌트 생성**: Workspace의 해당 폴더에서 Create Component를 통해 `TimeManager` 컴포넌트를 생성합니다. 2. **시간 관리 로직 (`OnUpdate`)**: * `[ [followup] | `TimeManager` 컴포넌트에서 `self._T.Time` 변수를 어떻게 초기화하고 `delta`를 더해 5초마다 `isSunrise` 상태를 번갈아 바꾸는지 구체적인 코드 흐름을 설명해 주세요. [followup_answer] | `TimeManager` 컴포넌트에서 시간 관리와 상태 전환이 이루어지는 구체적인 코드 흐름은 다음과 같습니다. 1. **초기화 및 시간 누적**: * `OnUpdate` 함수가 매 프레임 실행될 때, 먼저 `self._T.Time` 변수가 `nil`인지 확인합니다. * 만약 `nil`이라면 `self._T.Time = 0`으로 초기화합니다. * 초기화가 완료된 후, 매 프레임의 시간 간격인 `delta` 값을 `self._T.Time`에 더하여 누적 시간을 증가시킵니다. (`self._T.Tim [scores] | [judge_reason] | [source_doc] | 특정 시간마다 해가 뜨고 지는 로직을 만들어봅시다. 1. 해가 뜨고 지는 시간을 관리할 스크립트 컴포넌트가 필요합니다. **Workspace - MyDesk**의 콘텍스트 메뉴에서 **Create Scrips - Create Component**를 클릭해 새 컴포넌트를 만듭니다. 이름으로 **TimeManager**를 입력합니다. 2. **TimeManager** 스크립트 컴포넌트를 엽니다. `OnUpdate` 함수를 추가하여 해가 뜨고 지는 것을 판단하도록 합니다. ```lua Property: [Sy
[task] | single_turn [pass] | ⏳ 미판정 [title] | 스크립트 디버그 [question] | 중단점을 설정했는데 디버그 중에는 안 걸리고 그냥 넘어가는 경우가 있는데, 이게 왜 그런지 설명해 주실 수 있나요? [answer] | 제공된 문서에는 중단점이 디버그 중 걸리지 않고 넘어가는 현상의 **원인**에 대한 설명이 포함되어 있지 않습니다. 문서에서 확인 가능한 내용은 다음과 같습니다. 1. **중단점 상태 확인:** * 중단점은 활성화(적색 계열)와 비활성화(회색 계열 등) 상태가 있으며, 비활성화된 중단점은 **BreakPoint Settings** 창에서 다시 활성화해야 합니다. * 마우스 왼쪽 버튼을 2번 누르면 중단점이 해제됩니다. * **Breakpoints** 패널(`Panels - Debug - Brea [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 중단점을 비활성화할 때는 마우스 왼쪽 버튼을 클릭합니다. 비활성화된 중단점은 ![[object Object]](https://mod-file.dn.nexoncdn.co.kr/bbs/1769135859948681fdb075cef4ee7ab4fed9f2f4d4ebd.png "breakpoint4"), ![[object Object]](https://mod-file.dn.nexoncdn.co.kr/bbs/1769135881421982425439c154f54a9f5db45be1c38a6.png "breakpoint5") 로 표시되며, **
[task] | code [pass] | ⏳ 미판정 [title] | Entity Event System [question] | HunterComponent 스크립트를 작성해줘: [Sync] boolean isSunrise와 [Sync] number Hp 프로퍼티를 정의하고, [entity: map01(/maps/map01)] 이벤트 핸들러에서 SunriseEvent의 isSunrise 값을 self.isSunrise에 대입하며, [server Only] OnUpdate 메서드에서 self.isSunrise가 true일 때 Hp를 delta만큼 증가시켜 최대 200을 초과하지 않도록 제한하고 현재 Hp 값을 로그로 출력한다. [answer] | 요청하신 HunterComponent 스크립트입니다. ```lua Property: [Sync] boolean isSunrise = false [Sync] number Hp = 0 Method: [server Only] void OnUpdate(number delta) { if self.isSunrise == true then self.Hp = self.Hp + delta log("Hunter Hp : "..self.Hp) if self.Hp >= 200 then se [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | **HunterComponent**, **VampireComponent** 스크립트를 작성해 봅시다. 우선 두 컴포넌트 모두 **SunriseEvent**를 받도록 해야 합니다. 1. **HunterComponent**, **VampireComponent** 스크립트를 엽니다. **Event Handler**에서 **[+]** 버튼을 누르고, **SunriseEvent**를 추가합니다. 2. **SunriseEvent**의 중계 엔티티를 **map01**으로 설정해야 합니다. 다음과 같이 핸들러 상단의 이벤트 중계자를 **ma
[task] | code [pass] | ⏳ 미판정 [title] | Entity Event System [question] | VampireComponent 스크립트를 작성해줘: [Sync] boolean isSunrise와 [Sync] number Hp 프로퍼티를 정의하고, [entity: map01(/maps/map01)] 이벤트 핸들러에서 SunriseEvent의 isSunrise 값을 self.isSunrise에 대입하며, [server Only] OnUpdate 메서드에서 self.isSunrise가 true일 때 Hp를 delta만큼 감소시켜 0 이하가 되지 않도록 제한하고 현재 Hp 값을 로그로 출력한다. [answer] | 요청하신 VampireComponent 스크립트는 다음과 같습니다. ```lua Property: [Sync] boolean isSunrise = false [Sync] number Hp = 0 Method: [server Only] void OnUpdate(number delta) { if self.isSunrise == true then self.Hp = self.Hp - delta log("Vampire Hp : "..self.Hp) if self.Hp < 0 t [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] | Preset List에서 몬스터를 Workspace에 추가할 때 우클릭 메뉴의 정확한 항목 이름이 무엇인가요? [answer] | Preset List에서 몬스터를 우클릭했을 때 선택해야 할 정확한 항목 이름은 **Add to Workspace**입니다. [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] | 같은 월드 경로에 여러 엔티티가 존재할 때 GetEntityByPath()가 가장 먼저 찾은 엔티티를 반환한다고 하는데, 이 '가장 먼저'의 기준은 무엇이며, 이를 방지하기 위해 GetEntity()를 사용할 때 엔티티 ID를 어떻게 가져와야 하는지 알려 주세요. [answer] | 제공된 문서에는 `GetEntityByPath()` 함수가 동일한 월드 경로를 가진 엔티티가 2개 이상 존재할 때 "가장 먼저 찾은 엔티티"를 반환한다고 명시되어 있습니다. 그러나 **이 '가장 먼저'의 구체적인 기준(예: 생성 순서, Hierarchy 상의 위치 순서 등)에 대한 설명은 문서에 포함되어 있지 않습니다.** `GetEntityByPath()`의 이러한 한계를 방지하고, 같은 이름의 엔티티가 여러 개 있어도 원하는 특정 엔티티 하나만 정확히 가져오려면 `GetEntity()` 함수를 사용해야 합니다. `GetEnti [followup] | 스크립트 실행 중 동적으로 생성된 엔티티의 Id를 변수에 저장해 두지 않고, 경로만으로 다시 탐색해야 하는 상황에서 GetEntitiesByPath()와 GetEntity()를 조합하여 원하는 특정 엔티티(예: 이름이 "Bullet_1"인 것)를 안전하게 찾아오는 로직을 작성해 주세요. [followup_answer] | 제공된 문서에 따르면, `GetEntity()` 함수는 엔티티 ID를 매개변수로 받아 특정 엔티티를 반환합니다. 반면 `GetEntitiesByPath()`는 지정된 경로와 일치하는 **모든** 엔티티 배열을 반환합니다. 따라서 ID를 변수에 저장하지 않고 경로만으로 다시 탐색해야 하는 상황에서, 이름이 `"Bullet_1"`인 특정 엔티티를 찾기 위해서는 `GetEntitiesByPath()`로 해당 경로에 있는 모든 엔티티를 가져온 뒤, 이를 순회하며 `Name` 프로퍼티가 `"Bullet_1"`과 일치하는 엔티티를 찾아야 합 [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 월드를 제작하다 보면 특정 엔티티를 탐색하여 받아오거나, 혹은 관련 있는 여러 엔티티를 한 번에 받아야 하는 상황이 자주 발생합니다. 이럴 때 [**EntityService**](/apiReference/Services/EntityService)를 활용할 수 있습니다. **EntityService**는 엔티티 탐색, 삭제, 유효성 체크 등의 기능을 제공하고 있습니다. 이번 과정에서는 **EntityService**에서 제공하는 기능의 사용법을 하나씩 알아보도록 하겠습니다. **테스트 환경** **common
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | `_SpawnService:SpawnByModelId` 함수의 매개 변수 4개를 인자 순서대로 나열해 주세요. [answer] | `_SpawnService:SpawnByModelId` 함수의 매개 변수 4개는 인자 순서대로 다음과 같습니다. 1. 모델의 Entry ID (string) 2. 생성할 엔티티의 이름 (string) 3. 스폰될 위치 (Vector3) 4. 부모 엔티티 (Entity) ```lua _SpawnService:SpawnByModelId( "Entry ID", "SpawnedMonster", Vector3(0,0,0), parent) ``` [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] | 몬스터 스폰 규칙(최대 10마리, 5초 주기, 랜덤 위치)을 적용하기 위해 필요한 Workspace 설정 및 Preset List 사용 단계를 번호 목록으로 정리하세요. [answer] | 제공된 문서에는 "몬스터 스폰 규칙(최대 10마리, 5초 주기, 랜덤 위치)"을 적용하기 위한 구체적인 mLua 스크립트 코드나 Workspace 설정 절차가 포함되어 있지 않습니다. 문서에는 다음과 같은 **Preset List와 Workspace를 이용한 몬스터 추가 단계**만 설명되어 있습니다. 1. **Preset List**에서 스폰하려는 몬스터를 우클릭합니다. 2. 메뉴에서 **Add to Workspace**를 선택합니다. 3. **Workspace**에 해당 몬스터가 추가되었는지 확인합니다. 최대 스폰 수, 리스폰 [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] | 월드 제작 시 '기본' 템플릿을 권장하는 이유는 무엇인가요? [answer] | 월드 제작 시 '기본' 템플릿을 권장하는 이유는 제작 편의를 위해서입니다. [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] | 본 가이드가 포함된 전체 학습 과정의 순서와 각 편별 제목을 표로 정리하세요. [answer] | 제시된 가이드는 총 5편으로 구성된 학습 과정이며, 각 편의 순서와 제목은 다음과 같습니다. | 순서 | 편 | 제목 | | :--- | :--- | :--- | | 1 | 1편 | 몬스터를 스폰해보자 | | 2 | 2편 | 몬스터 드랍 아이템과 인벤토리 UI 만들기 | | 3 | 3편 | 인벤토리 스크립트 작성하기 | | 4 | 4편 | 인벤토리 UI 스크립트 작성하기 | | 5 | 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] | Entity Event System [question] | "뱀파이어 vs 헌터" 시나리오에서 `SunriseEvent`를 수신받아 `isSunrise` 상태에 따라 헌터의 HP 회복과 뱀파이어의 HP 감소를 처리하는 로직을 구현하려면, 두 컴포넌트 각각의 Event Handler와 HP 조작 메서드는 어떻게 작성해야 하나요? [answer] | 제공된 참고 문서에는 `SunriseEvent`의 프로퍼티 구조(`isSunrise`)와 컴포넌트 이름(`VampireComponent`, `HunterComponent`)은 정의되어 있지만, 실제 `SunriseEvent`를 수신하는 **Event Handler 코드의 구체적인 구현체(함수 본문)는 포함되어 있지 않습니다.** 문서에 있는 예제 코드(`HandleHitEvent` 등)는 타격(Hit) 관련 이벤트의 처리 방식만 보여줄 뿐, 해가 뜨는 이벤트에 대한 HP 조작 로직은 명시되어 있지 않습니다. 따라서 문서에 기반하여 [followup] | `VampireComponent`와 `HunterComponent`가 속한 엔티티의 HP를 직접 수정하는 대신, 해당 엔티티의 특정 컴포넌트(예: HealthComponent 등)를 통해 HP를 변경해야 하는 경우, `_EntityService` 또는 `self.Entity`를 이용해 타겟 엔티티의 컴포넌트에 접근하고 HP를 증감시키는 mLua 코드 예시를 보여주세요. [followup_answer] | 제공된 참고 문서에는 `_EntityService`를 사용하여 타겟 엔티티의 컴포넌트에 접근하거나, `HealthComponent`와 같은 특정 HP 관리 컴포넌트를 통해 HP를 증감시키는 **구체적인 API 이름이나 코드 예시가 포함되어 있지 않습니다.** 문서에 명시된 내용만으로는 다음과 같은 사실만 확인 가능합니다: 1. `VampireComponent`와 `HunterComponent`는 각각 뱀파이어와 헌터 엔티티에 부착됩니다. 2. 예제 코드에서 `self.Entity.HitComponent`와 같이 엔티티의 특정 [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] | code [pass] | ⏳ 미판정 [title] | 엔티티를 탐색하는 EntityService [question] | _OnBeginPlay에서 _SpawnService:SpawnByEntityTemplate으로 엔티티를 스폰하고, _EntityService:Destroy로 삭제하기 직전 _TimerService:SetTimerOnce를 통해 1초 지연된 콜백 함수를 등록하여 삭제 로직을 실행하는 스크립트를 작성해줘 [answer] | 요청하신 동작은 `OnBeginPlay`에서 엔티티를 스폰한 후, 1초 뒤에 실행되는 콜백 함수를 `_TimerService:SetTimerOnce`로 등록하여 해당 엔티티를 `_EntityService:Destroy`로 삭제하는 방식으로 구현합니다. ```lua Method: [server only] void OnBeginPlay() { -- 엔티티 템플릿을 경로로 가져옵니다. local monsterTemplate = _EntityService:GetEntityByPath("/maps/map01/monster-1 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 엔티티가 삭제될 때 발생하는 이벤트입니다. **Entity Event Handler**에서 핸들러를 추가할 수 있습니다. 이벤트 핸들러의 매개 변수로 이벤트가 전송되며, 이벤트에는 삭제 대기 중인 엔티티가 정보가 포함되어 있습니다. ```lua Method: [server only] void OnBeginPlay() { local monsterTemplate = _EntityService:GetEntityByPath("/maps/map01/monster-1") -- "spawnedMonster"라는 이름의 몬
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | `GetRandomPosition()` 함수의 구현 코드를 주석 설명 없이 출력하세요. [answer] | ```lua Vector3 GetRandomPosition() { local leftX = -3.571 local rightX = 2.688 local y = 0.170 local areaWidth = rightX - leftX local randomX = (_UtilLogic:RandomIntegerRange(0,100) / 100) * areaWidth + leftX return Vector3(randomX, y, 0) } ``` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 지정한 영역 안에서 랜덤한 위치에 몬스터를 스폰하는 기능을 추가하겠습니다. 위에 확인했던 좌표를 기준으로 스폰 영역을 정의하고, 영역 내 랜덤한 위치에 몬스터를 스폰해 봅시다. 1. **MonsterSpawn**을 스크립트 에디터에서 열고 **Vector3** 타입의 새 함수 `GetRandomPosition()`을 추가합니다. 2. `GetRandomPosition()` 함수를 다음과 같이 작성합니다. 위에서 기록해두었던 좌표를 함수에 활용합니다. ```lua Vector3 GetRandomPositio
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | 몬스터를 스폰 영역 내 랜덤 위치에 스폰하기 위한 `GetRandomPosition()` 함수 작성 과정을 단계별 번호 목록으로 3문장 이내로 요약해서 출력하세요. [answer] | 1. `MonsterSpawn` 스크립트에 `Vector3` 타입의 `GetRandomPosition()` 함수를 추가합니다. 2. 스폰 영역 좌표를 변수로 정의하고 `_UtilLogic:RandomIntegerRange(0,100)` 를 활용해 영역 내 랜덤 X 좌표를 계산합니다. 3. 계산된 X 좌표와 고정된 Y 좌표를 조합해 `Vector3` 객체를 반환합니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 지정한 영역 안에서 랜덤한 위치에 몬스터를 스폰하는 기능을 추가하겠습니다. 위에 확인했던 좌표를 기준으로 스폰 영역을 정의하고, 영역 내 랜덤한 위치에 몬스터를 스폰해 봅시다. 1. **MonsterSpawn**을 스크립트 에디터에서 열고 **Vector3** 타입의 새 함수 `GetRandomPosition()`을 추가합니다. 2. `GetRandomPosition()` 함수를 다음과 같이 작성합니다. 위에서 기록해두었던 좌표를 함수에 활용합니다. ```lua Vector3 GetRandomPositio
[task] | single_turn [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | 몬스터를 처치했을 때 아이템이 드랍되는 과정은 이 가이드의 몇 편에서 다루고 있나요? [answer] | 몬스터 처치 시 아이템이 드랍되는 과정은 이 가이드의 **2편**에서 다루고 있습니다. 2편의 제목은 "몬스터 드랍 아이템과 인벤토리 UI 만들기"이며, 몬스터를 처치하면 아이템을 드랍하고 이를 인벤토리에 저장하는 일련의 과정을 구현하는 단계입니다. [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] | `SpawnMonster()` 함수 내에서 사용된 서비스 메서드 이름과 전달 인자 4개를 표로 정리해서 출력하세요. [answer] | `SpawnMonster()` 함수에서 사용된 서비스 메서드와 전달 인자는 다음과 같습니다. | 서비스 메서드 | 전달 인자 1 | 전달 인자 2 | 전달 인자 3 | 전달 인자 4 | | :--- | :--- | :--- | :--- | :--- | | `_SpawnService:SpawnByModelId` | `"Entry ID"` | `"SpawnedMonster"` | `self:GetRandomPosition()` | `parent` | 참고로, `parent` 변수는 `_EntityService:GetEntityByP [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 지정한 영역 안에서 랜덤한 위치에 몬스터를 스폰하는 기능을 추가하겠습니다. 위에 확인했던 좌표를 기준으로 스폰 영역을 정의하고, 영역 내 랜덤한 위치에 몬스터를 스폰해 봅시다. 1. **MonsterSpawn**을 스크립트 에디터에서 열고 **Vector3** 타입의 새 함수 `GetRandomPosition()`을 추가합니다. 2. `GetRandomPosition()` 함수를 다음과 같이 작성합니다. 위에서 기록해두었던 좌표를 함수에 활용합니다. ```lua Vector3 GetRandomPositio