-
-
Save petercv/d300d2d57071c5066e7ea26e4a280c49 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class AssetLoader { | |
init(pack: String? = nil) { | |
// ... | |
} | |
func load(_ name: String) -> UIImage { | |
return UIImage(systemName: "smiley")! | |
} | |
} | |
struct AssetLoaderEnvironmentKey: EnvironmentKey { | |
static var defaultValue: AssetLoader = AssetLoader() | |
} | |
extension EnvironmentValues { | |
var assetLoader: AssetLoader { | |
get { self[AssetLoaderEnvironmentKey.self] } | |
set { self[AssetLoaderEnvironmentKey.self] = newValue} | |
} | |
} | |
enum Screen { | |
case home | |
case level(level: Int) | |
} | |
class GameState: ObservableObject { | |
@Published var screen: Screen = .home | |
@Published var score: Int = 0 | |
@Published var highScore: Int = UserDefaults.standard.integer(forKey: "highScore") | |
var level: Int { | |
switch screen { | |
case .level(let level): | |
return level | |
default: | |
return 1 | |
} | |
} | |
} | |
struct GameProgressHiddenPreferenceKey: PreferenceKey { | |
typealias Value = Bool | |
static var defaultValue: Value = false | |
static func reduce(value: inout Value, nextValue: () -> Value) { | |
value = nextValue() || value | |
} | |
} | |
extension View { | |
func gameProgressHidden(_ value: Bool) -> some View { | |
preference(key: GameProgressHiddenPreferenceKey.self, value: value) | |
} | |
} | |
struct ScreenLink<Content>: View where Content: View { | |
@EnvironmentObject private var state: GameState | |
let screen: Screen | |
let content: Content | |
init(_ screen: Screen, @ViewBuilder content: () -> Content) { | |
self.screen = screen | |
self.content = content() | |
} | |
func go() { | |
withAnimation { | |
self.state.screen = self.screen | |
} | |
} | |
var body: some View { | |
Button(action: self.go) { | |
content | |
} | |
} | |
} | |
struct LevelView: View { | |
let level: Int | |
@EnvironmentObject private var state: GameState | |
@Environment(\.assetLoader) private var assetLoader | |
func quit() { | |
state.screen = .home | |
} | |
var body: some View { | |
VStack { | |
Text("Level \(level)") | |
Image(uiImage: assetLoader.load("level_\(level)")) | |
Button(action: self.quit) { | |
Text("Quit") | |
} | |
} | |
.gameProgressHidden(false) | |
} | |
} | |
struct HomeView: View { | |
@EnvironmentObject private var state: GameState | |
var body: some View { | |
VStack { | |
Text("Highscore: \(state.highScore)") | |
ScreenLink(.level(level: 1)) { | |
Text("Start") | |
} | |
} | |
.gameProgressHidden(true) | |
} | |
} | |
struct GameProgressView: View { | |
@EnvironmentObject private var state: GameState | |
var body: some View { | |
VStack { | |
Divider() | |
HStack { | |
Text("Level: \(state.level)") | |
Spacer() | |
Text("Score: \(state.score)") | |
} | |
.padding() | |
} | |
} | |
} | |
struct GameView: View { | |
@ObservedObject var state = GameState() | |
@State var showProgress = false | |
let assetLoader = AssetLoader(pack: UserDefaults.standard.object(forKey: "assetPack") as? String) | |
func viewForScreen(_ screen: Screen) -> some View { | |
switch screen { | |
case .home: | |
return AnyView(HomeView()) | |
case .level(let level): | |
return AnyView(LevelView(level: level)) | |
} | |
} | |
var body: some View { | |
VStack { | |
viewForScreen(state.screen) | |
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: Alignment.center) | |
if showProgress { | |
GameProgressView() | |
} | |
} | |
.environment(\.assetLoader, assetLoader) | |
.environmentObject(state) | |
.onPreferenceChange(GameProgressHiddenPreferenceKey.self) { value in | |
self.showProgress = !value | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment