[task] | code [pass] | ⏳ 미판정 [title] | 타이머 만들기 [question] | CardPairGameLogic과 CardBoard 스크립트를 연동하여 게임 시작 시 60초에서 시작해 1초마다 1씩 감소하는 타이머가 UI에 정수로 표시되고, 0이 되면 게임이 종료될 수 있는 기본 구조를 작성해줘. [answer] | CardPairGameLogic과 CardBoard 컴포넌트를 연동하여 60초 타이머를 구현하고, 시간이 0이 되면 게임을 종료하는 기본 구조는 다음과 같습니다. ### 1. CardPairGameLogic 스크립트 게임 제한 시간(`PlayTime`)과 남은 시간(`RemainingTime`)을 관리하며, 매 프레임(`OnUpdate`)마다 시간을 감소시키고 0이 되는 시점을 감지하여 게임 종료 이벤트를 발생시킵니다. ```lua Property: [None] number PlayTime = 60 [None] number R [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 타이머 만들기 게임을 시작하면 1초씩 감소하는 타이머를 만들어봅시다. 1. **CardPairGameLogic** 로직에 게임 제한 시간으로 사용할 **PlayTime** 프로퍼티와 시간을 줄이기 위해 사용할 **RemainingTime** 프로퍼티를 추가합니다. PlayTime 초깃값은 **60**으로 설정합니다. ```lua Property: [None] number PlayTime = 60 [None] number RemainingTime = 0 ``` > **
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | 카드 엔티티를 모두 삭제할 때 Children 리스트에서 Destroy()를 호출하는 로직이 클라이언트에서 실행되는 이유는 무엇인가요? [answer] | 카드 엔티티 삭제 로직이 클라이언트에서 실행되는 이유는 해당 작업이 시각적 렌더링 및 사용자 인터페이스(UI) 상태 관리와 직접적으로 연관되어 있기 때문입니다. 제시된 코드에서 `ClearCardEntities` 함수는 `[client Only]` 태그가 붙어 있으며, 이는 해당 로직이 서버가 아닌 클라이언트에서 실행되어야 함을 의미합니다. 카드 게임에서 카드의 배치, 선택 상태, 삭제(소멸) 등은 플레이어가 화면에서 실제로 보는 시각적 요소입니다. `CardSpawnRoot.Children` 리스트에서 각 엔티티에 대해 `Des [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | [client Only] void ClearCardEntities () { local cardEntities = self.CardSpawnRoot.Children for i = 1, #cardEntities do cardEntities[i]:Destroy() end } [client only] void SelectCardCard (Card card) { self.SelectedCard = card card:CardOn() } [client only] void
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | PlayerStats 컴포넌트의 Score 프로퍼티를 [Sync]로 설정해야 다른 플레이어의 점수도 실시간으로 동기화되는지, 아니면 [None]으로 유지해도 되는지 궁금합니다. [answer] | 제시된 문서에는 `PlayerStats` 컴포넌트의 `Score` 프로퍼티가 `[None]`으로 선언되어 있습니다. ```lua Property: [None] number Score = 0 ``` 문서에는 다른 플레이어의 점수를 실시간으로 동기화하기 위해 `[Sync]`로 설정해야 하는지 여부에 대한 언급이나 설명이 없습니다. 따라서 제공된 자료만으로는 `[Sync]` 설정의 필요성이나 효과를 판단할 수 없으며, 문서에 명시되지 않은 사항입니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 점수 만들기 카드 짝 맞출 때마다 일정한 점수가 증가하게 만들어봅시다. 1. **PlayerStats** 컴포넌트를 **DefalutPlayer**에 추가합니다. **PlayerStats** 컴포넌트는 점수 증가를 담당합니다. 2. **PlayerStats** 컴포넌트에 number 타입 프로퍼티를 아래와 같이 추가합니다. ```lua Property: [None] number Score = 0 ``` 3. 초깃값이 0인 **Score** 프로퍼티에 점수가 더해질 수 있도록 `A
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | CardBoard 컴포넌트의 UpdateText 함수에서 self.ScoreText.TextComponent.Text 를 업데이트할 때, self.ScoreText 가 null 인 경우 발생하는 오류를 방지하기 위한 if 문 처리 방법은 무엇인가요? [answer] | 제공된 참고 문서에는 `UpdateText` 함수 내에서 `self.ScoreText`가 null인 경우를 검사하기 위한 `if` 문이나 `isvalid` 함수 사용 예시가 포함되어 있지 않습니다. 문서에는 단순히 `self.TimeText.TextComponent.Text = ...` 문장 아래에 다음 코드를 작성하라고만 안내하고 있습니다: ```lua local me = _UserService.LocalPlayer self.ScoreText.TextComponent.Text = tostring(math.floor(me.Play [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 점수 만들기 카드 짝 맞출 때마다 일정한 점수가 증가하게 만들어봅시다. 1. **PlayerStats** 컴포넌트를 **DefalutPlayer**에 추가합니다. **PlayerStats** 컴포넌트는 점수 증가를 담당합니다. 2. **PlayerStats** 컴포넌트에 number 타입 프로퍼티를 아래와 같이 추가합니다. ```lua Property: [None] number Score = 0 ``` 3. 초깃값이 0인 **Score** 프로퍼티에 점수가 더해질 수 있도록 `A
[task] | two_turn [pass] | ⏳ 미판정 [title] | 어노테이션 활용하기 [question] | Param Annotation과 Return Annotation의 문법 및 역할이 궁금합니다. [answer] | 메이플스토리 월드의 mLua 스크립트에서 **Param Annotation**과 **Return Annotation**은 함수의 매개 변수와 반환값의 타입을 명시적으로 지정하여, 스크립트 작성 시 IDE의 자동 완성 및 타입 체크(스크립트 어시스트) 기능을 활용할 수 있게 해주는 주석입니다. ### 1. Param Annotation 함수가 받는 매개 변수의 타입을 지정합니다. 루아는 동적 타이핑 언어이므로 기본적으로 함수가 어떤 타입의 값을 받는지 알 수 없습니다. `Param Annotation`을 사용함으로써 스크립트 어시스 [followup] | 매개 변수 2개 이상과 반환 값 2개 이상을 동시에 지정하는 복합적인 함수 정의 코드 예시를 요청합니다. [followup_answer] | Param Annotation과 Return Annotation을 동시에 사용하여 매개 변수 2개 이상과 반환 값 2개 이상의 타입을 지정하는 복합적인 함수 정의 예시는 다음과 같습니다. ```lua ---@param testParamA Entity ---@param testParamB integer ---@return Entity, string local function TestFunction(testParamA, testParamB) return self.Entity, "strValue" end ``` 위 코드에서 ` [scores] | [judge_reason] | [source_doc] | **Param Annotation**을 사용해 대상이 되는 함수의 매개 변수 타입을 지정하여 스크립트 어시스트의 도움을 받을 수 있습니다. **Param Annotation**은 함수 정의문에 사용합니다. 아래와 같은 문법으로 **Param Annotation**을 사용합니다. ```lua ---@param param_name PARAM_TYPE ``` ##### 사용 예시 ```lua ---@param testParamA Entity local function TestFunction(testParamA) end ``` ```
[task] | two_turn [pass] | ⏳ 미판정 [title] | 어노테이션 활용하기 [question] | mLua에서 Function의 Type Annotation 문법은 어떻게 작성하나요? [answer] | mLua에서 Function의 Type Annotation은 `---@type function(...)` 문법을 사용합니다. 이 주석은 함수의 매개변수 유형과 반환 값 유형을 명시하여 시그니처 헬퍼와 퀵 인포 기능을 활성화합니다. ### 기본 문법 ```lua ---@type function(param_name: PARAM_TYPE):RETURN_TYPE ``` ### 작성 예시 1. **매개변수 및 반환값이 없는 함수** ```lua ---@type function() local testFunction = f [followup] | AttackComponent와 string을 반환하는 함수의 Type Annotation 예시를 보여주세요 [followup_answer] | `AttackComponent`와 `string`을 반환하는 함수의 Type Annotation 예시는 다음과 같습니다. 반환 타입이 두 개이므로 쉼표(,)로 구분하여 나열합니다. ```lua ---@type function(testParamA:string, testParamB:Entity):AttackComponent, string local testFunction = function(testParamA, testParamB) return atkComponent, "strValue" end ``` 이 주석을 지정하면 I [scores] | [judge_reason] | [source_doc] | Function은 아래와 같은 문법으로 타입을 지정합니다. ```lua ---@type function(param_name: PARAM_TYPE):RETURN_TYPE ``` ##### 사용 예시 ```lua ---@type function() local testFunction = function() end ``` ```lua ---@type function(testParamA:string, testParamB:Entity) local testFunction = function(testParamA, testParamB) end
[task] | code [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | CardBoard 컴포넌트에 Entity 타입의 ScoreText 프로퍼티를 선언하고, UpdateText 함수에서 _UserService.LocalPlayer의 PlayerStats.Score 값을 읽어와 self.ScoreText.TextComponent.Text에 문자열로 표시하는 UI 연동 스크립트를 작성해줘 [answer] | CardBoard 컴포넌트에 `ScoreText` 프로퍼티를 추가하고, `UpdateText` 함수 내에서 로컬 플레이어의 점수를 읽어와 UI 텍스트에 반영하는 코드는 다음과 같습니다. ```lua Property: [None] Entity ScoreText = /ui/CardPairGameUI/UI_Board/Background/Title/Score_Backgrond/UI_Score/UI_Score_Text Method: void UpdateText() { -- 기존 시간 표시 로직 (참고 문서에 언급된 기존 코드 라인 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 점수 만들기 카드 짝 맞출 때마다 일정한 점수가 증가하게 만들어봅시다. 1. **PlayerStats** 컴포넌트를 **DefalutPlayer**에 추가합니다. **PlayerStats** 컴포넌트는 점수 증가를 담당합니다. 2. **PlayerStats** 컴포넌트에 number 타입 프로퍼티를 아래와 같이 추가합니다. ```lua Property: [None] number Score = 0 ``` 3. 초깃값이 0인 **Score** 프로퍼티에 점수가 더해질 수 있도록 `A
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | me.PlayerStats:AddScore(10)은 클라이언트 로직에서 실행되는데, 이 점수가 서버에 동기화되는지 아니면 클라이언트에서만 보이는 점수인지 어떻게 구별하나요? [answer] | 제공된 참고 문서에는 `PlayerStats` 컴포넌트의 동기화 방식(서버 동기화 여부, 클라이언트 전용 여부)에 대한 설명이나 API 문서가 포함되어 있지 않습니다. 따라서 주어진 문서만으로는 `me.PlayerStats:AddScore(10)`이 서버에 동기화되는지, 클라이언트에서만 보이는 점수인지를 구별하는 방법을 설명할 수 없습니다. [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | #### CardPairGameLogic 로직 ```lua Property: [None] Entity CardPairGameUI = /ui/CardPairGameUI [None] number PlayTime = 60 [None] number RemainingTime = 0 Method: [client only] void OnBeginPlay() { self:StartGame() } [client only] void StartGame() { self.CardPairGameUI.Enable = true
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | AddScore 함수의 매개변수 add 에 음수나 소수점이 포함된 값을 전달할 경우, UI 에 표시되는 점수(math.floor 적용)와 실제 Score 값의 차이가 어떻게 발생하며 이를 방지하려면 어떻게 해야 하나요? [answer] | 제공된 참고 문서에는 `AddScore` 함수의 매개변수 `add`에 음수나 소수점이 포함된 값을 전달했을 때 발생하는 구체적인 동작이나, 이를 방지하기 위한 검증 로직(예: `if add > 0 then` 같은 조건문)이 설명되어 있지 않습니다. 문서에는 `AddScore` 함수가 단순히 전달된 `number` 타입의 값을 `self.Score`에 더하는(`self.Score = self.Score + add`) 구조만 제시되어 있으며, UI 표시 시 `math.floor`를 적용하여 소수점 이하를 버림 처리하는 방식만 언급되어 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 점수 만들기 카드 짝 맞출 때마다 일정한 점수가 증가하게 만들어봅시다. 1. **PlayerStats** 컴포넌트를 **DefalutPlayer**에 추가합니다. **PlayerStats** 컴포넌트는 점수 증가를 담당합니다. 2. **PlayerStats** 컴포넌트에 number 타입 프로퍼티를 아래와 같이 추가합니다. ```lua Property: [None] number Score = 0 ``` 3. 초깃값이 0인 **Score** 프로퍼티에 점수가 더해질 수 있도록 `A
[task] | code [pass] | ⏳ 미판정 [title] | 메이플스토리 월드 루아 기초 [question] | 지수 연산자(^)와 나머지 연산자(%)를 조합해 2의 지수 값이 5로 나누어 떨어질 때 true, 그렇지 않을 때 false를 반환하는 함수를 정의하고 해당 함수의 결과를 log로 출력하는 스크립트를 작성해줘 [answer] | 2의 지수 값이 5로 나누어 떨어질 때 `true`, 그렇지 않을 때 `false`를 반환하는 함수를 정의하고 결과를 출력하는 스크립트입니다. ```lua Method: [client only] void OnBeginPlay() { -- 2의 지수 값이 5로 나누어 떨어지는지 검사하는 함수 정의 function IsPowerOfTwoDivisibleByFive(exponent) -- 2의 지수 값 계산 local powerValue = 2 ^ exponent [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 산술 연산을 할 때 사용하는 연산자입니다. | 연산자 | 설명 | | --- | --- | | `+` | 더하기 | | `-` | 빼기 | | `*` | 곱하기 | | `/` | 나누기 | | `//` | 나눈 후 몫만 취함 | | `%` | 나눈 후 나머지만 취함 | | `^` | 지수 | 예를 들어 아래와 같이 입력하고 **log**를 출력하면 주석의 값이 출력됩니다. ```lua log(1 + 1) -- 2 log(1 - 1) -- 0 log(5 * 5) -- 25 log(13 / 5) -- 2.6 log(13 // 5)
[task] | code [pass] | ⏳ 미판정 [title] | 메이플스토리 월드 루아 기초 [question] | 논리 연산자(and, or, not)를 사용해 두 boolean 변수의 상태를 종합적으로 판단하고 결과 문자열을 log로 출력하는 스크립트를 작성해줘 [answer] | 참고 문서에 명시된 논리 연산자(`and`, `or`, `not`)의 정의와 동작 방식을 기반으로 두 boolean 변수를 종합적으로 판단하는 스크립트를 작성합니다. 문서에 따르면 `and`는 두 인수가 모두 `true`일 때만 `true`를 반환하고, `or`는 두 인수 중 하나라도 `true`이면 `true`를 반환하며, `not`은 `true`를 `false`로, `false`를 `true`로 반전시킵니다. 또한 문자열 합치기는 `..` 연산자를 사용하며, 출력은 `log()` 함수를 사용합니다. ```lua Method: [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 산술 연산을 할 때 사용하는 연산자입니다. | 연산자 | 설명 | | --- | --- | | `+` | 더하기 | | `-` | 빼기 | | `*` | 곱하기 | | `/` | 나누기 | | `//` | 나눈 후 몫만 취함 | | `%` | 나눈 후 나머지만 취함 | | `^` | 지수 | 예를 들어 아래와 같이 입력하고 **log**를 출력하면 주석의 값이 출력됩니다. ```lua log(1 + 1) -- 2 log(1 - 1) -- 0 log(5 * 5) -- 25 log(13 / 5) -- 2.6 log(13 // 5)
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | SelectCardCard와 DeselectCard 메서드에서 SelectedCard 프로퍼티의 상태 변경과 함께 호출되는 CardOn 및 CardOff의 역할은 무엇인가요? [answer] | `SelectCardCard`와 `DeselectCard` 메서드에서 `CardOn` 및 `CardOff`는 선택된 카드의 **시각적 상태(색상)를 변경**하여 사용자가 어떤 카드가 선택되었는지 직관적으로 알 수 있도록 하는 역할을 합니다. 구체적인 동작은 다음과 같습니다: 1. **`SelectCardCard`와 `CardOn`** * `SelectCardCard` 메서드는 매개변수로 받은 `card`를 `self.SelectedCard` 프로퍼티에 저장합니다. * 동시에 해당 카드에 `card:Card [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | [client Only] void ClearCardEntities () { local cardEntities = self.CardSpawnRoot.Children for i = 1, #cardEntities do cardEntities[i]:Destroy() end } [client only] void SelectCardCard (Card card) { self.SelectedCard = card card:CardOn() } [client only] void
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | isvalid(card) 체크를 생략하고 카드가 이미 소멸된 상태인 경우 OnCardClicked가 호출되면 어떤 오류가 발생합니까? [answer] | 제공된 참고 문서에는 `isvalid(card)` 체크를 생략했을 때 발생하는 구체적인 오류 메시지나 런타임 예외에 대한 기술이 포함되어 있지 않습니다. 문서에서 확인 가능한 사실은 다음과 같습니다. 1. `OnCardClicked` 핸들러의 첫 줄에서 `isvalid(card) == false`일 경우 즉시 `return`하여 함수 실행을 중단하는 로직이 명시되어 있습니다. 2. 이후 로직에서는 `cardboard.SelectedCard`와 비교를 위해 `card`를 사용하며, 매칭 성공 시 `card:SetDestroyed [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | #### CardPairGameLogic 로직 ```lua Property: [None] Entity CardPairGameUI = /ui/CardPairGameUI [None] number PlayTime = 60 [None] number RemainingTime = 0 Method: [client only] void OnBeginPlay() { self:StartGame() } [client only] void StartGame() { self.CardPairGameUI.Enable = true
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | CardPairGameLogic 의 OnCardClicked 이벤트에서 newCard:SetDestroyed() 실행 후 바로 AddScore 를 호출하는 것과, SetDestroyed() 이후 타이머를 활용하여 지연 호출하는 것 중 카드 소멸 애니메이션과 점수 반영 시점의 자연스러운 연계를 위해 어떤 방식이 권장되는가요? [answer] | 제공된 참고 문서에는 `newCard:SetDestroyed()` 이후 타이머를 활용하여 지연 호출하는 방식에 대한 언급이나 예제가 없습니다. 문서에 명시된 내용만으로는 두 방식 중 어느 것이 권장되는지 판단할 근거가 부족합니다. 참고 문서에서 제시하는 공식적인 구현 방식은 `newCard:SetDestroyed()` 바로 아래 줄에 `AddScore`를 호출하는 것입니다. ```lua oldCard:SetDestroyed() newCard:SetDestroyed() [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 점수 만들기 카드 짝 맞출 때마다 일정한 점수가 증가하게 만들어봅시다. 1. **PlayerStats** 컴포넌트를 **DefalutPlayer**에 추가합니다. **PlayerStats** 컴포넌트는 점수 증가를 담당합니다. 2. **PlayerStats** 컴포넌트에 number 타입 프로퍼티를 아래와 같이 추가합니다. ```lua Property: [None] number Score = 0 ``` 3. 초깃값이 0인 **Score** 프로퍼티에 점수가 더해질 수 있도록 `A
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | CardSet 데이터 테이블의 1열에 저장된 spriteRUID 값이 카드의 비주얼에 어떻게 적용되는지 구체적인 과정을 알려줄 수 있나요? [answer] | 참고 문서에 따르면, `CardSet` 데이터 테이블의 1열에 저장된 `spriteRUID` 값은 카드 엔티티가 생성될 때 카드의 비주얼(이미지)로 적용됩니다. 구체적인 과정은 다음과 같습니다. 1. **데이터 로드 및 덱 구성**: `SetCards` 메서드에서 `_DataService:GetRowCount("CardSet")`을 통해 데이터 행의 개수를 구하고, 1부터 행 개수까지 반복문을 돌며 `_DataService:GetCell("CardSet", i, 1)`을 호출합니다. 이 과정에서 1열에 있는 `sprite [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | ```lua Property: [None] Entity CardSpawnRoot = /ui/CardPairGameUI/UI_Board/UI_Blocks/UI_Block_Group [None] Card SelectedCard = nil [None] Entity TimeText = /ui/CardPairGameUI/UI_Board/Background/Title/Timer_Background/UI_Time/UI_Time_Text [None] Entity ScoreText = /ui/CardPairGameUI/UI_Board/Backgro
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | SetCards() 함수에서 카드 데이터를 섞는 로직이 두 번 반복되는 이유와 각각의 차이점이 궁금해요. [answer] | `SetCards()` 함수에서 카드 데이터를 섞는 로직이 두 번 수행되는 이유는 **카드의 종류(덱 구성)** 와 **카드의 위치(배치 순서)** 를 분리하여 공정하게 준비하기 위해서입니다. 두 섞기 로직의 구체적인 차이점은 다음과 같습니다. **1. 첫 번째 섞기: 카드 종류(스프라이트) 순서 섞기** * **대상 데이터:** `deckTable` * **데이터 내용:** `CardSet` 데이터 행에서 가져온 고유한 카드 스프라이트 ID(`spriteRUID`) 목록입니다. * **목적:** 어떤 카드 종류가 먼 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | ```lua Property: [None] Entity CardSpawnRoot = /ui/CardPairGameUI/UI_Board/UI_Blocks/UI_Block_Group [None] Card SelectedCard = nil [None] Entity TimeText = /ui/CardPairGameUI/UI_Board/Background/Title/Timer_Background/UI_Time/UI_Time_Text [None] Entity ScoreText = /ui/CardPairGameUI/UI_Board/Backgro
[task] | code [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | CardPairGameLogic 컴포넌트의 OnCardClicked 함수 내부에서 newCard:SetDestroyed() 호출 직후 _UserService.LocalPlayer를 참조하여 PlayerStats:AddScore(10)을 실행하는 이벤트 처리 코드를 작성해줘 [answer] | 카드 짝이 맞아서 두 장의 카드가 소멸(`SetDestroyed`)되는 시점에서 점수를 추가하기 위해서는 `CardPairGameLogic` 컴포넌트의 `OnCardClicked` 함수 내부, 구체적으로 `oldCard:IsPairOf(newCard)` 조건이 참이 되는 블록 안의 `newCard:SetDestroyed()` 호출 바로 아래에 코드를 작성해야 합니다. 참고 문서에 명시된 바와 같이, `_UserService.LocalPlayer`를 통해 현재 플레이어를 조회한 후, 해당 플레이어의 `PlayerStats` 컴포넌트 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 점수 만들기 카드 짝 맞출 때마다 일정한 점수가 증가하게 만들어봅시다. 1. **PlayerStats** 컴포넌트를 **DefalutPlayer**에 추가합니다. **PlayerStats** 컴포넌트는 점수 증가를 담당합니다. 2. **PlayerStats** 컴포넌트에 number 타입 프로퍼티를 아래와 같이 추가합니다. ```lua Property: [None] number Score = 0 ``` 3. 초깃값이 0인 **Score** 프로퍼티에 점수가 더해질 수 있도록 `A
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 배경음악, 효과음 만들기 [question] | BGM이 월드 입장 시 자동으로 재생되도록 SoundComponent에서 활성화해야 하는 프로퍼티 두 가지를 나열하세요. [answer] | BGM이 월드 입장 시 자동으로 재생되도록 하려면 SoundComponent에서 다음 두 프로퍼티를 활성화해야 합니다. 1. `BGM` 2. `PlayOnEnable` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 게임을 다 만들었지만 어쩐지 심심한 느낌이 들지 않나요? 마지막으로 배경음악과 효과음을 추가해서 게임을 완성해봅시다. # 배경음악 설정하기 1. **Preset List - Background Music**을 선택합니다. 2. 원하는 BGM을 선택한 뒤, **Hierarchy - maps - map01**을 선택합니다. 프로퍼티 창에서 **SoundComponent**가 추가된 걸 확인할 수 있습니다. **Audio Play**를 눌러 음악을 확인합니다. **BGM, PlayOnEnable** 프로퍼티가 활성화 되어있는지
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | self.CardPairGameUI.Enable = true를 OnBeginPlay에서 설정하는데, UI 엔티티가 아직 로드되지 않아 null 에러가 나는 것을 방지하기 위해 어떤 다른 생명주기 메서드나 방법을 써야 하나요? [answer] | 제공된 참고 문서에는 UI 엔티티 로드 완료 여부를 확인하거나, 로드 전까지 대기하는 특정 생명주기 메서드나 API에 대한 정보가 포함되어 있지 않습니다. 문서에서 확인 가능한 표준 생명주기 메서드는 `OnBeginPlay()`, `OnUpdate(number delta)`, `OnEndPlay()`뿐이며, 이 중 `OnBeginPlay()` 내부에서 `self.CardPairGameUI.Enable = true`를 바로 호출하는 것이 문서에 제시된 유일한 방식입니다. 따라서 문서 근거 내에서 UI 로드 지연으로 인한 null [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | #### CardPairGameLogic 로직 ```lua Property: [None] Entity CardPairGameUI = /ui/CardPairGameUI [None] number PlayTime = 60 [None] number RemainingTime = 0 Method: [client only] void OnBeginPlay() { self:StartGame() } [client only] void StartGame() { self.CardPairGameUI.Enable = true
[task] | two_turn [pass] | ⏳ 미판정 [title] | 배경음악, 효과음 만들기 [question] | 배경음악과 효과음을 추가하기 위해 어떤 리소스를 어디서 찾아야 하나요? [answer] | 배경음악과 효과음을 추가하기 위해 필요한 리소스는 아래 위치에서 찾을 수 있습니다. **1. 배경음악 (BGM)** * **위치:** 에디터의 **Preset List** 메뉴에서 **Background Music** 항목을 선택합니다. * **사용 방법:** 원하는 BGM을 선택한 후, **Hierarchy** 뷰에서 `maps/map01`을 선택하면 프로퍼티 창에 **SoundComponent**가 추가됩니다. 이때 **BGM**과 **PlayOnEnable** 프로퍼티가 활성화되어 있는지 확인해야 합니다. 두 프로퍼티 [followup] | SoundComponent의 BGM, PlayOnEnable 프로퍼티를 활성화하지 않으면 월드 입장 시 배경음악이 재생되지 않나요? [followup_answer] | 네, **BGM**과 **PlayOnEnable** 프로퍼티가 모두 활성화되어 있어야 월드에 입장할 때 배경음악이 자동으로 재생됩니다. **SoundComponent**를 설정할 때는 다음 사항을 확인해야 합니다: 1. **BGM** 프로퍼티가 활성화되어 있는지 확인합니다. 2. **PlayOnEnable** 프로퍼티가 활성화되어 있는지 확인합니다. 두 프로퍼티 중 하나라도 비활성화 상태라면 월드 입장 시 배경음악이 재생되지 않습니다. [scores] | [judge_reason] | [source_doc] | 게임을 다 만들었지만 어쩐지 심심한 느낌이 들지 않나요? 마지막으로 배경음악과 효과음을 추가해서 게임을 완성해봅시다. # 배경음악 설정하기 1. **Preset List - Background Music**을 선택합니다. 2. 원하는 BGM을 선택한 뒤, **Hierarchy - maps - map01**을 선택합니다. 프로퍼티 창에서 **SoundComponent**가 추가된 걸 확인할 수 있습니다. **Audio Play**를 눌러 음악을 확인합니다. **BGM, PlayOnEnable** 프로퍼티가 활성화 되어있는지
[task] | two_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | 카드 짝 맞추기 게임에서 점수 및 남은 시간 텍스트를 UI에 실시간으로 갱신하는 로직은 어떻게 구현되나요? [answer] | 카드 짝 맞추기 게임에서 점수 및 남은 시간 텍스트를 UI에 실시간으로 갱신하는 로직은 클라이언트 측의 `OnUpdate` 생명주기 메서드를 활용하여 매 프레임마다 실행되는 방식으로 구현됩니다. 구체적인 구현 방법은 다음과 같습니다. 1. **UI 엔티티 참조 설정**: 갱신할 대상인 남은 시간 텍스트(`TimeText`)와 점수 텍스트(`ScoreText`) 엔티티를 `Property` 블록에서 선언합니다. 2. **OnUpdate 훅 사용**: `[client only]` 실행 공간의 `OnUpdate(number del [followup] | `UpdateText` 메서드에서 `_CardPairGameLogic.RemainingTime`과 `me.PlayerStats.Score` 값을 어떻게 문자열로 변환하여 `TextComponent`에 할당하는지 구체적인 코드 예시를 보여주세요. [followup_answer] | `UpdateText` 메서드에서 `_CardPairGameLogic.RemainingTime`과 `me.PlayerStats.Score` 값을 문자열로 변환하여 `TextComponent`에 할당하는 구체적인 코드는 다음과 같습니다. 두 값 모두 `number` 타입이지만, `TextComponent.Text`에는 `string` 타입만 할당할 수 있습니다. 또한, 게임 로직상 시간과 점수는 소수점 이하 값을 표시하지 않기 위해 `math.floor()` 함수를 사용하여 정수로 잘라낸 뒤, `tostring()` 함수를 이용해 [scores] | [judge_reason] | [source_doc] | ```lua Property: [None] Entity CardSpawnRoot = /ui/CardPairGameUI/UI_Board/UI_Blocks/UI_Block_Group [None] Card SelectedCard = nil [None] Entity TimeText = /ui/CardPairGameUI/UI_Board/Background/Title/Timer_Background/UI_Time/UI_Time_Text [None] Entity ScoreText = /ui/CardPairGameUI/UI_Board/Backgro
[task] | single_turn [pass] | ⏳ 미판정 [title] | 어노테이션 활용하기 [question] | 여러 값을 반환하는 함수에서 `local strValue, intValue = TestFunction()`처럼 할당받을 때, 뒤의 값만 따로 타입을 지정할 수 없는 이유는 무엇인가요? [answer] | 여러 값을 동시에 할당받을 때 타입 어노테이션(`---@type`)은 **앞에서 뒤로 순서대로** 적용됩니다. 따라서 `local strValue, intValue = TestFunction()` 같은 문장에서 `intValue`만 따로 타입을 지정하는 것은 불가능합니다. 왜냐하면 어노테이션은 첫 번째 변수부터 시작하여 연속적으로 값을 매핑하기 때문입니다. 중간이나 뒤의 변수만 건너뛰고 타입을 지정할 수 있는 문법이 존재하지 않아, 앞의 값부터 순서대로 지정해야 합니다. 예를 들어 `local strValue, intValue [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 **어노테이션**(Annotation)은 코드에 추가하여 사용하는 일종의 메타데이터입니다. 스크립트에 `--` 기호를 사용한 주석(Comment)은 스크립트 작성에 참고 역할만 하는 반면, `---@` 형태로 **어노테이션**을 작성하면 **퀵 인포**나 **시그니처 헬퍼**, **코드 컴플리션** 등 스크립트 어시스트의 도움을 받을 수 있습니다. 본 과정을 통해 메이플스토리 월드에서 제공하는 **어노테이션**의 종류와 활용 방법을 알아봅시다. > **더 알아보기** > 퀵 인포, 시그니처 헬퍼, 코드 컴플리
[task] | code [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | `OnBeginPlay` 에서 `CardPairGameUI` 를 활성화하고 `CardBoard` 의 `SetCards` 메서드를 호출하여 초기 카드를 배치하는 시작 처리를 수행해줘. [answer] | 요청하신 시작 처리(`OnBeginPlay`에서 UI 활성화 및 카드 배치)는 아래 스크립트와 같이 구현할 수 있습니다. ```lua Property: [None] Entity CardPairGameUI = /ui/CardPairGameUI Method: [client only] void OnBeginPlay() { self.CardPairGameUI.Enable = true local cardboard = self.CardPairGameUI.CardBoard cardboard:SetCards() } `` [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | #### CardPairGameLogic 로직 ```lua Property: [None] Entity CardPairGameUI = /ui/CardPairGameUI [None] number PlayTime = 60 [None] number RemainingTime = 0 Method: [client only] void OnBeginPlay() { self:StartGame() } [client only] void StartGame() { self.CardPairGameUI.Enable = true
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | UserService.LocalPlayer 로 접근한 me 객체를 통해 PlayerStats 컴포넌트를 호출할 때, me.PlayerStats 가 아닌 me:GetComponent("PlayerStats") 와 같은 구문으로 접근해야 하는지 mLua 의 컴포넌트 접근 규칙이 궁금합니다. [answer] | mLua에서는 `GetComponent()` 메서드를 사용하지 않습니다. 컴포넌트 접근은 **엔티티 이름(또는 컴포넌트 이름)을 프로퍼티처럼 직접 붙여** 사용하는 규칙을 따릅니다. 따라서 `me.PlayerStats` 구문이 올바른 접근 방식이며, `me:GetComponent("PlayerStats")`는 mLua의 컴포넌트 접근 규칙에 맞지 않습니다. ### mLua 컴포넌트 접근 규칙 요약 1. **직접 프로퍼티 접근**: 엔티티 객체(예: `self.Entity`, `me`, `cardboard` 등) 뒤에 컴포넌트 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 점수 만들기 카드 짝 맞출 때마다 일정한 점수가 증가하게 만들어봅시다. 1. **PlayerStats** 컴포넌트를 **DefalutPlayer**에 추가합니다. **PlayerStats** 컴포넌트는 점수 증가를 담당합니다. 2. **PlayerStats** 컴포넌트에 number 타입 프로퍼티를 아래와 같이 추가합니다. ```lua Property: [None] number Score = 0 ``` 3. 초깃값이 0인 **Score** 프로퍼티에 점수가 더해질 수 있도록 `A
[task] | code [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | `OnUpdate` 에서 매 프레임마다 `RemainingTime` 을 감소시켜 0 이하가 되면 `CardPairGameUI` 의 `Enable` 속성을 false 로 설정하여 게임을 종료하는 로직을 구현해줘. [answer] | `OnUpdate` 메서드에서 매 프레임마다 `delta` 값을 `RemainingTime`에서 빼주어 시간을 계산하고, 0 이하가 되는 순간 `CardPairGameUI`의 `Enable` 속성을 `false`로 설정하는 로직입니다. ```lua Property: [None] Entity CardPairGameUI = /ui/CardPairGameUI [None] number PlayTime = 60 [None] number RemainingTime = 0 Method: [client only] void OnBeginPlay( [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | #### CardPairGameLogic 로직 ```lua Property: [None] Entity CardPairGameUI = /ui/CardPairGameUI [None] number PlayTime = 60 [None] number RemainingTime = 0 Method: [client only] void OnBeginPlay() { self:StartGame() } [client only] void StartGame() { self.CardPairGameUI.Enable = true
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | self.CardSpawnRoot.Children에 접근하여 루프를 돌릴 때, 리스트의 길이(#cardEntities)가 변하는 상황에서 인덱스 접근 시 주의해야 할 점은 무엇인가요? [answer] | `self.CardSpawnRoot.Children` 리스트의 길이(`#cardEntities`)가 루프 도중 변하는 상황에서는 **인덱스 오버플로우(Index Out of Range) 오류**가 발생할 수 있습니다. 참고 문서의 `ClearCardEntities` 함수는 다음과 같이 작성되어 있습니다. ```lua [client Only] void ClearCardEntities () { local cardEntities = self.CardSpawnRoot.Children for i = 1, [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | [client Only] void ClearCardEntities () { local cardEntities = self.CardSpawnRoot.Children for i = 1, #cardEntities do cardEntities[i]:Destroy() end } [client only] void SelectCardCard (Card card) { self.SelectedCard = card card:CardOn() } [client only] void
[task] | single_turn [pass] | ⏳ 미판정 [title] | 어노테이션 활용하기 [question] | 이벤트, 컴포넌트, 엔티티, Enum과 같은 복잡한 객체도 단순 원시 타입처럼 `---@type`으로 지정할 수 있나요? [answer] | 네, 가능합니다. **Type Annotation**(`---@type`)은 `string`, `integer`와 같은 단순한 원시 타입뿐 아니라 **이벤트, 컴포넌트, 엔티티, Enum** 등 다양한 복잡한 객체 타입에도 지정할 수 있습니다. 이를 통해 스크립트 에디터에서 퀵 인포, 시그니처 헬퍼, 코드 컴플리션 등 스크립트 어시스트의 도움을 받을 수 있습니다. ### 사용 예시 일반적인 원시 타입 지정과 동일한 문법(`---@type TYPE`)을 사용합니다. ```lua -- 엔티티 타입 지정 ---@type Entit [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | # 학습 과정 소개 **어노테이션**(Annotation)은 코드에 추가하여 사용하는 일종의 메타데이터입니다. 스크립트에 `--` 기호를 사용한 주석(Comment)은 스크립트 작성에 참고 역할만 하는 반면, `---@` 형태로 **어노테이션**을 작성하면 **퀵 인포**나 **시그니처 헬퍼**, **코드 컴플리션** 등 스크립트 어시스트의 도움을 받을 수 있습니다. 본 과정을 통해 메이플스토리 월드에서 제공하는 **어노테이션**의 종류와 활용 방법을 알아봅시다. > **더 알아보기** > 퀵 인포, 시그니처 헬퍼, 코드 컴플리
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 배경음악, 효과음 만들기 [question] | OnCardClicked 함수 내 각 코드 라인에 추가해야 할 _SoundService:PlaySound 호출 문장만 출력하세요. [answer] | ```lua cardboard:SelectCard(newCard) _SoundService:PlaySound("0c57ceb6897c4955b1a4e860c6895868", 0.7) ``` ```lua cardboard:DeselectCard() _SoundService:PlaySound("0c57ceb6897c4955b1a4e860c6895868", 0.7) ``` ```lua newCard:SetDestroyed() _SoundService:PlaySound("3b79d37626de4023a600e90d7e1595f8", 0 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | 게임을 다 만들었지만 어쩐지 심심한 느낌이 들지 않나요? 마지막으로 배경음악과 효과음을 추가해서 게임을 완성해봅시다. # 배경음악 설정하기 1. **Preset List - Background Music**을 선택합니다. 2. 원하는 BGM을 선택한 뒤, **Hierarchy - maps - map01**을 선택합니다. 프로퍼티 창에서 **SoundComponent**가 추가된 걸 확인할 수 있습니다. **Audio Play**를 눌러 음악을 확인합니다. **BGM, PlayOnEnable** 프로퍼티가 활성화 되어있는지
[task] | single_turn [pass] | ⏳ 미판정 [title] | 점수 만들기 [question] | cardboard:IsEmpty()가 true일 때 SetCards()를 다시 호출하면 기존에 선택된 카드 상태는 초기화되나요? [answer] | 제공된 문서의 코드와 설명을 기준으로 판단할 때, `cardboard:IsEmpty()`가 true일 때 `SetCards()`를 다시 호출하면 기존에 선택된 카드 상태는 초기화되지 않습니다. 이유는 다음과 같습니다. 1. **선택 상태 해제 시점:** 카드가 모두 제거되는 상황(`IsEmpty()`가 true)에 도달하려면, 마지막 남은 두 장의 카드가 짝이 맞아야 합니다. 코드를 보면 짝이 맞을 때(`oldCard:IsPairOf(newCard)`가 true일 때) `cardboard:DeselectCard()`가 먼저 호 [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | #### CardPairGameLogic 로직 ```lua Property: [None] Entity CardPairGameUI = /ui/CardPairGameUI [None] number PlayTime = 60 [None] number RemainingTime = 0 Method: [client only] void OnBeginPlay() { self:StartGame() } [client only] void StartGame() { self.CardPairGameUI.Enable = true
[task] | instruction_following [pass] | ⏳ 미판정 [title] | 어노테이션 활용하기 [question] | 문서에 제시된 `---@type` 함수 타입 지정 문법의 기본 형식을 표(항목, 설명)로 정리하세요. [answer] | 문서에 제시된 `---@type` 함수 타입 지정 문법의 기본 형식은 다음과 같습니다. | 항목 | 설명 | | :--- | :--- | | `function` | 함수 타입임을 나타내는 키워드입니다. | | `param_name` | 함수의 매개변수 이름입니다. | | `PARAM_TYPE` | 매개변수의 타입입니다. (예: `string`, `Entity`, `AttackComponent` 등) | | `RETURN_TYPE` | 함수가 반환하는 값의 타입입니다. | **기본 문법 구조:** ```lua ---@type fu [followup] | [followup_answer] | [scores] | [judge_reason] | [source_doc] | Function은 아래와 같은 문법으로 타입을 지정합니다. ```lua ---@type function(param_name: PARAM_TYPE):RETURN_TYPE ``` ##### 사용 예시 ```lua ---@type function() local testFunction = function() end ``` ```lua ---@type function(testParamA:string, testParamB:Entity) local testFunction = function(testParamA, testParamB) end