comparison GeoQuiz/Logic/GameProtocol+Extension.swift @ 10:a793f33f05fb

refactor code and fix layout
author Dennis C. M. <dennis@denniscm.com>
date Sat, 08 Oct 2022 21:36:40 +0200
parents GeoQuiz/Logic/Game.swift@3540c7efc216
children 136928bae534
comparison
equal deleted inserted replaced
9:3540c7efc216 10:a793f33f05fb
1 //
2 // GameProtocol+Extension.swift
3 // GeoQuiz
4 //
5 // Created by Dennis Concepción Martín on 18/9/22.
6 //
7
8 import Foundation
9 import SwiftUI
10 import AVFAudio
11
12 protocol Game: ObservableObject {
13
14 // Define generic type
15 associatedtype T: Equatable
16
17 // Game
18 var data: [String: T] { get set}
19 var dataAsked: [String: T] { get set }
20 var correctAnswer: (key: String, value: T) { get set }
21
22 // User
23 var userChoices: [String: T] { get set }
24 var userScore: Int { get set }
25 var userLives: Int { get set }
26 var correctAnswers: [String: T] { get set }
27 var wrongAnswers: [String: T] { get set }
28
29 // Alerts
30 var alertTitle: String { get set }
31 var alertMessage: String { get set }
32 var showingGameOverAlert: Bool { get set }
33 var showingEndGameAlert: Bool { get set }
34 var showingWrongAnswerAlert: Bool { get set }
35 var showingExitGameAlert: Bool { get set }
36
37 // Animations
38 var scoreScaleAmount: Double { get set }
39 var livesScaleAmount: Double { get set }
40
41 // Sound effects
42 var player: AVAudioPlayer? { get set }
43
44 func selector()
45 }
46
47 extension Game {
48 var questionCounter: Int {
49 dataAsked.count
50 }
51
52 func askQuestion(selector: () -> Void) {
53 guard questionCounter < data.count else {
54 alertTitle = "⭐️ Congratulations ⭐️"
55 alertMessage = "You completed the game."
56 showingEndGameAlert = true
57
58 return
59 }
60
61 selector()
62 }
63
64 func answer(_ choice: (key: String, value: T), selector: () -> Void) {
65 let haptics = Haptics()
66
67 if correctAnswer == choice {
68 haptics.success()
69 playSound("correctAnswer")
70
71 withAnimation(.easeIn(duration: 0.5)) {
72 scoreScaleAmount += 1
73 userScore += 1
74 }
75
76 correctAnswers[correctAnswer.key] = correctAnswer.value
77 askQuestion {
78 selector()
79 }
80 } else {
81 haptics.error()
82 playSound("wrongAnswer")
83
84 withAnimation(.easeIn(duration: 0.5)) {
85 livesScaleAmount += 1
86 userLives -= 1
87 }
88
89 wrongAnswers[choice.key] = choice.value
90
91 if userLives == 0 {
92 alertTitle = "🤕 Game over 🤕"
93 alertMessage = "Get up and try again."
94 showingGameOverAlert = true
95 } else {
96 alertTitle = "🔴 Wrong 🔴"
97 alertMessage = "You have \(userLives) lives left."
98 showingWrongAnswerAlert = true
99 }
100 }
101
102 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [self] in
103 withAnimation(.easeIn(duration: 0.5)) {
104 scoreScaleAmount = 1
105 livesScaleAmount = 1
106 }
107 }
108 }
109
110 func reset(selector: () -> Void) {
111 dataAsked = [String: T]()
112 userScore = 0
113 userLives = 3
114 correctAnswers = [String: T]()
115 wrongAnswers = [String: T]()
116 askQuestion {
117 selector()
118 }
119 }
120
121 private func playSound(_ filename: String) {
122 let user = User()
123
124 if user.settings.sound {
125 guard let soundFileURL = Bundle.main.url(forResource: filename, withExtension: "wav") else {
126 fatalError("Sound file \(filename) couldn't be found")
127 }
128
129 do {
130 try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient)
131 try AVAudioSession.sharedInstance().setActive(true)
132 } catch {
133 fatalError("Couldn't activate session")
134 }
135
136 do {
137 player = try AVAudioPlayer(contentsOf: soundFileURL)
138 player?.play()
139 } catch {
140 fatalError("Couldn't play sound effect")
141 }
142 }
143 }
144 }