HP Trivia (8)
GamePlayView
이전글에서 게임로직을 구현해놓았으니, 이제는 직점 게임을 하는 것에 대한 UI를 그려본다.
그전에 PlayButton에 있는
1
@State private var playGame = false
이걸 ContentView로 옮겨준다.
왜냐면 Playbutton에서는 @Binding
Wrapper를 사용할 예정이기 때문
그렇게 관련된 부분들을 전부 바꿔주고
ContentView로 가서
1
2
3
4
5
6
7
.onAppear {
animateViewsIn = true
//playAudio()
}
.fullScreenCover(isPresented: $playGame) { // new
GamePlayView()
}
전에는 sheet
Modifier를 사용해서 화면을 보여줬다면, 이번에는 fullScreenCover
를 사용했다.
처음에 올라오는건 sheet이고, 두번째로 올라오는게 fullscreencover이다.
둘의 차이는 사진을 보면 알겠지만, 드래그를 통해서 view를 전환할 수 없다.
그리고 지금 Audio가 무한 재생이라 잠시 주석을 잡아뒀는데
1
2
3
4
GamePlayView()
.onAppear {
audioPlayer.setVolume(0, fadeDuration: 2)
}
이렇게 GamePlayView로 전환할때 소리를 0으로 줄일 수 있다.
이때 주의점
1
2
3
4
5
6
7
8
9
10
.onAppear {
animateViewsIn = true
//playAudio()
}
.fullScreenCover(isPresented: $playGame) {
GamePlayView()
.onAppear {
audioPlayer.setVolume(0, fadeDuration: 2)
}
}
음악 재생 Method를 주석 한 상태에서 하단의 onappear에서 audioplayer에 관한 세팅을 하게되면
이렇게 Crash가 발생
간단한 이유는 audioplayer가 nil이기 때문 (audioPlayer 초기화가 되지 않은 상태에서 setVolume()을 호출하면 런타임 에러 발생)
그래서 preview로 테스트를 할때 소리가 너무 거슬리다면
1
2
3
4
5
6
private func playAudio() {
let sound = Bundle.main.path(forResource: "magic-in-the-air", ofType: "mp3")
audioPlayer = try! AVAudioPlayer(contentsOf: URL(filePath: sound!))
audioPlayer.numberOfLoops = -1
//audioPlayer.play()
}
오히려 이렇게 재생에 관한 부분만 주석을 잡도록 하자.
GamePlayView에서 다시 ContentView로 돌아올때는 배경음악이 재생되도록 하기위해
1
2
3
4
5
6
7
GamePlayView()
.onAppear {
audioPlayer.setVolume(0, fadeDuration: 2)
}
.onDisappear {
audioPlayer.setVolume(1, fadeDuration: 3)
}
이렇게 onDisappear
를 사용해주면 된다.
볼륨크기를 3초에 걸쳐 1로 올리겠다는것.
View 틀 짜기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var body: some View {
GeometryReader { geo in
ZStack {
Image(.hogwarts)
.resizable()
.frame(width: geo.size.width * 3, height: geo.size.height * 1.05)
.overlay {
Rectangle()
.foregroundStyle(.black.opacity(0.8))
}
VStack {
// MARK: - Controls
// MARK: - Question
// MARK: - Hints
// MARK: - Answers
}
.frame(width: geo.size.width, height: geo.size.height)
}
.frame(width: geo.size.width, height: geo.size.height)
// MARK: - Celebration
}
.ignoresSafeArea()
}
이렇게 MARK를 이용해서 전반적으로 어떻게 UI를 구성할지에 대해 틀만 짜두도록 한다.
Sounds Effect
디자인은 잠시 보류하고 GamePlayView에 다음과 같이 만들어 주었다.
크게 언급할 부분은 없다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@State private var musicPlayer: AVAudioPlayer!
@State private var sfxPlayer: AVAudioPlayer!
private func playMusic() {
let songs = ["let-the-mystery-unfold", "spellcraft", "hiding-place-in-the-forest", "deep-in-the-dell"]
let song = songs.randomElement()!
let sound = Bundle.main.path(forResource: song, ofType: "mp3")
musicPlayer = try! AVAudioPlayer(contentsOf: URL(filePath: sound!))
musicPlayer.numberOfLoops = -1
musicPlayer.volume = 0.1
musicPlayer.play()
}
private func playFilpSound() {
let sound = Bundle.main.path(forResource: "page-flip", ofType: "mp3")
sfxPlayer = try! AVAudioPlayer(contentsOf: URL(filePath: sound!))
sfxPlayer.play()
}
private func playWrongSound() {
let sound = Bundle.main.path(forResource: "negative-beeps", ofType: "mp3")
sfxPlayer = try! AVAudioPlayer(contentsOf: URL(filePath: sound!))
sfxPlayer.play()
}
private func playCorrectSound() {
let sound = Bundle.main.path(forResource: "magic-wand", ofType: "mp3")
sfxPlayer = try! AVAudioPlayer(contentsOf: URL(filePath: sound!))
sfxPlayer.play()
}
그리고 2초후에 음악을 재생하기위해
1
2
3
4
5
6
7
.onAppear {
game.startGame()
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
playMusic()
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2)
를 사용하였다.
이것도 뭐 크게 언급할 부분은 없다.