[task] | instruction_following [pass] | ⏳ 미판정 [title] | 행동 트리를 활용한 AI 만들기 [question] | 행동 트리가 FSM보다 유지 보수가 쉬운 이유를 3단계 번호 목록으로 작성하세요. [answer] | 1. **개별 로직의 모듈화와 재사용성**: 행동 트리의 각 노드는 상태와 전이로 묶인 유한 상태 기계(FSM)와 달리 개별 로직으로 독립적으로 모듈화되어 있어, 상황과 목적에 따라 쉽게 재사용할 수 있습니다. 2. **행동 연결과 해제의 용이성**: 각 노드가 결합 순서에 따라 순차적으로 실행되기 때문에, 특정 행동을 추가하거나 제거하는 과정이 단순해져 유지 보수 부담을 줄일 수 있습니다. 3. **복잡한 상태 흐름의 파악 및 관리 용이성**: FSM은 상태와 액션이 다양해지고 복잡해질수록 각 상태 간의 연결과 흐름 파악이 어려워 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 행동 트리와 BTNodeType 개념을 이해하고, AIComponent를 활용해 Action Node를 생성하는 방법을 알아봅시다. [행동 트리 노드 만들기](/docs?postId=1155)에서 행동 트리 구현 방법과 예제를 소개합니다. ##### 참고 가이드 * [행동 트리 노드 만들기](/docs?postId=1155) * [Behaviour Tree Editor로 행동 트리 만들기](/docs?postId=1399) ##### 참고 API Reference * [BTNode](/apiReference
[task] | single_turn [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | 카드 모델을 월드에 미리 배치하지 않고 실행 시점에 UI에 소환하도록 만들 때, 기존 모델 활용 방식과 다른 점은 무엇인가요? [answer] | 카드 모델을 월드에 미리 배치하지 않고 실행 시점에 UI에 소환하는 방식은 기존 모델 활용 방식과 다음과 같은 점이 다릅니다. 기존 방식에서는 모델을 만들어서 월드에 직접 배치하거나, 특정 로직에 따라 몬스터나 오브젝트처럼 월드에 스트라이트(배치)를 지정해 사용하는 것이 일반적입니다. 하지만 카드 짝 맞추기 게임에서는 카드가 UI의 일부로 동작해야 하므로, 모델을 월드에 물리적으로 배치하지 않습니다. 대신, `Model_Card`라는 모델을 '틀' 또는 '판본'으로만 정의해 두고, 게임이 시작될 때(`OnBeginPlay`) 스 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 리메이크한 월드에는 제작에 필요한 UI, 리소스, 그리고 비어 있는 컴포넌트 등이 있습니다. 단계 별로 하나씩 채워나가며 함께 게임을 완성해봅시다. # CardPairGameUI 활성화 월드에 유저가 입장하면 **CardPairGameUI**가 **Enable**로 변경되도록 만들어 봅시다. 월드 전체에 적용되는 규칙이나 로직을 만들 때는 Logic을 사용합니다. **CardPairGameLogic** 로직에는 짝 맞추기에 기본적으로 필요한 UI를 켜거나 끄기, 카드 입력 등 전반적인 규칙을 작성할 것입니다. 우선 월드에 입장
[task] | single_turn [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | 월드 전체 로직을 처리하기 위해 CardPairGameLogic에 스크립트를 붙였는데, 왜 유저 입장 시 CardPairGameUI가 자동으로 켜지지 않는지 궁금합니다. [answer] | `CardPairGameUI`가 자동으로 켜지지 않는 이유는, UI 엔티티의 `Enable` 프로퍼티가 기본적으로 `false` 상태이기 때문입니다. UI를 화면에 나타내려면 해당 프로퍼티를 명시적으로 `true`로 변경하는 코드를 실행해야 합니다. 월드 전체 로직을 처리하는 `CardPairGameLogic` 스크립트에서 유저 입장 시 UI를 활성화하려면, `OnBeginPlay()` 생명주기 메서드를 이용하여 `CardPairGameUI`의 `Enable`을 `true`로 설정하는 로직을 추가해야 합니다. 아래와 같이 스크립 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 리메이크한 월드에는 제작에 필요한 UI, 리소스, 그리고 비어 있는 컴포넌트 등이 있습니다. 단계 별로 하나씩 채워나가며 함께 게임을 완성해봅시다. # CardPairGameUI 활성화 월드에 유저가 입장하면 **CardPairGameUI**가 **Enable**로 변경되도록 만들어 봅시다. 월드 전체에 적용되는 규칙이나 로직을 만들 때는 Logic을 사용합니다. **CardPairGameLogic** 로직에는 짝 맞추기에 기본적으로 필요한 UI를 켜거나 끄기, 카드 입력 등 전반적인 규칙을 작성할 것입니다. 우선 월드에 입장
[task] | code [pass] | ⏳ 미판정 [title] | Effective MSW 2 [question] | UI Entity의 컴포넌트에서 서버의 실행 제어 함수를 직접 호출하지 않고, World Entity를 중개자로 삼아 정보를 서버로 전달하는 스크립트를 작성해줘 [answer] | 참고 문서에 따르면, UI Entity는 각 클라이언트에만 존재하는 Localized Entity이므로 서버에 존재하지 않습니다. 따라서 UI Entity의 컴포넌트에서 서버의 실행 제어 함수를 직접 호출할 수 없습니다. UI Entity에서 서버로 정보를 주고받으려면 반드시 World Entity를 통해서 전송해야 합니다. 문서에는 World Entity가 UI Entity로부터 정보를 받아 서버로 전달하는 구체적인 API(예: World Entity의 특정 메서드 호출, 이벤트 발생 등)나 UI Entity에서 World En [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 함수의 실행 공간을 설정하면 별도의 과정 없이 쉽게 클라이언트와 서버가 통신할 수 있습니다. 자동으로 처리하기 때문에 편리하지만, 몇몇 경우는 제약이 있어 크리에이터가 원하는 대로 동작하지 않을 수 있습니다. 일부는 로그가 나오지만, 어떤 것은 동작하지 않는 이유를 확인할 수 없을 수도 있습니다. 이번 가이드에서는 실행 제어를 사용할 수 없는 경우를 알아봅시다. # 매개 변수가 지원하지 않는 종류 함수에는 여러 종류의 매개 변수(parameter)가 있습니다. 이 매개 변수는 다른 공간에서 실행 제어를 사용
[task] | code [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | 유저가 월드에 입장하면 CardPairGameUI의 Enable 프로퍼티를 True로 설정하여 게임 UI를 활성화하는 CardPairGameLogic 스크립트를 작성해줘. [answer] | 유저가 월드에 입장하면 게임 UI가 활성화되도록 `CardPairGameLogic` 스크립트를 작성하는 방법은 다음과 같습니다. 월드 전체에 적용되는 로직은 Logic 컴포넌트를 사용하여 구현하며, UI를 화면에 표시하려면 해당 UI 엔티티의 `Enable` 프로퍼티를 `true`로 설정해야 합니다. 아래 코드는 `OnBeginPlay()` 생명주기 메서드가 실행될 때 `StartGame()` 메서드를 호출하여 `CardPairGameUI`를 활성화합니다. ```lua Property: [None] Entity CardPair [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 리메이크한 월드에는 제작에 필요한 UI, 리소스, 그리고 비어 있는 컴포넌트 등이 있습니다. 단계 별로 하나씩 채워나가며 함께 게임을 완성해봅시다. # CardPairGameUI 활성화 월드에 유저가 입장하면 **CardPairGameUI**가 **Enable**로 변경되도록 만들어 봅시다. 월드 전체에 적용되는 규칙이나 로직을 만들 때는 Logic을 사용합니다. **CardPairGameLogic** 로직에는 짝 맞추기에 기본적으로 필요한 UI를 켜거나 끄기, 카드 입력 등 전반적인 규칙을 작성할 것입니다. 우선 월드에 입장
[task] | code [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | Model_Card 모델의 SpriteGUIRendererComponent에 CardSet에서 무작위로 선택된 SpriteRUID를 설정하여 카드를 생성하는 _SpawnService를 활용한 스크립트를 작성해줘. [answer] | 제시된 참고 문서에는 `_SpawnService`를 사용하여 모델을 생성하는 코드 예제나 `_SpawnService` API의 사용법이 포함되어 있지 않습니다. 참고 문서에 명시된 내용만으로는 `_SpawnService`를 활용한 카드 생성 스크립트를 작성할 수 없으며, 해당 API가 문서에 존재하지 않습니다. 참고 문서에서 확인 가능한 정보에 따르면, 카드 생성을 위해선 `Model_Card` 모델을 만들고, `SpriteGUIRendererComponent`의 `ImageRUID`에 이미지를 설정한 뒤, `CardSet` 데 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 리메이크한 월드에는 제작에 필요한 UI, 리소스, 그리고 비어 있는 컴포넌트 등이 있습니다. 단계 별로 하나씩 채워나가며 함께 게임을 완성해봅시다. # CardPairGameUI 활성화 월드에 유저가 입장하면 **CardPairGameUI**가 **Enable**로 변경되도록 만들어 봅시다. 월드 전체에 적용되는 규칙이나 로직을 만들 때는 Logic을 사용합니다. **CardPairGameLogic** 로직에는 짝 맞추기에 기본적으로 필요한 UI를 켜거나 끄기, 카드 입력 등 전반적인 규칙을 작성할 것입니다. 우선 월드에 입장
[task] | single_turn [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | CreateCardEntities 함수를 [client only]로 선언했는데, 서버에서 실행하려고 하면 어떤 오류가 발생하나요? [answer] | 제시된 참고 문서에는 `[client only]`로 선언된 함수가 서버에서 실행될 때 발생하는 구체적인 오류 메시지나 예외에 대한 정보가 포함되어 있지 않습니다. 따라서 문서 기반에서 정확한 오류 내용을 답변할 수 없습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | ```lua Property: [None] Entity CardSpawnRoot = /ui/CardParirGameUi/UI_Board/UI_Blocks/UI_Block_Group Method: [client only] void CreateCardEntities() { local cardModelId = "Model_Card EntiryID" local card = _SpawnService:SpawnByModelId(cardModelId, "Card", Vector3(0,0,0), self.CardSpawn
[task] | code [pass] | ⏳ 미판정 [title] | Effective MSW 1 [question] | `OnUpdate()` 루프에서 매 프레임마다 특정 대상 엔티티의 `Position`을 확인하여 10 단위 이내로 접근하면 `_TimerService:SetTimerOnce()`를 호출하여 1초 후 `log()`로 도달 알림을 출력하도록, `Entity` 컴포넌트와 `_TimerService`를 사용하여 작성해줘 [answer] | `OnUpdate()`에서 `wait()`를 직접 호출하면 프레임마다 Update 객체가 누적되어 성능 저하와 디버깅 난이도가 높아지는 문제가 발생합니다. 따라서 대기 로직이 필요한 경우 `_TimerService:SetTimerOnce()`를 사용하는 것이 권장됩니다. 요청하신 기능(매 프레임 위치 확인, 10 단위 이내 접근 시 1초 후 로그 출력)은 `OnUpdate()`에서 조건만 검사하고, 조건이 충족되면 타이머를 설정하는 방식으로 구현할 수 있습니다. ```lua Property: [None] Entity Target [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 그럼 `OnUpdate()`에서 사용할 경우를 살펴보겠습니다. `OnUpdate()` 문에서 아래 코드는 어떻게 동작할까요? ```lua log("TEST") -- No.1 wait(1) log("TEST2") -- No.2 ``` * 기대 동작: TEST - 1초 대기 - TEST2 - TEST1 - 1초 대기 - TEST2 * 실제 동작: **TEST - TEST - TEST - .... (첫 번째 TEST가 찍힌 시점부터 1초가 지났을 때 ) - TEST2** `OnUpdate()`는 논리적인 측면에서 수행이 끝날 당시
[task] | single_turn [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | _SpawnService:SpawnByModelId 메서드에서 네 번째 인자로 부모 엔티티를 지정할 때, UI 위젯을 부모로 설정할 수 있나요? [answer] | 네, 가능합니다. 제공된 예제 코드에서 `_SpawnService:SpawnByModelId`의 네 번째 인자로 UI 경로를 나타내는 `Entity` 타입의 프로퍼티(`self.CardSpawnRoot`)를 직접 전달하여 카드 엔티티가 UI 보드 아래에 생성되는 것을 확인할 수 있습니다. ```lua Property: [None] Entity CardSpawnRoot = /ui/CardParirGameUi/UI_Board/UI_Blocks/UI_Block_Group Method: [client only] void CreateCa [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | ```lua Property: [None] Entity CardSpawnRoot = /ui/CardParirGameUi/UI_Board/UI_Blocks/UI_Block_Group Method: [client only] void CreateCardEntities() { local cardModelId = "Model_Card EntiryID" local card = _SpawnService:SpawnByModelId(cardModelId, "Card", Vector3(0,0,0), self.CardSpawn
[task] | code [pass] | ⏳ 미판정 [title] | Effective MSW 2 [question] | 매개 변수 타입이 any인 함수를 다른 실행 공간으로 호출할 때 발생하는 에러를 방지하기 위해, 매개 변수를 number 또는 string 등 전송 가능한 타입으로 변환하여 전달하는 로직을 포함한 스크립트를 작성해줘 [answer] | mLua에서 `any` 타입의 매개 변수를 다른 실행 공간(예: Client에서 Server)으로 전송하는 함수의 인수로 전달하면, `any`는 전송 가능한 약속된 형태가 없어 **"Failed to convert argument"** 에러가 발생합니다. 이를 방지하려면 함수 선언 시 매개 변수 타입을 `number`, `string` 등 기본 타입으로 명시하고, 호출 시에도 해당 타입에 맞는 값만 전달해야 합니다. 아래 예제는 `any` 타입을 피하고 `number` 및 `string` 타입의 매개 변수를 사용하여 Client에 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 함수의 실행 공간을 설정하면 별도의 과정 없이 쉽게 클라이언트와 서버가 통신할 수 있습니다. 자동으로 처리하기 때문에 편리하지만, 몇몇 경우는 제약이 있어 크리에이터가 원하는 대로 동작하지 않을 수 있습니다. 일부는 로그가 나오지만, 어떤 것은 동작하지 않는 이유를 확인할 수 없을 수도 있습니다. 이번 가이드에서는 실행 제어를 사용할 수 없는 경우를 알아봅시다. # 매개 변수가 지원하지 않는 종류 함수에는 여러 종류의 매개 변수(parameter)가 있습니다. 이 매개 변수는 다른 공간에서 실행 제어를 사용
[task] | code [pass] | ⏳ 미판정 [title] | Effective MSW 2 [question] | EntityService의 GetEntity로 UIEntity를 조회하고 _UserService.LocalPlayer의 money 프로퍼티 변경 시에만 해당 UIEntity의 TextComponent.Text를 갱신하는 스크립트를 작성해줘 [answer] | 제공된 참고 문서에는 `money` 프로퍼티의 변경을 감지하는 이벤트 핸들러(예: `HandlePropertyChangeEvent`)나 `GetEntity` 메서드의 정확한 시그니처(문서 예시에서는 `GetEntityByPath` 또는 특정 ID 기반 접근이 혼용되어 있으나, 질문에서 `GetEntity`를 명시함)에 대한 구체적인 API 정의가 없습니다. 또한, 문서의 예제 코드(`SetMoney` 메서드)는 `money`가 변경될 때마다 UI를 갱신하는 로직을 보여주지만, **"LocalPlayer의 money 프로퍼티 변경 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 메이플스토리 월드에서는 기본적으로 멀티 플레이를 손쉽게 구현할 수 있습니다. 대부분의 기능을 멀티 플레이 기반으로 처리하는 것을 권장합니다. 하지만 일부 항목은 별도의 Local 개념이 필요합니다. 주요 항목은 다음과 같습니다. * Localized Entity * 입력 처리 * 내 캐릭터 처리 **UIEntity**와 **입력** 그리고 **내 캐릭터** 모두 **나의 클라이언트에만 존재하는 개념**이라 별도로 처리해야 합니다. 특히 **내 캐릭터**는 클라이언트에서 처리하기 위해 `_UserService.LocalPlay
[task] | two_turn [pass] | ⏳ 미판정 [title] | Effective MSW 2 [question] | 서버와 클라이언트 간 실행 제어 함수 사용 시 매개 변수의 전송 제약이 어떻게 작용하며, 어떤 타입의 인자가 에러를 유발하는지? [answer] | 서버와 클라이언트 간 실행 제어 함수를 사용할 때, 매개 변수는 다른 공간으로 전송되기 전에 **"전송 가능한 약속된 형태"**로 변환되어야 합니다. `number`나 `string`과 같이 미리 정의된 전송 규칙이 있는 타입은 정상적으로 변환되어 전송됩니다. 그러나 **`any`** 타입의 매개 변수는 전송할 수 없습니다. `any` 타입은 어떤 데이터 타입이든 허용하는 유연성이 있지만, 이 때문에 전송 시 적용할 수 있는 공통된 약속된 변환 형태가 없기 때문입니다. `any` 타입을 매개 변수로 가진 함수를 다른 공간(예: 서 [followup] | `any` 타입 매개 변수로 인해 발생하는 "Failed to convert argument" 오류를 해결하기 위해, 특정 데이터 구조를 `number`나 `string` 등 약속된 형태로 변환하는 구체적인 코드 예시를 작성해 주세요. [followup_answer] | 제공된 참고 문서에는 `any` 타입을 `number` 또는 `string`으로 변환하는 구체적인 코드 예시나 변환 로직에 대한 설명이 포함되어 있지 않습니다. 문서에서는 `any` 타입이 전송 가능한 약속된 형태로 변경될 수 없으므로 다른 공간의 실행 제어 함수를 사용할 때 에러가 발생한다는 사실과, "Failed to convert argument" 오류가 발생하면 매개 변수 타입을 다른 것으로 변경해야 한다는 원칙만 명시하고 있을 뿐, 실제 변환을 위한 mLua 코드 구현 방법은 제시하고 있지 않습니다. [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 함수의 실행 공간을 설정하면 별도의 과정 없이 쉽게 클라이언트와 서버가 통신할 수 있습니다. 자동으로 처리하기 때문에 편리하지만, 몇몇 경우는 제약이 있어 크리에이터가 원하는 대로 동작하지 않을 수 있습니다. 일부는 로그가 나오지만, 어떤 것은 동작하지 않는 이유를 확인할 수 없을 수도 있습니다. 이번 가이드에서는 실행 제어를 사용할 수 없는 경우를 알아봅시다. # 매개 변수가 지원하지 않는 종류 함수에는 여러 종류의 매개 변수(parameter)가 있습니다. 이 매개 변수는 다른 공간에서 실행 제어를 사용
[task] | single_turn [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | 카드 스폰 루트를 Property에 절대 경로로 지정할 때 Entity 타입으로 선언하는 것이 올바른가요? [answer] | 네, 올바른 선언 방식입니다. 제공된 참고 문서의 예제 코드를 보면, 카드가 생성될 위치를 나타내는 `CardSpawnRoot`를 `Entity` 타입으로 선언하고 있습니다. 이 프로퍼티에는 `/ui/CardParirGameUi/UI_Board/UI_Blocks/UI_Block_Group`과 같은 UI 내의 절댓 경로(Absolute Path)가 지정되어 있습니다. mLua에서 특정 엔티티(예: UI 오브젝트, 스폰 지점)를 참조할 때는 `Entity` 타입의 프로퍼티를 사용하고, 에디터에서 해당 경로를 지정하는 것이 표준적인 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | ```lua Property: [None] Entity CardSpawnRoot = /ui/CardParirGameUi/UI_Board/UI_Blocks/UI_Block_Group Method: [client only] void CreateCardEntities() { local cardModelId = "Model_Card EntiryID" local card = _SpawnService:SpawnByModelId(cardModelId, "Card", Vector3(0,0,0), self.CardSpawn
[task] | code [pass] | ⏳ 미판정 [title] | Effective MSW 2 [question] | _SpawnService로 생성된 Enemy Entity가 _UserService.LocalPlayer의 TransformComponent.Position과 가까워지면 LocalPlayer의 UIEntity에 경고 메시지를 표시하는 스크립트를 작성해줘 [answer] | 제공된 참고 문서에는 `_SpawnService`로 엔티티를 생성하는 구체적인 API(메서드명, 파라미터)나 `UIEntity`의 텍스트를 변경하는 구체적인 컴포넌트/프로퍼티 접근 방식이 명시되어 있지 않습니다. 또한, 두 엔티티 사이의 거리를 계산하는 벡터 연산 API나 주기적인 업데이트를 위한 `OnUpdate` 루프의 정확한 구현 예시가 문서에 포함되어 있지 않습니다. 따라서 요청하신 기능 중 **`_SpawnService`를 이용한 생성**, **거리 계산**, 그리고 **UIEntity의 텍스트 표시** 부분에 대해서는 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 메이플스토리 월드에서는 기본적으로 멀티 플레이를 손쉽게 구현할 수 있습니다. 대부분의 기능을 멀티 플레이 기반으로 처리하는 것을 권장합니다. 하지만 일부 항목은 별도의 Local 개념이 필요합니다. 주요 항목은 다음과 같습니다. * Localized Entity * 입력 처리 * 내 캐릭터 처리 **UIEntity**와 **입력** 그리고 **내 캐릭터** 모두 **나의 클라이언트에만 존재하는 개념**이라 별도로 처리해야 합니다. 특히 **내 캐릭터**는 클라이언트에서 처리하기 위해 `_UserService.LocalPlay
[task] | two_turn [pass] | ⏳ 미판정 [title] | Effective MSW 2 [question] | 서버의 `OnBeginPlay()`에서 클라이언트로 정보를 전송하려 했을 때 실패하는 원인과, 클라이언트 접속 시점에 데이터를 안전하게 전달하기 위한 대안 패턴은 무엇인가요? [answer] | 서버의 `OnBeginPlay()`에서 클라이언트로 정보를 전송하려 했을 때 실패하는 원인은 서버가 먼저 생성되고 `OnBeginPlay()`가 호출되는 시점에 클라이언트는 아직 서버에 접속하지 않았기 때문입니다. 클라이언트는 서버에 접속한 이후에야 서버로부터 정보를 받아 클라이언트를 구성하므로, 서버 초기화 단계에서 클라이언트로 보내는 데이터는 수신할 대상이 없어 전달되지 않습니다. 클라이언트 접속 시점에 데이터를 안전하게 전달하기 위한 대안 패턴은 클라이언트의 `OnBeginPlay()`에서 서버에 자신의 초기화 완료 시점을 [followup] | 클라이언트의 `OnBeginPlay()`에서 서버에 신호를 보내고 서버가 응답하는 방식으로, 서버에서 특정 데이터(예: 아이템 목록)를 클라이언트로 전달하는 전체적인 스크립트 코드 구조를 작성해 주세요. [followup_answer] | 클라이언트와 서버 간의 데이터 전달은 실행 제어 함수의 매개 변수가 전송 가능한 형태여야 합니다. `number`, `string`과 같은 기본 타입은 전송 가능하지만, `any` 타입은 전송 가능한 형태로 변경할 수 없어 에러가 발생합니다. 따라서 아이템 목록을 전달할 때는 `any` 타입을 사용하지 않고, 전송 가능한 타입(예: `string`, `number`)을 사용해야 합니다. 다음은 클라이언트의 `OnBeginPlay()`에서 서버에 신호를 보내고, 서버가 응답하여 특정 데이터를 클라이언트로 전달하는 전체적인 스크립트 [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 함수의 실행 공간을 설정하면 별도의 과정 없이 쉽게 클라이언트와 서버가 통신할 수 있습니다. 자동으로 처리하기 때문에 편리하지만, 몇몇 경우는 제약이 있어 크리에이터가 원하는 대로 동작하지 않을 수 있습니다. 일부는 로그가 나오지만, 어떤 것은 동작하지 않는 이유를 확인할 수 없을 수도 있습니다. 이번 가이드에서는 실행 제어를 사용할 수 없는 경우를 알아봅시다. # 매개 변수가 지원하지 않는 종류 함수에는 여러 종류의 매개 변수(parameter)가 있습니다. 이 매개 변수는 다른 공간에서 실행 제어를 사용
[task] | two_turn [pass] | ⏳ 미판정 [title] | Effective MSW 1 [question] | wait()와 OnUpdate()의 상호작용으로 인해 발생하는 디버깅 난이도와 프로퍼티 흐름 파악의 어려움에 대해 더 구체적으로 알고 싶습니다. [answer] | `wait()`와 `OnUpdate()`의 상호작용으로 인해 발생하는 디버깅 난이도와 프로퍼티 흐름 파악의 어려움은 다음과 같은 구체적인 메커니즘에서 비롯됩니다. ### 1. Update 객체의 누적과 프로퍼티 흐름의 혼선 `OnUpdate()`는 논리적으로 한 프레임의 처리가 끝나면 해당 실행 컨텍스트(Update 객체)가 종료되어야 정상적인 흐름을 유지합니다. 그러나 `OnUpdate()` 본문 내에서 `wait()`를 호출하면 해당 코드의 실행이 즉시 중단되지 않고 입력된 시간만큼 대기에 들어갑니다. 이때 중요한 점은, ` [followup] | Update 객체가 반복 생성되면서 각 객체별 프로퍼티 상태가 어떻게 달라지는지, 그리고 이를 방지하기 위해 wait() 대신 사용할 수 있는 대안적인 코드 패턴이나 설계 원칙을 알려주세요. [followup_answer] | `OnUpdate()` 내부에서 `wait()`를 사용할 때 발생하는 Update 객체 누적과 프로퍼티 상태 혼선, 그리고 이를 방지하기 위한 대안적인 코드 패턴을 참고 문서의 내용을 바탕으로 설명합니다. ### 1. Update 객체 반복 생성과 프로퍼티 상태의 문제 `OnUpdate()`는 매 프레임마다 실행되며, 논리적으로 한 프레임의 처리가 끝나면 해당 실행 컨텍스트(Update 객체)는 종료되어야 합니다. 그러나 `wait()`가 개입하면 다음과 같은 문제가 발생합니다. * **객체 누적:** `wait()`는 현 [scores] | [judge_reason] | [source_doc] | 그럼 `OnUpdate()`에서 사용할 경우를 살펴보겠습니다. `OnUpdate()` 문에서 아래 코드는 어떻게 동작할까요? ```lua log("TEST") -- No.1 wait(1) log("TEST2") -- No.2 ``` * 기대 동작: TEST - 1초 대기 - TEST2 - TEST1 - 1초 대기 - TEST2 * 실제 동작: **TEST - TEST - TEST - .... (첫 번째 TEST가 찍힌 시점부터 1초가 지났을 때 ) - TEST2** `OnUpdate()`는 논리적인 측면에서 수행이 끝날 당시
[task] | two_turn [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | 카드 짝 맞추기 게임에서 UI 보드에 카드를 생성하는 기본적인 구조와 방법을 알고 싶습니다 [answer] | 카드 짝 맞추기 게임에서 UI 보드에 카드를 생성하는 과정은 크게 **스폰 루트(Entity)를 정의**하는 단계와 **스폰 서비스를 통해 카드 엔티티를 생성**하는 단계로 나뉩니다. ### 1. 카드 생성의 기본 구조 1. **스폰 루트(Spawn Root) 설정**: * 카드를 생성할 위치를 UI 경로로 정의합니다. * 예: `/ui/CardParirGameUi/UI_Board/UI_Blocks/UI_Block_Group` * 이 경로는 `Entity` 타입의 Property로 선언됩니다. [followup] | CreateCardEntities 메서드에서 _SpawnService:SpawnByModelId 를 사용할 때 CardSpawnRoot 경로가 잘못된 경우 어떤 에러가 발생하며, 이를 해결하기 위해 Entity 타입의 Property 설정을 어떻게 수정해야 하는지 코드 예시를 보여주세요. [followup_answer] | 제시된 참고 문서에는 `_SpawnService:SpawnByModelId` 호출 시 `CardSpawnRoot` 경로가 잘못된 경우에 발생하는 구체적인 에러 메시지나 예외 처리 방식에 대한 정보가 포함되어 있지 않습니다. 또한, 잘못된 경로를 감지하거나 처리하는 코드 예제도 문서에 존재하지 않습니다. 따라서 문서에 근거하여 에러 유형이나 해결 코드를 제시할 수 없습니다. 다만, 문서에 명시된 올바른 `Entity` 타입 Property 설정 방식은 다음과 같습니다. UI 경로 문자열을 직접 Property 값으로 지정하여 사용 [scores] | [judge_reason] | [source_doc] | ```lua Property: [None] Entity CardSpawnRoot = /ui/CardParirGameUi/UI_Board/UI_Blocks/UI_Block_Group Method: [client only] void CreateCardEntities() { local cardModelId = "Model_Card EntiryID" local card = _SpawnService:SpawnByModelId(cardModelId, "Card", Vector3(0,0,0), self.CardSpawn
[task] | single_turn [pass] | ⏳ 미판정 [title] | Effective MSW 2 [question] | `_UserService.LocalPlayer`는 어떤 상황에서 사용하며, 단순히 Entity를 비교하는 것과의 차이점은 무엇인가요? [answer] | `_UserService.LocalPlayer`는 현재 스크립트가 실행되고 있는 **클라이언트(내 PC)의 플레이어 캐릭터**를 직접 참조하기 위해 사용됩니다. 메이플스토리 월드에서 Entity(예: Player)는 멀티 플레이 환경에서 모든 클라이언트에 존재하므로, "나"의 캐릭터인지 "다른 사람"의 캐릭터인지를 구별하는 것이 중요합니다. ### `_UserService.LocalPlayer` 사용 상황 1. **입력 처리(Input Handling) 시:** * 키보드, 마우스 등의 입력 이벤트는 해당 클라이언트에 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 메이플스토리 월드에서는 기본적으로 멀티 플레이를 손쉽게 구현할 수 있습니다. 대부분의 기능을 멀티 플레이 기반으로 처리하는 것을 권장합니다. 하지만 일부 항목은 별도의 Local 개념이 필요합니다. 주요 항목은 다음과 같습니다. * Localized Entity * 입력 처리 * 내 캐릭터 처리 **UIEntity**와 **입력** 그리고 **내 캐릭터** 모두 **나의 클라이언트에만 존재하는 개념**이라 별도로 처리해야 합니다. 특히 **내 캐릭터**는 클라이언트에서 처리하기 위해 `_UserService.LocalPlay
[task] | code [pass] | ⏳ 미판정 [title] | Effective MSW 1 [question] | `OnUpdate()`에서 매 프레임마다 `self.Entity.TransformComponent.Position`의 Y 좌표가 100을 초과하면 `_EntityService:GetEntityByPath("/maps/map01/obj")`로 가져온 객체의 이름을 `log()`로 출력하되, 중복 출력을 방지하기 위해 전역 변수를 활용하도록 작성해줘 [answer] | `OnUpdate()`에서 매 프레임마다 위치를 확인하고 조건이 만족되면 로깅을 수행하되, 중복 출력을 방지하기 위해 프로퍼티를 활용하는 스크립트는 다음과 같습니다. 참고 문서에 명시된 바와 같이, `OnUpdate()` 내부에서 `wait()`를 사용해서는 안 되므로, 조건 검사만 수행하고 상태 변수(여기서는 `IsLogged` 또는 유사한 용도의 플래그)를 통해 중복을 제어하는 방식을 취합니다. ```lua Property: [None] boolean HasLoggedPosition = false Method: [serve [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 그럼 `OnUpdate()`에서 사용할 경우를 살펴보겠습니다. `OnUpdate()` 문에서 아래 코드는 어떻게 동작할까요? ```lua log("TEST") -- No.1 wait(1) log("TEST2") -- No.2 ``` * 기대 동작: TEST - 1초 대기 - TEST2 - TEST1 - 1초 대기 - TEST2 * 실제 동작: **TEST - TEST - TEST - .... (첫 번째 TEST가 찍힌 시점부터 1초가 지났을 때 ) - TEST2** `OnUpdate()`는 논리적인 측면에서 수행이 끝날 당시
[task] | single_turn [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | UI_Block_Group에 자식 UI Entity들을 배치할 때 Spacing 값이 95, 50으로 설정되어 있는데, 이 두 값이 각각 가로 간격과 세로 간격에 어떻게 대응하나요? [answer] | 참고 문서의 정보만으로는 Spacing 값 `(95, 50)` 중 어느 값이 가로 간격이고 어느 값이 세로 간격인지에 대한 명시적인 설명이 없습니다. 문서에는 Spacing 프로퍼티에 대해 "카드 사이의 간격을 설정합니다"라고만 기술되어 있을 뿐, 벡터 값의 X(첫 번째 값)와 Y(두 번째 값)가 각각 가로/세로에 어떻게 매핑되는지에 대한 구체적인 API 정의나 설명이 제공되지 않았습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이제 카드를 화면에 불러낼 차례입니다. 카드를 불러내기 위해선 **/ui/CardPairGameUI/UI_Board/UI_Blocks/UI_Block_Group**를 활용합니다. **UI_Block_Group**은 [ScrollLayoutGroupComponent](/apiReference?postId=382%7B%22target%22:%22_self%22%7D)를 활용했습니다. **ScollLayoutGroupComponent**는 여러 개의 엔티티를 펼쳐야할 때 사용합니다. 주로 상점이나, 인벤토리처럼 한 눈에 봐야하는 이미지
[task] | single_turn [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | ScrollLayoutGroupComponent의 Constraint를 FixedColumnCount로 설정했을 때, ConstraintCount 값이 실제로 적용되는 방향(가로/세로)은 어떻게 되나요? [answer] | `ScrollLayoutGroupComponent`의 `Constraint`가 `FixedColumnCount`로 설정되어 있을 때, `ConstraintCount` 값은 **가로 방향**에 적용됩니다. 구체적으로, `ConstraintCount`에 입력한 숫자만큼의 자식 UI 엔티티가 한 행(가로)에 배치되며, 그 이후에 추가되는 자식들은 자동으로 다음 행(세로 방향)으로 넘어가며 배치됩니다. 예를 들어 `ConstraintCount`가 6으로 설정되어 있다면, 가로로 6개의 카드가 꽉 차면 나머지 카드는 아래 줄로 이동하여 정 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이제 카드를 화면에 불러낼 차례입니다. 카드를 불러내기 위해선 **/ui/CardPairGameUI/UI_Board/UI_Blocks/UI_Block_Group**를 활용합니다. **UI_Block_Group**은 [ScrollLayoutGroupComponent](/apiReference?postId=382%7B%22target%22:%22_self%22%7D)를 활용했습니다. **ScollLayoutGroupComponent**는 여러 개의 엔티티를 펼쳐야할 때 사용합니다. 주로 상점이나, 인벤토리처럼 한 눈에 봐야하는 이미지
[task] | two_turn [pass] | ⏳ 미판정 [title] | Effective MSW 1 [question] | `OnUpdate`에서 동기화 프로퍼티를 매 프레임 업데이트하면 N*N의 네트워크 비용이 발생한다는 설명을 이해했는데, 서버에서 이벤트를 시작할 때의 시점만 기록하고 클라이언트에서 경과 시간을 계산하는 방식을 적용하려면 어떤 코드가 필요한가? [answer] | 서버에서 이벤트가 시작되는 시점의 서버 시간(`_UtilLogic.ServerElapsedSeconds`)을 동기화 프로퍼티에 **한 번만** 저장하고, 클라이언트에서는 현재 서버 시간에서 그 저장된 시점을 빼서 경과 시간을 계산하는 방식으로 구현합니다. 이렇게 하면 매 프레임마다 프로퍼티 값을 변경하고 동기화할 필요가 없어 네트워크 비용이 크게 줄어듭니다. 아래는 이 방식을 적용한 mLua 스크립트 예시입니다. ```lua Property: [Sync] number eventActiveTime = 0 Method: [serv [followup] | `_UtilLogic.ServerElapsedSeconds`를 사용하여 서버에서 `eventActiveTime`을 설정하고, 클라이언트에서 현재 시각을 빼서 경과 시간을 구하는 `OnUpdate` 또는 이벤트 핸들러 코드 예시를 작성해 줘. [followup_answer] | 참고 문서에 제시된 최적화 방식을 적용하여, 서버에서 이벤트 시작 시점만 한 번 동기화하고 클라이언트에서 `OnUpdate`를 통해 경과 시간을 계산하는 코드 예시입니다. ```lua Property: [Sync] number eventActiveTime = 0 Method: [server only] void StartEvent() { -- 이벤트가 시작될 때 서버의 현재 시간을 기록합니다. -- 이 값은 [Sync] 프로퍼티이므로 클라이언트로 동기화됩니다. self.eventActiveTime = _Uti [scores] | [judge_reason] | [source_doc] | `wait`는 대기한 뒤에 직접 어떤 행동을 수행하는 것이고, `TimerService`는 해당 행동을 수행하는 별도의 일을 만드는 것입니다. `wait`는 직렬, `TimerService`는 병렬 형태로 동작합니다. 따라서 `wait`의 사용 코드는 다음과 같이 표현할 수 있습니다 ```lua local targetEntity = _EntityService:GetEntity("a22396e1-6365-42d4-9cef-5924c223f7fa") targetEntity.TestComponent:ShowMessage() func
[task] | single_turn [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | ScrollLayoutGroupComponent를 사용할 때 Padding의 top 값을 15로만 설정하고 나머지는 0으로 두면, 카드는 화면의 어느 쪽에 정렬되어 배치되나요? [answer] | Padding의 top 값이 15로 설정되고 나머지 값이 0으로 설정되면, 카드는 상단에서 15만큼의 여유 공간을 확보한 채로 화면의 **상단**에 정렬되어 배치됩니다. 이는 ScrollLayoutGroupComponent의 Padding 속성이 레이아웃 그룹의 내부 여백을 제어하기 때문에, top 값만 양수이면 콘텐츠(카드)가 해당 여백 아래에서 시작하게 되기 때문입니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이제 카드를 화면에 불러낼 차례입니다. 카드를 불러내기 위해선 **/ui/CardPairGameUI/UI_Board/UI_Blocks/UI_Block_Group**를 활용합니다. **UI_Block_Group**은 [ScrollLayoutGroupComponent](/apiReference?postId=382%7B%22target%22:%22_self%22%7D)를 활용했습니다. **ScollLayoutGroupComponent**는 여러 개의 엔티티를 펼쳐야할 때 사용합니다. 주로 상점이나, 인벤토리처럼 한 눈에 봐야하는 이미지
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 행동 트리를 활용한 AI 만들기 [question] | 행동 트리의 실행 순서와 자식 노드 반환값에 따른 부모 노드 동작 방식을 3문장 이내로 설명하세요. [answer] | 행동 트리는 매 프레임마다 Root 노드에서 시작하여 위에서 아래, 왼쪽에서 오른쪽 순서로 부모 노드가 자식 노드를 순차적으로 실행합니다. 각 노드는 실행 시 Running, Success, Failure 중 하나의 상태 값을 반환하며, 부모 노드는 자식 노드가 반환한 값에 따라 다음 자식 노드의 실행 여부를 결정합니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 행동 트리는 프레임마다 Root 노드에서 시작합니다. 그 후 순차적으로 실행됩니다. 실행 순서는 위에서 아래, 왼쪽에서 오른쪽입니다. 부모 노드가 자식 노드를 실행하며 실행 순서는 각 부모에 등록된 순서대로 실행됩니다. 부모 노드는 종류에 따라 자식 노드 실행 조건을 달리하며, 조건에 부합할 때 부모가 가진 자식 노드를 모두 순차적으로 실행합니다. 예를 들어 부모 노드에 자식 노드 A, B, C가 순차적으로 등록된 경우 A가 가장 좌측에, 노드 C가 가장 우측에 배치됩니다. 부모 노드 실행 시 자식 노드는 A, B, C 순으로 실행
[task] | single_turn [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | SetCards 메서드에서 self:CreateCardEntities()를 호출할 때, 콜론(:)을 사용하는 것이 정확한 문법인가요? [answer] | 네, 콜론(:)을 사용하는 것이 정확한 문법입니다. mLua에서는 다른 메서드를 호출할 때 `self:Method()` 형식을 사용합니다. 이는 Lua에서 객체 메서드를 호출하는 표준 방식이며, `self`를 첫 번째 인자로 전달하는 것을 의미합니다. 제공된 참고 문서의 예제에서도 `SetCards` 메서드 안에서 `CreateCardEntities`를 호출할 때 `self:CreateCardEntities()`처럼 콜론을 사용하고 있습니다. 따라서 다음과 같은 코드가 올바른 문법입니다: ```lua Property: [Non [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | ```lua Property: [None] Entity CardSpawnRoot = /ui/CardParirGameUi/UI_Board/UI_Blocks/UI_Block_Group Method: [client only] void CreateCardEntities() { local cardModelId = "Model_Card EntiryID" local card = _SpawnService:SpawnByModelId(cardModelId, "Card", Vector3(0,0,0), self.CardSpawn
[task] | single_turn [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | CellSize를 90, 90으로 고정했을 때, 실제 로드되는 Model_Card의 크기가 이 값보다 크거나 작으면 어떤 현상이 발생하나요? [answer] | 제공된 문서에는 `CellSize` 값(90, 90)이 실제 로드되는 `Model_Card`의 크기보다 크거나 작을 때 발생하는 구체적인 현상(예: 잘림, 겹침, 스크롤 범위 변화 등)에 대한 설명이 포함되어 있지 않습니다. 문서에서는 `CellSize`가 "펼쳐질 카드의 크기를 90, 90 크기로 설정합니다"라고 정의할 뿐, 모델 자체의 크기와 `CellSize` 간의 불일치 시 행동에 대해 언급하고 있지 않습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이제 카드를 화면에 불러낼 차례입니다. 카드를 불러내기 위해선 **/ui/CardPairGameUI/UI_Board/UI_Blocks/UI_Block_Group**를 활용합니다. **UI_Block_Group**은 [ScrollLayoutGroupComponent](/apiReference?postId=382%7B%22target%22:%22_self%22%7D)를 활용했습니다. **ScollLayoutGroupComponent**는 여러 개의 엔티티를 펼쳐야할 때 사용합니다. 주로 상점이나, 인벤토리처럼 한 눈에 봐야하는 이미지
[task] | single_turn [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | UI_Board 하위에 있는 UI_Block_Group을 CardSpawnRoot로 지정했을 때, 카드가 화면의 특정 위치에 정확히 표시되나요? [answer] | 제공된 문서의 정보만으로는 카드가 화면의 **특정 위치에 정확히** 표시되는지 여부를 단정할 수 없습니다. 문서에서 확인할 수 있는 사실은 다음과 같습니다. 1. `CardSpawnRoot` 프로퍼티에 `/ui/CardParirGameUi/UI_Board/UI_Blocks/UI_Block_Group` 경로가 지정되어 있습니다. 2. `CreateCardEntities()` 메서드에서 `_SpawnService:SpawnByModelId(cardModelId, "Card", Vector3(0,0,0), self.CardSpaw [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | ```lua Property: [None] Entity CardSpawnRoot = /ui/CardParirGameUi/UI_Board/UI_Blocks/UI_Block_Group Method: [client only] void CreateCardEntities() { local cardModelId = "Model_Card EntiryID" local card = _SpawnService:SpawnByModelId(cardModelId, "Card", Vector3(0,0,0), self.CardSpawn
[task] | single_turn [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | 상점이나 인벤토리처럼 이미지가 많은 UI를 만들 때 ScrollLayoutGroupComponent를 쓰는 것이 일반적이라고 하는데, 단순 리스트보다 이 컴포넌트를 선택해야 하는 구체적인 장점은 무엇인가요? [answer] | ScrollLayoutGroupComponent는 상점이나 인벤토리처럼 한눈에 봐야 하는 이미지가 많은 UI를 제작할 때 유용하게 사용됩니다. 이 컴포넌트를 선택해야 하는 구체적인 장점은 자식 UI Entity들의 크기와 배치 간격 등을 일괄적으로 적용할 수 있다는 것입니다. 이를 통해 여러 개의 엔티티를 펼쳐야 할 때 수동으로 각각의 위치와 크기를 조정하는 대신, 컴포넌트 설정 값(예: CellSize, Spacing, Constraint, ConstraintCount, Padding)을 한 번만 설정하면 자식 요소들이 일정한 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 이제 카드를 화면에 불러낼 차례입니다. 카드를 불러내기 위해선 **/ui/CardPairGameUI/UI_Board/UI_Blocks/UI_Block_Group**를 활용합니다. **UI_Block_Group**은 [ScrollLayoutGroupComponent](/apiReference?postId=382%7B%22target%22:%22_self%22%7D)를 활용했습니다. **ScollLayoutGroupComponent**는 여러 개의 엔티티를 펼쳐야할 때 사용합니다. 주로 상점이나, 인벤토리처럼 한 눈에 봐야하는 이미지
[task] | code [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | client only 실행 공간에서 SetCards 메서드를 호출하여 카드 생성 로직을 트리거하는 스크립트를 작성해줘 [answer] | client only 실행 공간에서 `SetCards` 메서드를 호출하여 카드 생성을 트리거하는 스크립트는 다음과 같습니다. ```lua Property: [None] Entity CardPairGameUI = /ui/CardPairGameUI Method: [client only] void OnBeginPlay() { self:StartGame() } [client only] void StartGame() { self.CardPairGameUI.Enable = true local cardboard = [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | ```lua Property: [None] Entity CardSpawnRoot = /ui/CardParirGameUi/UI_Board/UI_Blocks/UI_Block_Group Method: [client only] void CreateCardEntities() { local cardModelId = "Model_Card EntiryID" local card = _SpawnService:SpawnByModelId(cardModelId, "Card", Vector3(0,0,0), self.CardSpawn
[task] | code [pass] | ⏳ 미판정 [title] | 카드와 UI 만들기 [question] | CardSet 데이터셋의 SpriteRUID 리스트에서 인덱스가 0부터 29까지인 모든 값을 가져와서 CardPairGameUI에 배치할 카드 엔티티를 생성하는 로직을 작성해줘. [answer] | 참고 문서에는 `CardSet` 데이터셋에서 값을 읽어와 카드 엔티티를 생성하는 구체적인 코드나 API(데이터셋 접근 메서드, 카드 생성 메서드 등)가 제공되지 않습니다. 문서에서 확인할 수 있는 정보는 다음과 같습니다: 1. `CardSet` 데이터셋에는 30개의 `SpriteRUID`가 저장되어 있습니다. 2. 카드 생성을 위해 `Model_Card` 모델을 사용하라고 안내하지만, 모델에서 엔티티를 생성하는 구체적인 스크립트 예시(`_SpawnService:SpawnByModelId` 등)는 문서에 명시되어 있지 않습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 리메이크한 월드에는 제작에 필요한 UI, 리소스, 그리고 비어 있는 컴포넌트 등이 있습니다. 단계 별로 하나씩 채워나가며 함께 게임을 완성해봅시다. # CardPairGameUI 활성화 월드에 유저가 입장하면 **CardPairGameUI**가 **Enable**로 변경되도록 만들어 봅시다. 월드 전체에 적용되는 규칙이나 로직을 만들 때는 Logic을 사용합니다. **CardPairGameLogic** 로직에는 짝 맞추기에 기본적으로 필요한 UI를 켜거나 끄기, 카드 입력 등 전반적인 규칙을 작성할 것입니다. 우선 월드에 입장