Mercurial > public > geoquiz
comparison GeoQuiz/Models/Controllers/GameProtocol+Extension.swift @ 26:425078c01194
refactor code
author | Dennis C. M. <dennis@denniscm.com> |
---|---|
date | Wed, 09 Nov 2022 10:30:01 +0100 |
parents | GeoQuiz/Logic/GameProtocol+Extension.swift@e281791e0494 |
children | 3f4b366d476d |
comparison
equal
deleted
inserted
replaced
25:b3df0f5dc750 | 26:425078c01194 |
---|---|
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 import CoreData | |
12 | |
13 @objc | |
14 public enum GameType: Int16, CaseIterable { | |
15 case guessTheFlag | |
16 case guessTheCapital | |
17 case guessTheCountry | |
18 case guessThePopulation | |
19 } | |
20 | |
21 protocol Game: ObservableObject { | |
22 | |
23 // Define generic type | |
24 associatedtype T: Equatable | |
25 | |
26 // Game | |
27 var data: [String: T] { get set} | |
28 var dataAsked: [String: T] { get set } | |
29 var correctAnswer: (key: String, value: T) { get set } | |
30 | |
31 // User | |
32 var userChoices: [String: T] { get set } | |
33 var userScore: Int { get set } | |
34 var userLives: Int { get set } | |
35 var correctAnswers: [String: T] { get set } | |
36 var wrongAnswers: [String: T] { get set } | |
37 | |
38 // Alerts | |
39 var alertTitle: String { get set } | |
40 var alertMessage: String { get set } | |
41 var showingEndGameAlert: Bool { get set } | |
42 var showingWrongAnswerAlert: Bool { get set } | |
43 var showingExitGameAlert: Bool { get set } | |
44 | |
45 // Animations | |
46 var scoreScaleAmount: Double { get set } | |
47 var livesScaleAmount: Double { get set } | |
48 | |
49 // Sound effects | |
50 var player: AVAudioPlayer? { get set } | |
51 | |
52 func selector() | |
53 } | |
54 | |
55 extension Game { | |
56 var questionCounter: Int { | |
57 dataAsked.count | |
58 } | |
59 | |
60 func askQuestion(selector: () -> Void) { | |
61 guard questionCounter < data.count else { | |
62 alertTitle = "⭐️ Congratulations ⭐️" | |
63 alertMessage = "You completed the game." | |
64 showingEndGameAlert = true | |
65 | |
66 return | |
67 } | |
68 | |
69 selector() | |
70 } | |
71 | |
72 func answer(choice: (key: String, value: T), wrongMessage: String, selector: () -> Void) { | |
73 let haptics = HapticsController() | |
74 | |
75 if correctAnswer == choice { | |
76 haptics.success() | |
77 playSound("correctAnswer") | |
78 | |
79 withAnimation(.easeIn(duration: 0.5)) { | |
80 scoreScaleAmount += 1 | |
81 userScore += 1 | |
82 } | |
83 | |
84 correctAnswers[correctAnswer.key] = correctAnswer.value | |
85 askQuestion { | |
86 selector() | |
87 } | |
88 } else { | |
89 haptics.error() | |
90 playSound("wrongAnswer") | |
91 | |
92 withAnimation(.easeIn(duration: 0.5)) { | |
93 livesScaleAmount += 1 | |
94 userLives -= 1 | |
95 } | |
96 | |
97 wrongAnswers[choice.key] = choice.value | |
98 | |
99 if userLives == 0 { | |
100 alertTitle = "🤕 Game over 🤕" | |
101 alertMessage = "Get up and try again." | |
102 showingEndGameAlert = true | |
103 } else { | |
104 alertTitle = "🔴 Wrong 🔴" | |
105 alertMessage = "\(wrongMessage). You have \(userLives) lives left." | |
106 showingWrongAnswerAlert = true | |
107 } | |
108 } | |
109 | |
110 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [self] in | |
111 withAnimation(.easeIn(duration: 0.5)) { | |
112 scoreScaleAmount = 1 | |
113 livesScaleAmount = 1 | |
114 } | |
115 } | |
116 } | |
117 | |
118 func save(_ gameType: GameType, with moc: NSManagedObjectContext) { | |
119 let playedGame = PlayedGame(context: moc) | |
120 | |
121 playedGame.type = gameType | |
122 playedGame.date = Date() | |
123 playedGame.score = Int32(userScore) | |
124 playedGame.correctAnswers = Array(correctAnswers.keys) | |
125 playedGame.wrongAnswers = Array(wrongAnswers.keys) | |
126 | |
127 do { | |
128 try moc.save() | |
129 } catch { | |
130 print("Couldn't save object to CoreData: \(error)") | |
131 } | |
132 } | |
133 | |
134 private func playSound(_ filename: String) { | |
135 let user = UserController() | |
136 | |
137 if user.data.sound { | |
138 guard let soundFileURL = Bundle.main.url(forResource: filename, withExtension: "wav") else { | |
139 fatalError("Sound file \(filename) couldn't be found") | |
140 } | |
141 | |
142 do { | |
143 try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient) | |
144 try AVAudioSession.sharedInstance().setActive(true) | |
145 } catch { | |
146 fatalError("Couldn't activate session") | |
147 } | |
148 | |
149 do { | |
150 player = try AVAudioPlayer(contentsOf: soundFileURL) | |
151 player?.play() | |
152 } catch { | |
153 fatalError("Couldn't play sound effect") | |
154 } | |
155 } | |
156 } | |
157 } |