본문 바로가기

IOS(Swift)

[IOS/Swift] MBTI 카드 선택 게임 UI 구현

반응형

swift ui를 이용해 어플리케이션 설계를 진행 해봅시다.

검색 화면 UI 목업

기획된 구성은 다음과 같습니다.

  • 문서량 또는 언급량을 비교할 두 개의 항목을 각각 카드로 보여줍니다.
  • 항상 아래에 있는 카드(파랑)가 위에 있는 카드(빨강) 보다 언급량이 더 많은지 낮은지를 선택합니다.
  • 정답을 맞추면 다음 카드로 이동, 잘못 선택하면 게임이 끝납니다.

데이터 구성

게임을 구성하는 데이터(API 전달 결과)를 설계해봅시다.

struct StageList: Codable {
    var data: Array<String>
    var answer: Array<Int>
}

API에서 응답받은 결과를 처리하는 Struct는 다음과 같습니다.

실제 데이터는 다음과 같습니다.

{
    "data": ["짜장면", "짬뽕", "탕수육", "유린기", "꿔바로우"],
    "answer": [100, 1000, 1200, 500, 400]
}

각 리스트의 항목들이 카드 항목으로 순차적으로 생성됩니다. 예를들어 data[0], data[1]이 카드로 생성됩니다.

데이터를 바탕으로 코드 전체를 작성해봅시다.

//
//  GameView.swift
//  mbtiRankGame
//
//  Created by 박종후 on 2022/05/15.
//

import SwiftUI

struct GameView: View {
    
    var data: StageList
    @State private var firstCard = false
    @State private var secondCard = true
    @State private var isFirstCard = false
    
    @State private var cardX: CGFloat = UIScreen.main.bounds.width
    @State private var topCardY:CGFloat = CGFloat(150)
    @State private var secCardY:CGFloat = CGFloat(150 + UIScreen.main.bounds.height * 0.4)
    
    @State private var stage: Array<String>
    @State private var answer: Array<Int>
    @State private var firstText: String
    @State private var secondText: String
    @State private var firstCount: Int
    @State private var secondCount: Int
    @State private var showCount = false
    
    @State private var showAlert = false
    @State private var showGameEnd = false
    
    // 클래스 초기화 시 할당되지 않은 데이터를 할당함. data는 위에 json 데이터를 가져옴
    init(data: StageList){
        self.data = data
        self.stage = data.data
        self.answer = data.answer
        self.firstText = data.data[0]
        self.secondText = data.data[1]
        self.firstCount = data.answer[0]
        self.secondCount = data.answer[1]
    }
    
    func checkStage(isSmall: Bool) -> (Bool, Bool){
        var res: Bool
        var isNext = true
//        if (self.answer.count < 3){
//            isNext = false
//            return (false, isNext)
//        }
        if (self.answer[1] == self.answer[self.answer.count - 1]){
            isNext = false
        }
        if (self.answer[0] < self.answer[1]){
            res = isSmall ? true: false
        } else {
            res = isSmall ? false: true
        }
        return (res, isNext)
    }
    func changeStatus() {
        self.firstCard.toggle()
        self.secondCard.toggle()
        self.stage.removeFirst()
        self.answer.removeFirst()
    }
    
    var body: some View {
        VStack{
            ZStack{
                CardItem(firstCard: true, isFirst: self.firstCard, targetText: self.firstText, targetCount: self.firstCount, isShowCount: showCount ? false : true)
                CardItem(firstCard: false, isFirst: self.secondCard, targetText: self.secondText, targetCount: self.secondCount, isShowCount: showCount ? true : false)
            }
            HStack{
                Button(action: {
                    let (res, isNext) = self.checkStage(isSmall: true)
                    if (isNext==false){
                        showGameEnd = true
                        showCount.toggle()
                    }else{
                        if (res==true){
                            self.changeStatus()
                            if (self.isFirstCard != true){
                                self.firstText = self.stage[1]
                                self.firstCount = self.answer[1]
                                self.isFirstCard = isFirstCard ? false : true
                            }else{
                                self.secondText = self.stage[1]
                                self.secondCount = self.answer[1]
                            }
                            showCount.toggle()
                        }else{
                            showAlert = true
                        }
                    }
                    
                }){
                    Text("더 높다")
                }.alert("틀렸습니다.", isPresented: $showAlert){
                    Button("OK", role: .cancel){}
                }.alert("게임이 종료됐습니다.", isPresented: $showGameEnd){
                    Button("OK", role: .cancel){}
                }
                
                Button(action: {
                    let (res, isNext) = self.checkStage(isSmall: true)
                    if (isNext==false){
                        showGameEnd = true
                        showCount.toggle()
                    }else{
                        if (res==false){
                            self.changeStatus()
                            if (isFirstCard == true){
                                showCount.toggle()
                                self.firstText = self.stage[1]
                                self.firstCount = self.answer[1]
                            }else{
                                isFirstCard = isFirstCard ? false : true
                                self.secondText = self.stage[1]
                                self.secondCount = self.answer[1]
                                
                                
                            }
                            
                        }else{
                            showAlert = true
                        }
                    }
                    
                }){
                    Text("더 낮다")
                }.alert("틀렸습니다.", isPresented: $showAlert){
                    Button("OK", role: .cancel){}
                }.alert("게임이 종료됐습니다.", isPresented: $showGameEnd){
                    Button("OK", role: .cancel){}
                }
            }
            
        }
    }
}

struct GameView_Previews: PreviewProvider {
    static var previews: some View {
        GameView(data:ModelData().stageList)
    }
}

코드를 작성하면서 Swift UI에서 발견한 개발 내용을 정리해봤습니다.

클래스 초기화 시 변수 할당

...
init(data: StageList){
        self.data = data
        self.stage = data.data
        self.answer = data.answer
        self.firstText = data.data[0]
        self.secondText = data.data[1]
        self.firstCount = data.answer[0]
        self.secondCount = data.answer[1]
    }

View 클래스 내부에서 data, stage, 등의 변수는 @State private 변수지만 선언만 된 값이었습니다. 여기서 init 함수를 사용해서 데이터를 할당하고 View 내부에서 사용할 수 있도록 해주었습니다.

 

 

반응형