Project 2, part 3

이번 날에는 프로젝트를 잘 이해하고 있는지 테스트를 하고,
3개의 문제를 혼자 해결해야 한다.

Challenge

  1. @State를 사용하여 점수를 저장하는 프로퍼티를 생성한 다음, 플레이어가 답을 맞추거나 틀리면 점수를 변경하고 UI에 표시
  2. 잘못된 국기를 선택하는 경우 alert에서 틀렸다는 메시지와 함께 해당 국기의 국가명을 같이 표시
  3. 한 게임을 8개의 스테이지만 진행하게 하고, 8개의 스테이지가 모두 끝난 경우 최종 스코어와 다시하기 알림을 표시

문제 풀이

*정답이 아닐 수 있음.

1번

점수를 저장할 score프로퍼티를 선언함. UI에 표시가 될 수 있기 때문에 @State 프로퍼티 래퍼를 사용

//점수를 저장할 프로퍼티
@State private var score = 0

Score:??? 에 물음표 대신 score가 표시될 수 있게 수정함.

// ??? -> \(score) 변경
Text("Score: \(score)")
    .foregroundStyle(.white)
    .font(.title.bold())

사용자가 답을 맞추면 +10점, 틀리면 -1점을 얻도록 함. 0점일 때 틀린 경우 마이너스 점수로 가는 것은 예외처리 하지 않았음.
점수 관련한 게임 로직은 flagTapped() 함수에서 처리하도록 했음.

2번도 여기서 확인할 수 있음. countries[number]를 활용하여 탭한 국기 정보를 가져와, 틀렸을 때 표시되는 문구에 추가한다.

func flagTapped(_ number:Int) {
        if number == correctAnswer {
            scoreTitle = "Correct!"
            score += 10 //10점 추가
        } else {
            scoreTitle = "Wrong! it's \(countries[number])"
            score -= 1  //1점 삭제
        }        
        // alert를 표시하도록 프로퍼티의 값을 변경
        showingScore = true
    }

3번

8개의 스테이지를 체크하기 위해, 현재 스테이지를 저장하는 stage와 게임이 끝났는지 여부를 체크하는 isGameEnd 프로퍼티를 선언했다.
이들 역시 UI의 상태 변화에 관여하므로 @State 프로퍼티 래퍼를 사용했다.

//8문제 중 현재 몇 스테이지인지?
@State private var stage = 1

//게임이 끝나는지를 체크
@State private var isGameEnd = false

스테이지 체크와 관련된 로직은 askQuestion() 함수에서 처리했다.

if-else문을 사용하여 진행한 스테이지를 stage 프로퍼티를 활용하여 체크, 8스테이지 이상 진행한 경우 isGameEnd 프로퍼티를 true값으로 바꿔 게임 종료 alert가 표시되도록 했다.

func askQuestion() {
    countries.shuffle()
    correctAnswer = Int.random(in: 0...2)
    if stage>=8 {
        isGameEnd = true
    } else {
        stage += 1            
    }
}

게임 종료 alert는 정답/오답을 알리는 alert 바로 다음 추가했다.

.alert("Game End, Total Score: \(score)", isPresented: $isGameEnd) {
    Button("Restart", action: reset)
}

게임이 끝나면 버튼을 통해 reset 함수가 실행되도록 한다. 게임을 초기상태로 되돌린다.

//게임을 리셋함
func reset() {
    countries.shuffle() //1
    correctAnswer = Int.random(in: 0...2)//2
    stage = 1
    score = 0
}

주석 1, 2번은 askQuestion에서 배열을 섞는 로직을 그대로 가져왔는데, 게임 재시작 시 이전 문제가 그대로 나타나는 현상이 발생하였기 때문에 게임 초기화 시 배열이 다시 섞여 새로운 문재가 나타나도록 했다.

전체 코드

//
//  ContentView.swift
//  GuessTheFlag
//
//  Created by 이찬희 on 11/7/23.
//

import SwiftUI

struct ContentView: View {
    
    //국기들의 배열
    @State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Nigeria", "Poland", "Spain", "UK", "Ukraine", "US"].shuffled()
    
    @State private var correctAnswer = Int.random(in: 0...2)

    //alert를 표시할 프로퍼티
    @State private var showingScore = false
    // alert 안에 저장할 타이틀
    @State private var scoreTitle = ""
    
    //점수를 저장할 프로퍼티
    @State private var score = 0
    
    //8문제 중 현재 몇 스테이지인지?
    @State private var stage = 1
    //게임이 끝나는지를 체크
    @State private var isGameEnd = false
    
    var body: some View {
        
        ZStack {
            //배경 설정
            RadialGradient(stops: [
                .init(color: Color(red: 0.1, green: 0.2, blue: 0.45), location: 0.3),
                .init(color: Color(red: 0.76, green: 0.15, blue: 0.26), location: 0.3),
            ], center: .top, startRadius: 200, endRadius: 400)
                .ignoresSafeArea()
            
            //외부 VStack
            VStack {
                Text("Guess the Flag( \(stage) / 8 )")
                    .font(.largeTitle.weight(.bold))
                    .foregroundStyle(.white)
                
                //내부 VStack
                VStack(spacing: 15) {
                    VStack {
                        Text("Tap the flag of")
                            .font(.subheadline.weight(.heavy))
                            .foregroundStyle(.secondary)
                            
                        Text(countries[correctAnswer])
                            .font(.largeTitle.weight(.semibold))
                            
                    }
                    
                    
                        ForEach(0..<3) { number in
                            Button {
                                flagTapped(number)
                            } label: {
                                Image(countries[number])
                                    .clipShape(.capsule)
                                    .shadow(radius: 5)
                            }
                            
                        
                    }
                }
                .frame(maxWidth: .infinity)
                .padding(.vertical, 20)
                .background(.regularMaterial)
                .clipShape(.rect(cornerRadius: 20))
                
                Text("Score: \(score)")
                    .foregroundStyle(.white)
                    .font(.title.bold())
            }
            .padding()
        }
        .alert(scoreTitle,isPresented: $showingScore) {
            Button("Continue", action: askQuestion)
        }
        .alert("Game End, Total Score: \(score)", isPresented: $isGameEnd) {
            Button("Restart", action: reset)
        }
    }
        
    // 정답과 오답을 처리하는 부분, 주요 게임 로직
    func flagTapped(_ number:Int) {
        if number == correctAnswer {
            scoreTitle = "Correct!"
            score += 10 //10점 추가
        } else {
            scoreTitle = "Wrong! it's \(countries[number])"
            score -= 1
        }
        
        // alert를 표시하도록 프로퍼티의 값을 변경
        showingScore = true
    }
    
    func askQuestion() {
        countries.shuffle()
        correctAnswer = Int.random(in: 0...2)
        if stage>=8 {
            isGameEnd = true
        } else {
            stage += 1
            
        }
    }
    
    //게임을 리셋함
    func reset() {
        countries.shuffle()
        correctAnswer = Int.random(in: 0...2)
        stage = 1
        score = 0
    }
}

#Preview {
    ContentView()
}

카테고리:

업데이트: