← 목록

mLua · Nemotron SDG 질문-응답 (SFT)

총 21,567개 · 페이지 390/719
🔀 랜덤
불러오는 중…

[task] | two_turn [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | 몬스터 스폰 시스템의 기본 규칙(최대 10마리, 5초 리스폰, 특정 영역 랜덤 위치)을 mLua로 구현하는 가장 기본적인 구조는 어떻게 되나요? [answer] | 제공된 참고 문서에는 "몬스터를 스폰해 보자"는 제목의 가이드가 포함되어 있으나, 실제 mLua 코드는 **몬스터 처치 시 아이템 드랍 및 인벤토리 저장** 과정에 초점을 맞추고 있습니다. 문서에는 다음 내용만 명시되어 있습니다: 1. **스포닝 목표**: 맵에 최대 10마리 유지 2. **리스폰 주기**: 5초마다 체크 후 부족한 수량만큼 리스폰 3. **스포닝 위치**: 특정 영역 내 랜덤 위치 그러나 이 규칙을 구현하는 **구체적인 mLua 코드(최대 수량 체크, 리스폰 타이머, 랜덤 위치 계산, `_SpawnServ [followup] | 5초마다 맵 내 몬스터 수를 체크하고 부족한 만큼 리스폰하는 로직을 `OnUpdate` 또는 타이머 서비스(`_TimerService`)를 활용해 구체적으로 작성해 주세요. [followup_answer] | 제공된 참고 문서에는 "5초마다 맵 내 몬스터 수를 체크하고 부족한 만큼 리스폰하는" 구체적인 mLua 코드(최대 수량 카운팅, 리스폰 타이머 설정, `_SpawnService`를 통한 몬스터 생성 호출 등)가 **포함되어 있지 않습니다.** 문서에 포함된 코드 예제는 모두 **몬스터 소멸 시 아이템 드랍 처리**(`OnMonsterDestroy`, `DropItem`)와 관련되어 있으며, 몬스터를 스폰(생성)하는 로직의 구현 코드는 제시되지 않았습니다. 따라서 요청하신 "5초 주기 몬스터 수 체크 및 리스폰 로직"의 mLua [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] | `MaxSpawnCount` 프로퍼티에 `[Sync]` 태그를 붙인 이유는 무엇이며, 클라이언트에서도 이 값을 읽을 수 있나요? [answer] | `MaxSpawnCount` 프로퍼티에 `[Sync]` 태그를 붙인 이유는 서버와 클라이언트 간에 해당 값이 동기화되도록 하기 위해서입니다. `[Sync]` 태그가 붙은 프로퍼티는 서버에서 값을 변경하면 클라이언트에도 자동으로 반영됩니다. 따라서 클라이언트에서도 `MaxSpawnCount` 값을 읽을 수 있습니다. [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] | code [pass] | ⏳ 미판정 [title] | 스크립트 디버그 [question] | _TimerService와 wait()를 활용하여 OnBeginPlay 실행 후 2초 동안 대기한 뒤 log()로 "Timer Finished"를 출력하는 스크립트를 작성해줘 [answer] | `wait()` 함수는 코드의 실행을 일시정지시키는 용도로 사용되며, `_TimerService`와 함께 특정 시점에 작업을 실행하는 데에는 `wait()`만 사용하는 것이 일반적입니다. 하지만 질문에서는 `_TimerService`와 `wait()`를 **동시에** 활용하라고 요청하고 있습니다. 참고 문서에 따르면 `_TimerService`는 타이머를 예약하고 콜백 함수를 실행하는 서비스입니다. `wait()` 함수는 mLua 스크립트 규칙에 따라 사용 가능한 표준 함수로 명시되어 있습니다. 두 가지 방식을 모두 충족하려면, [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | ## 학습 과정 소개 디버그 기능을 통해 스크립트를 디버깅하는 방법에 대해 알아봅니다. ## 중단점(Breakpoints) 스크립트 디버깅의 시작은 중단점 설정에서 시작됩니다. 이상이 발생하거나, 오작동의 원인으로 의심되는 코드 라인에 중단점을 설정 또는 해제하는 방법을 알아봅니다. ### 중단점 아이콘 중단점 설정 상태에 따라 아이콘이 다르게 나타납니다. |아이콘 | 이름 | 설명| ---|---|--- | ![[object Object]](https://mod-file.dn.nexoncdn.co.kr/bbs/17691

[task] | two_turn [pass] | ⏳ 미판정 [title] | 스크립트 디버그 [question] | Call Stack 패널을 통해 함수 호출 순서를 확인할 때, OnBeginPlay에서 시작하여 여러 메서드를 거쳐 특정 함수에 도달한 경우 어떤 정보를 제공받나요? [answer] | Call Stack(콜스택) 패널을 열면 현재 디버깅 중인 함수가 어디서부터 시작되어 호출되었는지에 대한 정보를 확인할 수 있습니다. `OnBeginPlay`를 시작으로 `Method1`, `Method2`를 거쳐 특정 함수(예: `Method3`)에 도달한 경우, `Method3`까지 도달하기까지의 **함수 호출 순서**와 각 함수의 **실행 공간**(예: `[server only]`, `[client only]` 등)을 함께 제공합니다. 이를 통해 코드 흐름이 어떤 경로를 거쳐 현재 중단점에 도달했는지 파악할 수 있습니다. [followup] | OnBeginPlay → Method1 → Method2 → Method3 호출 흐름에서 Method3 내부 디버그 시 Call Stack에서 보이는 항목과 실행 공간 확인 방법을 설명해 주세요. [followup_answer] | `OnBeginPlay` → `Method1` → `Method2` → `Method3` 호출 흐름에서 `Method3` 내부에 중단점을 설정하고 디버깅을 수행하면, 내비게이션 메뉴의 **Panels - Debug - Call Stack**을 클릭해 Call Stack 패널을 열 수 있습니다. 이 패널에서는 `Method3`까지 도달하기까지의 **함수 호출 순서**를 상단에서 하단으로(또는 호출 발생 순서대로) 확인할 수 있으며, 각 함수 항목과 함께 해당 함수가 선언된 **실행 공간**(예: `[server only]`, `[c [scores] | [judge_reason] | [source_doc] | 중단점을 설정한 코드를 확인했을 때 문제가 없다면, 혹은 해당 코드 아래 줄의 상태도 함께 확인하고 싶다면 어떻게 해야 할까요? 확인하고자 하는 모든 코드 라인에 중단점을 설정할 수도 없고, 매번 디버그 시작/중지를 반복하며 중단점 설정 해제를 반복하는 것도 비효율적입니다. 디버깅 중 중단점에서 플레이가 멈춘 뒤, 중단점이 설정된 라인 이후로 코드를 실행하는 방법이 있습니다. **프로시저 단위 실행**, **한 단계씩 코드 실행** 등을 통해 단위별로 코드를 실행하며 코드의 상태나 흐름을 파악할 수 있습니다. 단위별 코드 실행은 디

[task] | single_turn [pass] | ⏳ 미판정 [title] | 점프대 만들기 [question] | 캐릭터가 바라보는 방향에 따라 힘의 방향을 바꾸기 위해 controller.LookDirectionX의 부호를 판단하는 방식은, 캐릭터가 정면을 보고 있을 때에도 정상적으로 동작하나요? [answer] | 제공된 참고 문서의 코드 예제와 설명을 보면, `controller.LookDirectionX`가 0 (정면을 보고 있는 상태)인 경우를 명시적으로 처리하는 로직이 없습니다. 문서에 제시된 코드는 다음과 같이 작성되어 있습니다: ```lua if controller.LookDirectionX > 0 then rigidbody:SetForce(Vector2(10,10)) else rigidbody:SetForce(Vector2(-10,10)) end ``` 이 코드는 `LookDirectionX`가 양수(> [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 점프대에 닿으면 캐릭터가 높이 솟아오르는 점프대를 만들어 봅니다. 이번 예제를 통해 확장 스크립트 작성법과 스크립트를 통해 물체와의 충돌 및 충돌 시 처리, 그리고 물체에 물리적인 힘을 가하는 방법에 대해 알아봅니다. 추가로 컴포넌트에 프로퍼티를 추가하고, 오브젝트별로 다른 프로퍼티 값을 설정하는 방법을 알아봅니다. # 점프대 배치하기 1. **Preset List**에서 스프링 모양의 모델(object-4575)을 찾아 맵에 배치합니다. # TriggerComponent로 충돌 기능 활용하기 물체와

[task] | single_turn [pass] | ⏳ 미판정 [title] | 점프대 만들기 [question] | TriggerComponent를 확장해서 만든 Spring 스크립트에서 __base:OnEnterTriggerBody(enterEvent) 호출이 왜 필요한지 궁금해요. [answer] | `__base:OnEnterTriggerBody(enterEvent)` 호출은 확장(Extend)된 컴포넌트에서 **기존 `TriggerComponent`의 기본 동작이 정상적으로 수행되도록** 하기 위해 필요합니다. 메이플스토리 월드에서 기존 컴포넌트를 확장하여 새 스크립트를 만들 때, 새 함수(예: `OnEnterTriggerBody`)가 기존 컴포넌트가 이미 가지고 있던 동일한 이름의 함수를 덮어쓰기(override)하는 형태입니다. 만약 `__base` 호출을 하지 않으면, `TriggerComponent`가 원래 수행해야 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 점프대에 닿으면 캐릭터가 높이 솟아오르는 점프대를 만들어 봅니다. 이번 예제를 통해 확장 스크립트 작성법과 스크립트를 통해 물체와의 충돌 및 충돌 시 처리, 그리고 물체에 물리적인 힘을 가하는 방법에 대해 알아봅니다. 추가로 컴포넌트에 프로퍼티를 추가하고, 오브젝트별로 다른 프로퍼티 값을 설정하는 방법을 알아봅니다. # 점프대 배치하기 1. **Preset List**에서 스프링 모양의 모델(object-4575)을 찾아 맵에 배치합니다. # TriggerComponent로 충돌 기능 활용하기 물체와

[task] | instruction_following [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | 5초마다 실행되는 리스폰 로직을 구현하는 mLua 스크립트 코드만 출력하고, 로직 설명은 주석으로 작성하세요. [answer] | ```lua Property: [None] number MaxMonsterCount = 10 number RespawnInterval = 5 string MonsterModelId = "Monster001" Vector3 SpawnAreaMin = Vector3(0, 0, 0) Vector3 SpawnAreaMax = Vector3(10, 0, 10) Method: [server only] void OnBeginPlay() { -- 초기화: 현재 몬스터 수 카운트 변수를 0으로 설정 self.CurrentMonste [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] | 몬스터를 스폰해 보자 [question] | 몬스터 스폰 시 현재 개수를 체크하여 최대 수량 부족분만 생성하도록 수정하는 원리는 무엇인가요? [answer] | 몬스터 스폰 시 현재 개수를 체크하여 최대 수량 부족분만 생성하는 원리는 **5초마다 실행되는 타이머 로직**에 있습니다. 1. **시간 누적:** `OnUpdate` 함수에서 매 프레임 `delta`를 `self.Time`에 더합니다. 2. **5초 주기 확인:** `self.Time`이 5초 이상 도달하면 타이머를 0으로 리셋하고 스폰 로직을 실행합니다. 3. **현재 개수 조회:** `self:GetCurMonsterCount()`를 호출하여 현재 활성 상태인 몬스터의 수(`curMonsterCnt`)를 가져옵니다. 4 [followup] | GetRandomPosition()이 table을 반환하도록 바꾸고, SpawnMonster()와 OnUpdate()에서 이 table과 spawnCount를 어떻게 활용하는지 코드 흐름을 설명해 주세요. [followup_answer] | `GetRandomPosition()`이 `table`을 반환하도록 변경된 후, `SpawnMonster()`와 `OnUpdate()`에서 이 테이블과 `spawnCount`를 활용하는 코드 흐름은 다음과 같습니다. ### 1. `OnUpdate()`: 스폰 개수 결정 및 트리거 `OnUpdate()`는 5초 주기로 실행되며, 실제 스폰할 개수(`spawnCount`)를 계산하여 `SpawnMonster()`에 전달하는 역할을 합니다. 1. **시간 체크:** `self.Time`이 5초 이상 되면 타이머를 리셋합니다. 2. [scores] | [judge_reason] | [source_doc] | 이번에는 5초마다 한 마리씩 스폰하는 것이 아니라, 5초마다 현재 몬스터 수량을 체크하여 최대 몬스터 수량보다 부족한 만큼 생성하도록 수정해 봅시다. 1. **MonsterSpawn**의 `GetRandomPosition()` 함수에 매개 변수를 하나 추가합니다. 2. 매개 변수 타입은 **number**로, 이름은 **spawnCount**로 설정하고, 리턴 타입을 **table**로 변경합니다. 함수는 다음과 같이 수정합니다. ```lua table GetRandomPosition(nu

[task] | instruction_following [pass] | ⏳ 미판정 [title] | 프로퍼티 [question] | Vector3과 Vector4의 차이점을 멤버 변수 기준으로 3문장 이내로 설명하세요. [answer] | Vector3은 3차원 벡터를 표현하며 x, y, z 멤버 변수를 가집니다. Vector4는 4차원 벡터를 표현하며 Vector3에 w 멤버 변수가 추가된 것입니다. 따라서 두 타입의 차이는 Vector4에 w 성분이 존재하는지 여부입니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 3차원 벡터와 위치를 표현합니다. **Vector2**와 마찬가지로 프로퍼티 또는 변수에 할당 시 참조됩니다. **Vector2**에서 멤버 변수 z가 추가됩니다. **TransformComponent**의 **Position**에 할당할 때를 제외하곤 주로 **Vector2**를 사용합니다. 값의 생성과 참조, 그리고 멤버 변수 x, y, z에 접근하는 방법은 아래를 참고합니다. ```lua Method: [Server Only] void OnBeginPlay() { local tmpVector3 = Vector3(10,

[task] | two_turn [pass] | ⏳ 미판정 [title] | 엔티티를 탐색하는 EntityService [question] | EntityService에서 제공하는 8개의 탐색 함수 중 나머지 함수들(예: GetEntitiesSpawnedByModelId 등)도 함께 비교하며, 각각의 매개 변수(worldPath, entityId, modelId)를 어떻게 조합하여 상황에 맞게 선택해야 하는지 정리해 주세요. [answer] | 제공된 참고 문서에는 `EntityService`에서 제공하는 8개의 탐색 함수 중 **`GetEntityByPath()`**, **`GetEntitiesByPath()`**, **`GetEntity()`** 단 3개 함수의 상세 설명과 예제 코드만 포함되어 있습니다. 문서에 언급된 **`GetEntitiesSpawnedByModelId()`**를 제외한 나머지 5개 함수의 이름, 매개 변수, 사용법은 문서에 존재하지 않으므로 설명할 수 없습니다. 또한, 문서에 없는 API나 매개 변수 조합을 지어내어 답변하는 것은 불가능합니다. [followup] | 탄막 슈팅 게임에서 모델 ID를 기반으로 생성된 총알 엔티티들을 모두 찾아서, 그 중 생명력이 0 이하인 엔티티를 찾아 삭제하는 로직을 GetEntitiesSpawnedByModelId()와 EntityService의 삭제 기능을 활용하여 구현해 주세요. [followup_answer] | 제공된 참고 문서에는 `GetEntitiesSpawnedByModelId()` 함수가 "8개의 엔티티 탐색 함수" 중 하나로 언급되어 있고, 함수 이름에서 모델 ID를 기반으로 엔티티를 탐색한다는 것이 암시되지만, **해당 함수의 구체적인 매개 변수 목록, 반환 타입, 사용 예제 코드가 문서에 포함되어 있지 않습니다.** 또한, 질문에서 요구하는 **`EntityService`의 삭제 기능(예: `DeleteEntity` 등)**과 **엔티티의 생명력(HP)을 확인하는 방법(컴포넌트 접근 등)**에 대한 정보도 제공된 문서에 존재 [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 월드를 제작하다 보면 특정 엔티티를 탐색하여 받아오거나, 혹은 관련 있는 여러 엔티티를 한 번에 받아야 하는 상황이 자주 발생합니다. 이럴 때 [**EntityService**](/apiReference/Services/EntityService)를 활용할 수 있습니다. **EntityService**는 엔티티 탐색, 삭제, 유효성 체크 등의 기능을 제공하고 있습니다. 이번 과정에서는 **EntityService**에서 제공하는 기능의 사용법을 하나씩 알아보도록 하겠습니다. **테스트 환경** **common

[task] | two_turn [pass] | ⏳ 미판정 [title] | 프로퍼티 [question] | SyncTable< v > 타입의 프로퍼티를 정의할 때 일반 table과 달리 `next` 함수를 사용할 수 없는 제약이 있나요? [answer] | 네, `SyncTable< v >` 타입의 프로퍼티는 일반 `table`과 달리 `next` 함수를 사용할 수 없습니다. `SyncTable< v >`는 루아의 table 형태를 가지지만 동기화(Sync)가 가능한 제약이 있는 타입입니다. 일반 table 프로퍼티와 마찬가지로 정해진 타입 중 한 가지(value 타입)만 설정할 수 있지만, 내부 구조가 일반 table과 다르기 때문에 `next` 함수를 통한 반복 처리를 지원하지 않습니다. 또한 일반 table보다 성능이 다소 느릴 수 있다는 점도 참고해야 합니다. 참고로, 일반 [followup] | SyncTable< string, number >를 사용하여 서버에서 값을 수정하고 클라이언트에서 동기화되는 과정을 보여주는 코드 예시를 작성해 주세요. [followup_answer] | 참고 문서에는 `SyncTable< k, v >` 타입의 정의와 제약 사항(`next` 함수 사용 불가, 동기화 가능, 일반 table보다 느림)만 설명되어 있으며, 서버에서 값을 수정하고 클라이언트에서 동기화되는 구체적인 코드 예제는 제공되지 않습니다. 따라서 요청하신 특정 시나리오를 보여주는 코드 예시를 작성해 드릴 수 없습니다. 다만, 문서에 명시된 `SyncTable< k, v >`의 기본 특성은 다음과 같습니다: * **타입 제약**: key와 value에 각각 정해진 타입만 설정할 수 있습니다. (예: `SyncT [scores] | [judge_reason] | [source_doc] | #### table 루아 테이블을 참조합니다. 동기화(Sync)는 되지 않습니다. ```lua Property: [None] table TableProperty = {1,2,3,4,5} Method: [Server Only] void OnBeginPlay() { local tmpTable = self.TableProperty self.TableProperty[1] = 10 log("tmpTable : "..tmpTable[1]) --콘솔 창에 "tmpTable : 10" 출력 log("TablePr

[task] | code [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | _SpawnService 를 사용해 Preset List 의 몬스터를 지정된 좌표에 스폰하는 스크립트를 작성해줘 [answer] | Preset List에 추가한 몬스터를 지정된 좌표에 스폰하려면, 먼저 `_EntityService:GetEntityByPath`를 통해 해당 몬스터 엔티티의 참조를 가져온 뒤 `_SpawnService:SpawnByEntityTemplate` 메서드를 사용해야 합니다. 아래는 지정된 좌표에 몬스터를 스폰하는 mLua 스크립트 예시입니다. ```lua Property: [None] Vector3 SpawnPosition = Vector3(0, 0, 0) string MonsterName = "spawnedMonster" stri [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] | 몬스터가 죽어서 사라진 경우에도 `MonsterArray` 에 남아있는 참조를 정리하는 로직은 어디에 구현되어 있나요? [answer] | 몬스터가 죽어서 사라진 경우 `MonsterArray` 에 남아있는 참조를 정리하는 로직은 **`GetCurMonsterCount()`** 함수 안에 구현되어 있습니다. 이 함수는 테이블을 순회하면서 각 항목이 여전히 유효한 엔티티인지 `isvalid()` 함수로 확인합니다. 유효하지 않다면(즉, 몬스터가 사라진 경우) `table.remove()` 를 통해 해당 항목을 배열에서 제거합니다. 구체적인 구현 코드는 다음과 같습니다. ```lua number GetCurMonsterCount() { local i = 1 [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] | 몬스터가 10마리 모두 살아있는 상태에서 5초가 지나도 새로운 몬스터가 스폰되지 않는 것은 정상적인 동작인가요? [answer] | 네, 정상적인 동작입니다. 제시된 스크립트 로직을 살펴보면 `OnUpdate` 함수 내에서 다음과 같은 조건이 만족될 때에만 새로운 몬스터가 스폰됩니다. 1. 5초 간격이 지난 경우 (`self.Time >= 5`) 2. 현재 살아있는 몬스터 수가 `MaxSpawnCount`(기본값 10)보다 작은 경우 (`curMonsterCnt < self.MaxSpawnCount`) `GetCurMonsterCount()` 함수는 `MonsterArray` 배열에서 실제로 존재하는(`isvalid`가 true인) 몬스터 엔티티의 개수 [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] | SpawnMonster 함수에서 parent 를 _EntityService:GetEntityByPath 로 직접 지정하는 것과 self 를 parent 로 사용하는 것의 차이점이 무엇인가요? [answer] | 제공된 참고 문서에는 `SpawnMonster` 함수에서 `parent` 파라미터에 `_EntityService:GetEntityByPath`로 가져온 엔티티를 전달하는 예제만 포함되어 있으며, `self`를 parent로 사용하는 경우의 동작이나 두 방식의 차이점에 대한 설명이 없습니다. 따라서 제공된 문서 범위 내에서 두 방식의 차이점을 설명할 수 없습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 지정한 영역 안에서 랜덤한 위치에 몬스터를 스폰하는 기능을 추가하겠습니다. 위에 확인했던 좌표를 기준으로 스폰 영역을 정의하고, 영역 내 랜덤한 위치에 몬스터를 스폰해 봅시다. 1. **MonsterSpawn**을 스크립트 에디터에서 열고 **Vector3** 타입의 새 함수 `GetRandomPosition()`을 추가합니다. 2. `GetRandomPosition()` 함수를 다음과 같이 작성합니다. 위에서 기록해두었던 좌표를 함수에 활용합니다. ```lua Vector3 GetRandomPositio

[task] | single_turn [pass] | ⏳ 미판정 [title] | 점프대 만들기 [question] | enterEvent.TriggerBodyEntity로 가져온 플레이어 엔티티에서 RigidbodyComponent나 PlayerControllerComponent가 nil인 경우를 방지하기 위해 어떤 확인 로직을 넣어야 하나요? [answer] | `enterEvent.TriggerBodyEntity`로 가져온 엔티티에서 특정 컴포넌트가 존재하지 않을 수 있으므로, 해당 컴포넌트가 `nil`인지 확인하는 방어적 코딩을 수행해야 합니다. 문서에 제시된 점프대 스크립트 예제에서 볼 수 있듯이, `RigidbodyComponent`와 `PlayerControllerComponent`를 각각 변수에 할당받은 후, 값이 `nil`인 경우 함수를 즉시 종료(`return`)하도록 체크하는 로직을 추가합니다. 아래는 요청하신 확인 로직이 포함된 `OnEnterTriggerBody` 메 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 점프대에 닿으면 캐릭터가 높이 솟아오르는 점프대를 만들어 봅니다. 이번 예제를 통해 확장 스크립트 작성법과 스크립트를 통해 물체와의 충돌 및 충돌 시 처리, 그리고 물체에 물리적인 힘을 가하는 방법에 대해 알아봅니다. 추가로 컴포넌트에 프로퍼티를 추가하고, 오브젝트별로 다른 프로퍼티 값을 설정하는 방법을 알아봅니다. # 점프대 배치하기 1. **Preset List**에서 스프링 모양의 모델(object-4575)을 찾아 맵에 배치합니다. # TriggerComponent로 충돌 기능 활용하기 물체와

[task] | instruction_following [pass] | ⏳ 미판정 [title] | 프로퍼티 [question] | Entity와 EntityRef의 차이점을 비교 대상으로, 설명, 성능, 안정성 항목을 포함하여 표로 정리하세요. [answer] | Entity와 EntityRef의 차이점은 다음과 같습니다. | 구분 | Entity | EntityRef | | :--- | :--- | :--- | | **설명** | 엔티티를 직접 참조합니다. | 엔티티의 키 값을 가지고 있다가 실제 접근할 때 엔티티를 찾습니다. | | **성능** | 직접 참조하므로 접근이 빠릅니다. | 접근할 때마다 엔티티를 탐색해야 하므로 Entity보다 느립니다. | | **안정성** | 다른 맵으로 이동했다가 다시 돌아온 경우 참조가 끊어져 프로퍼티를 사용할 수 없게 됩니다. | 다른 맵에 갔다 왔 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 3차원 벡터와 위치를 표현합니다. **Vector2**와 마찬가지로 프로퍼티 또는 변수에 할당 시 참조됩니다. **Vector2**에서 멤버 변수 z가 추가됩니다. **TransformComponent**의 **Position**에 할당할 때를 제외하곤 주로 **Vector2**를 사용합니다. 값의 생성과 참조, 그리고 멤버 변수 x, y, z에 접근하는 방법은 아래를 참고합니다. ```lua Method: [Server Only] void OnBeginPlay() { local tmpVector3 = Vector3(10,

[task] | code [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | isvalid 로 엔티티 유효성을 검사하여 죽은 몬스터를 table.remove 로 제거하고 남은 수를 반환하는 GetCurMonsterCount 메서드를 작성해줘 [answer] | 요청하신 `GetCurMonsterCount` 메서드는 `isvalid` 함수를 사용해 테이블에 저장된 몬스터 엔티티가 여전히 유효한지(즉, 살아있는지) 검사합니다. 유효하지 않으면 해당 인덱스를 `table.remove`로 제거하고, 최종적으로 테이블의 길이(`#`)를 반환하여 현재 생존 중인 몬스터 수를 계산합니다. ```lua Method: [server only] number GetCurMonsterCount() { local i = 1 while i <= #self.MonsterArray do [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] | SyncTable< k, v > 타입의 제약 사항과 일반 table 프로퍼티와의 성능 차이를 3문장 이내로 요약하세요. [answer] | SyncTable< k, v >는 next 함수 사용이 불가능하고, key와 value에 각각 정해진 타입만 설정할 수 있습니다. 일반 table 프로퍼티와 달리 동기화(Sync)를 지원하지만, 일반 table보다는 다소 느린 성능을 보입니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | #### table 루아 테이블을 참조합니다. 동기화(Sync)는 되지 않습니다. ```lua Property: [None] table TableProperty = {1,2,3,4,5} Method: [Server Only] void OnBeginPlay() { local tmpTable = self.TableProperty self.TableProperty[1] = 10 log("tmpTable : "..tmpTable[1]) --콘솔 창에 "tmpTable : 10" 출력 log("TablePr

[task] | single_turn [pass] | ⏳ 미판정 [title] | 점프대 만들기 [question] | SetForce 함수에 Vector2(10,10)을 전달할 때 X와 Y 값의 크기가 점프 고도와 이동 거리에 각각 어떤 영향을 미치는지 테스트해 보고 싶어요. [answer] | 참고 문서에 `SetForce` 함수에 전달하는 `Vector2`의 X, Y 값이 점프 고도와 이동 거리에 구체적으로 어떤 영향을 미치는지에 대한 수치적 설명이나 공식은 포함되어 있지 않습니다. 문서에 따르면 `SetForce`는 캐릭터가 바라보는 방향(`LookDirectionX`)에 따라 X 좌표의 부호만 바꾸고, Y 좌표는 항상 10으로 고정된 `Vector2(10, 10)` 또는 `Vector2(-10, 10)`을 전달하도록 예제 코드가 제시되어 있을 뿐입니다. 따라서 X, Y 값의 크기가 물리적 결과(고도, 거리)에 미치 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 점프대에 닿으면 캐릭터가 높이 솟아오르는 점프대를 만들어 봅니다. 이번 예제를 통해 확장 스크립트 작성법과 스크립트를 통해 물체와의 충돌 및 충돌 시 처리, 그리고 물체에 물리적인 힘을 가하는 방법에 대해 알아봅니다. 추가로 컴포넌트에 프로퍼티를 추가하고, 오브젝트별로 다른 프로퍼티 값을 설정하는 방법을 알아봅니다. # 점프대 배치하기 1. **Preset List**에서 스프링 모양의 모델(object-4575)을 찾아 맵에 배치합니다. # TriggerComponent로 충돌 기능 활용하기 물체와

[task] | instruction_following [pass] | ⏳ 미판정 [title] | 프로퍼티 [question] | table 프로퍼티와 SyncTable< v > 프로퍼티의 동기화 가능 여부와 next 함수 사용 가능 여부를 비교하여 표로 정리하세요. [answer] | `table` 프로퍼티와 `SyncTable< v >` 프로퍼티의 비교는 다음과 같습니다. | 구분 | table | SyncTable< v > | | :--- | :---: | :---: | | **동기화(Sync) 가능 여부** | 불가능 | 가능 | | **`next` 함수 사용 가능 여부** | 가능 | 불가능 | * **table**: 루아 테이블을 참조하며 동기화(Sync)는 되지 않습니다. * **SyncTable< v >**: 루아의 table 형태이지만 제약이 있는 타입으로 `next` 함수는 사용할 수 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | #### table 루아 테이블을 참조합니다. 동기화(Sync)는 되지 않습니다. ```lua Property: [None] table TableProperty = {1,2,3,4,5} Method: [Server Only] void OnBeginPlay() { local tmpTable = self.TableProperty self.TableProperty[1] = 10 log("tmpTable : "..tmpTable[1]) --콘솔 창에 "tmpTable : 10" 출력 log("TablePr

[task] | two_turn [pass] | ⏳ 미판정 [title] | 스크립트 디버그 [question] | Watch Expression에 변수와 프로퍼티를 등록할 때 각각 어떤 형식으로 이름을 입력해야 하며, 등록 후 값 변화를 추적하는 과정은 어떻게 이루어지나요? [answer] | Watch Expression에 변수와 프로퍼티를 등록할 때의 형식과 값 변화 추적 과정은 다음과 같습니다. ### 1. 등록 형식 Watch Expression 패널의 **Add Expression** 입력창에 이름을 입력할 때, 대상에 따라 아래 형식을 사용해야 합니다. * **함수 내부에서 선언된 변수**: 변수 이름만 입력합니다. * 예: `text` * **스크립트 프로퍼티**: `self.` 접두사와 프로퍼티 명을 붙여 입력합니다. * 예: `self.Power` ### 2. 값 변화 추 [followup] | 현재 포커싱된 함수의 지역 변수와 self 프로퍼티를 Watch Expression에 추가하는 정확한 문법과, F11 실행 시 값이 갱신되는 방식을 코드 예시와 함께 알려주세요. [followup_answer] | Watch Expression에 지역 변수와 self 프로퍼티를 추가하는 정확한 문법과 F11 실행 시 값이 갱신되는 방식은 다음과 같습니다. ### 1. Watch Expression 추가 문법 내비게이션 메뉴의 **Panels - Debug - Watch Expression**을 열어 **Add Expression** 입력창에 아래 형식으로 이름을 입력합니다. * **현재 포커싱된 함수의 지역 변수**: 변수 이름만 입력합니다. * **self 프로퍼티**: `self.프로퍼티 명` 형식으로 입력합니다. ### 2. [scores] | [judge_reason] | [source_doc] | 중단점을 설정한 코드를 확인했을 때 문제가 없다면, 혹은 해당 코드 아래 줄의 상태도 함께 확인하고 싶다면 어떻게 해야 할까요? 확인하고자 하는 모든 코드 라인에 중단점을 설정할 수도 없고, 매번 디버그 시작/중지를 반복하며 중단점 설정 해제를 반복하는 것도 비효율적입니다. 디버깅 중 중단점에서 플레이가 멈춘 뒤, 중단점이 설정된 라인 이후로 코드를 실행하는 방법이 있습니다. **프로시저 단위 실행**, **한 단계씩 코드 실행** 등을 통해 단위별로 코드를 실행하며 코드의 상태나 흐름을 파악할 수 있습니다. 단위별 코드 실행은 디

[task] | code [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | _TimerService 를 이용해 5초 간격으로 맵 내 몬스터 개수를 확인하고 최대 10마리를 유지하도록 리스폰하는 스크립트를 작성해줘 [answer] | 제시된 참고 문서에는 `_TimerService`를 사용하여 주기적으로 타이머를 설정하는 방법(`SetTimer`의 반복 옵션 사용)과 `_EntityService`를 사용하여 엔티티를 스폰하는 일반적인 구조는 포함되어 있으나, **현재 맵 내 특정 타입(몬스터)의 엔티티 개수를 카운트하는 API나, 특정 영역 내에서 랜덤 좌표를 생성하는 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] | single_turn [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | 몬스터가 맵의 특정 좌표가 아닌 원하는 영역 내에서 랜덤하게 스폰되려면 어떤 좌표 값을 매개변수로 전달해야 하나요? [answer] | 몬스터가 특정 좌표가 아닌 원하는 영역 내에서 랜덤하게 스폰되려면, `_SpawnService:SpawnByModelId` 함수의 세 번째 매개변수인 위치(`Vector3`)에 고정된 값 대신 **랜덤 값**을 계산하여 전달해야 합니다. 참고 문서에는 `math.random` 등 구체적인 랜덤 함수 사용 예제가 명시되어 있지 않지만, mLua는 Lua 5.3 기반이므로 Lua 표준 라이브러리의 `math.random` 함수를 활용하여 영역의 최소/최대 좌표 사이에서 랜덤한 x, z 좌표 값을 생성한 뒤 `Vector3` 객체에 담 [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] | 디버그 중 중단점에서 멈춘 후, 함수 내부로 진입하거나 현재 함수를 빠져나가는 실행 단위별 버튼의 차이는 무엇인가요? [answer] | 중단점에서 멈춘 후, 함수 내부로 진입하거나 현재 함수를 빠져나가는 실행 단위별 버튼의 차이는 다음과 같습니다. 1. **한 단계씩 코드 실행 (F11)** * **기능**: 코드를 한 줄씩 실행합니다. * **함수 진입 여부**: 포커싱된 라인에 함수 호출이 있을 경우, 해당 **함수 내부로 들어가서** 함수 내 코드를 한 줄씩 실행합니다. * **용도**: 함수 내부의 로직을 디테일하게 추적하고 싶을 때 사용합니다. 2. **프로시저 나가기 (Shift + F11)** * **기능**: 현 [followup] | 프로시저 단위 실행(F10)과 한 단계씩 코드 실행(F11)의 차이, 그리고 프로시저 나가기(Shift+F11)를 언제 사용해야 하는지 구체적으로 설명해 주세요. [followup_answer] | 프로시저 단위 실행(F10), 한 단계씩 코드 실행(F11), 프로시저 나가기(Shift+F11)의 차이와 사용 시기는 다음과 같습니다. ### 1. 프로시저 단위 실행 (F10) vs 한 단계씩 코드 실행 (F11) 두 버튼 모두 코드를 한 줄씩 실행하지만, **함수 호출이 포함된 라인에서 어떻게 동작하는지**가 다릅니다. * **프로시저 단위 실행 (F10)** * **동작**: 포커싱된 라인에 함수 호출이 있을 경우, 해당 함수를 실행한 것으로 간주하고 **함수 내부로 들어가지 않고** 바로 다음 줄로 넘어 [scores] | [judge_reason] | [source_doc] | 중단점을 설정한 코드를 확인했을 때 문제가 없다면, 혹은 해당 코드 아래 줄의 상태도 함께 확인하고 싶다면 어떻게 해야 할까요? 확인하고자 하는 모든 코드 라인에 중단점을 설정할 수도 없고, 매번 디버그 시작/중지를 반복하며 중단점 설정 해제를 반복하는 것도 비효율적입니다. 디버깅 중 중단점에서 플레이가 멈춘 뒤, 중단점이 설정된 라인 이후로 코드를 실행하는 방법이 있습니다. **프로시저 단위 실행**, **한 단계씩 코드 실행** 등을 통해 단위별로 코드를 실행하며 코드의 상태나 흐름을 파악할 수 있습니다. 단위별 코드 실행은 디

[task] | code [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | `/maps/map01` 을 부모 엔티티로 지정하고 Entry ID "monster01" 로 몬스터를 Vector3(0,0,0) 위치에 스폰하는 SpawnMonster() 메서드를 구현한 MonsterSpawn 스크립트를 작성해줘. [answer] | `_EntityService:GetEntityByPath`로 부모 엔티티를 조회하고, `_SpawnService:SpawnByModelId`로 몬스터를 스폰하는 `SpawnMonster` 메서드를 포함하는 스크립트입니다. ```lua Method: [server only] void SpawnMonster() { local parent = _EntityService:GetEntityByPath("/maps/map01") _SpawnService:SpawnByModelId( "monster01", [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] | `GetCurMonsterCount()` 함수에서 `isvalid()` 체크를 수행하는 이유가 무엇이며, 이 부분을 생략하면 어떤 문제가 발생하나요? [answer] | `GetCurMonsterCount()` 함수에서 `isvalid()` 체크를 수행하는 이유는, `MonsterArray` 테이블에 저장된 몬스터 엔티티가 실제로 월드에 존재하는 유효한 객체인지 확인하기 위해서입니다. 몬스터는 사냥당하거나 다른 이유로 소거(Destroy)될 수 있습니다. 몬스터가 소거되면 해당 엔티티 참조는 더 이상 유효하지 않게 되지만, `MonsterArray` 테이블에서는 자동으로 제거되지 않습니다. 즉, 테이블 안에는 이미 사라진 몬스터에 대한 "죽은 참조(dead reference)"가 남아있게 됩니다. [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] | Vector2 프로퍼티의 x, y 멤버 변수를 수정할 때 참조를 통해 원본 프로퍼티 값이 변경되는지 여부를 검증하는 코드만 출력하고 설명은 주석으로 작성하세요. [answer] | ```lua Property: [Sync] Vector2 TargetVector = Vector2(0, 0) Method: [Server Only] void OnBeginPlay() { -- 1. 초기값 확인 log("Initial: " .. self.TargetVector.x .. ", " .. self.TargetVector.y) -- 2. 참조 변수 생성 (Vector2는 테이블 형태이므로 참조로 동작) local refVector = self.TargetVector -- 3. 참조 변 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | #### table 루아 테이블을 참조합니다. 동기화(Sync)는 되지 않습니다. ```lua Property: [None] table TableProperty = {1,2,3,4,5} Method: [Server Only] void OnBeginPlay() { local tmpTable = self.TableProperty self.TableProperty[1] = 10 log("tmpTable : "..tmpTable[1]) --콘솔 창에 "tmpTable : 10" 출력 log("TablePr

[task] | single_turn [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | 스폰 영역의 Y 좌표를 고정값 0.170 으로 설정했는데, 지형이 비평탄할 때 몬스터가 공중에 뜨거나 땅속으로 들어가는 현상을 방지하기 위해 어떻게 수정해야 하나요? [answer] | 제공된 참고 문서에는 지형의 높이(고도)를 실시간으로 조회하거나, 특정 지점의 지형 Y 좌표를 반환하는 API가 포함되어 있지 않습니다. 문서에 명시된 기능은 고정된 좌표 값(`y = 0.170`)을 사용하여 `Vector3` 위치를 생성하는 것입니다. 따라서 비평탄한 지형에서 몬스터가 공중에 뜨거나 땅속으로 들어가는 현상을 방지하기 위해 지형 높이에 따라 Y 좌표를 동적으로 조정하는 방법은 **참고 문서에 기재된 API나 기능이 없어 설명할 수 없습니다.** 현재 문서에서 확인 가능한 내용은 다음과 같습니다. 1. `GetRa [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 지정한 영역 안에서 랜덤한 위치에 몬스터를 스폰하는 기능을 추가하겠습니다. 위에 확인했던 좌표를 기준으로 스폰 영역을 정의하고, 영역 내 랜덤한 위치에 몬스터를 스폰해 봅시다. 1. **MonsterSpawn**을 스크립트 에디터에서 열고 **Vector3** 타입의 새 함수 `GetRandomPosition()`을 추가합니다. 2. `GetRandomPosition()` 함수를 다음과 같이 작성합니다. 위에서 기록해두었던 좌표를 함수에 활용합니다. ```lua Vector3 GetRandomPositio

[task] | single_turn [pass] | ⏳ 미판정 [title] | 몬스터를 스폰해 보자 [question] | _SpawnService:SpawnByModelId 호출 시 두 번째 인자로 넘기는 "SpawnedMonster" 이름과 몬스터 모델 ID의 관계가 무엇인지 궁금합니다. [answer] | 참고 문서에 포함된 정보만 기준으로 설명드리겠습니다. `_SpawnService:SpawnByModelId` 호출 시 두 번째 인자로 넘기는 `"SpawnedMonster"`는 **스폰된 엔티티의 이름**입니다. 문서 내 `SpawnMonster()` 함수 예제를 보면 다음과 같이 사용됩니다. ```lua _SpawnService:SpawnByModelId( "Entry ID", -- 첫 번째 인자: 몬스터 모델 ID "SpawnedMonster", -- 두 번째 인자: 스폰될 엔티티의 이름 se [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 지정한 영역 안에서 랜덤한 위치에 몬스터를 스폰하는 기능을 추가하겠습니다. 위에 확인했던 좌표를 기준으로 스폰 영역을 정의하고, 영역 내 랜덤한 위치에 몬스터를 스폰해 봅시다. 1. **MonsterSpawn**을 스크립트 에디터에서 열고 **Vector3** 타입의 새 함수 `GetRandomPosition()`을 추가합니다. 2. `GetRandomPosition()` 함수를 다음과 같이 작성합니다. 위에서 기록해두었던 좌표를 함수에 활용합니다. ```lua Vector3 GetRandomPositio

← → 방향키로 페이지 이동 · 숫자 입력 후 Enter로 점프