100 Days of SwiftUI - Day 22
Project 2, part 3
이번 날에는 프로젝트를 잘 이해하고 있는지 테스트를 하고,
3개의 문제를 혼자 해결해야 한다.
Challenge
@State
를 사용하여 점수를 저장하는 프로퍼티를 생성한 다음, 플레이어가 답을 맞추거나 틀리면 점수를 변경하고 UI에 표시- 잘못된 국기를 선택하는 경우
alert
에서 틀렸다는 메시지와 함께 해당 국기의 국가명을 같이 표시 - 한 게임을 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()
}