포스트

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를 사용했다.

Image

처음에 올라오는건 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에 관한 세팅을 하게되면

Image

이렇게 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)를 사용하였다.

이것도 뭐 크게 언급할 부분은 없다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.