From 8b7633fcb62d6cd0e873e8cc89c0646fbc106468 Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Sat, 25 Apr 2020 16:24:25 +0100 Subject: [PATCH] Added save/restore state --- Source/Engine/Actor.swift | 2 +- Source/Engine/Animation.swift | 2 +- Source/Engine/Color.swift | 2 +- Source/Engine/Door.swift | 4 ++-- Source/Engine/Effect.swift | 4 ++-- Source/Engine/Game.swift | 22 ++++++++++++++++++++++ Source/Engine/Monster.swift | 2 +- Source/Engine/Pickup.swift | 2 +- Source/Engine/Player.swift | 2 +- Source/Engine/Sounds.swift | 4 ++-- Source/Engine/Switch.swift | 4 ++-- Source/Engine/Texture.swift | 2 +- Source/Engine/Thing.swift | 2 +- Source/Engine/Tile.swift | 2 +- Source/Engine/Tilemap.swift | 2 +- Source/Engine/Vector.swift | 2 +- Source/Engine/Weapon.swift | 2 +- Source/Engine/World.swift | 2 +- Source/Rampage/ViewController.swift | 26 ++++++++++++++++++++++++++ 19 files changed, 69 insertions(+), 21 deletions(-) diff --git a/Source/Engine/Actor.swift b/Source/Engine/Actor.swift index 217932c..3c4766b 100644 --- a/Source/Engine/Actor.swift +++ b/Source/Engine/Actor.swift @@ -6,7 +6,7 @@ // Copyright © 2019 Nick Lockwood. All rights reserved. // -public protocol Actor { +public protocol Actor: Codable { var radius: Double { get } var position: Vector { get set } var isDead: Bool { get } diff --git a/Source/Engine/Animation.swift b/Source/Engine/Animation.swift index d9fa445..41257a0 100644 --- a/Source/Engine/Animation.swift +++ b/Source/Engine/Animation.swift @@ -6,7 +6,7 @@ // Copyright © 2019 Nick Lockwood. All rights reserved. // -public struct Animation { +public struct Animation: Codable { public let frames: [Texture] public let duration: Double public var time: Double = 0 diff --git a/Source/Engine/Color.swift b/Source/Engine/Color.swift index 6081eee..a5eaf19 100644 --- a/Source/Engine/Color.swift +++ b/Source/Engine/Color.swift @@ -6,7 +6,7 @@ // Copyright © 2019 Nick Lockwood. All rights reserved. // -public struct Color { +public struct Color: Codable { public var r, g, b, a: UInt8 public init(r: UInt8, g: UInt8, b: UInt8, a: UInt8 = 255) { diff --git a/Source/Engine/Door.swift b/Source/Engine/Door.swift index de2848f..1d978b0 100644 --- a/Source/Engine/Door.swift +++ b/Source/Engine/Door.swift @@ -6,14 +6,14 @@ // Copyright © 2019 Nick Lockwood. All rights reserved. // -public enum DoorState { +public enum DoorState: Int, Codable { case closed case opening case open case closing } -public struct Door { +public struct Door: Codable { public let duration: Double = 0.5 public let closeDelay: Double = 3 public let position: Vector diff --git a/Source/Engine/Effect.swift b/Source/Engine/Effect.swift index 8d67431..3fd19e2 100644 --- a/Source/Engine/Effect.swift +++ b/Source/Engine/Effect.swift @@ -6,13 +6,13 @@ // Copyright © 2019 Nick Lockwood. All rights reserved. // -public enum EffectType { +public enum EffectType: Int, Codable { case fadeIn case fadeOut case fizzleOut } -public struct Effect { +public struct Effect: Codable { public let type: EffectType public let color: Color public let duration: Double diff --git a/Source/Engine/Game.swift b/Source/Engine/Game.swift index 3a12b7b..6e23584 100644 --- a/Source/Engine/Game.swift +++ b/Source/Engine/Game.swift @@ -17,6 +17,10 @@ public enum GameState { case playing } +public struct SavedGame: Codable { + let world: World? +} + public struct Game { public weak var delegate: GameDelegate? public let levels: [Tilemap] @@ -39,6 +43,24 @@ public extension Game { return HUD(player: world.player, font: font) } + func save() -> SavedGame { + switch state { + case .playing: + return SavedGame(world: world) + default: + return SavedGame(world: nil) + } + } + + mutating func load(_ savedGame: SavedGame) { + guard let world = savedGame.world else { + self.state = .title + return + } + self.state = .playing + self.world = world + } + mutating func update(timeStep: Double, input: Input) { guard let delegate = delegate else { return diff --git a/Source/Engine/Monster.swift b/Source/Engine/Monster.swift index ffaf759..6d1ec16 100644 --- a/Source/Engine/Monster.swift +++ b/Source/Engine/Monster.swift @@ -6,7 +6,7 @@ // Copyright © 2019 Nick Lockwood. All rights reserved. // -public enum MonsterState { +public enum MonsterState: Int, Codable { case idle case chasing case blocked diff --git a/Source/Engine/Pickup.swift b/Source/Engine/Pickup.swift index abcc39f..afdda8f 100644 --- a/Source/Engine/Pickup.swift +++ b/Source/Engine/Pickup.swift @@ -6,7 +6,7 @@ // Copyright © 2020 Nick Lockwood. All rights reserved. // -public enum PickupType { +public enum PickupType: Int, Codable { case medkit case shotgun } diff --git a/Source/Engine/Player.swift b/Source/Engine/Player.swift index 4a12009..fa4064e 100644 --- a/Source/Engine/Player.swift +++ b/Source/Engine/Player.swift @@ -6,7 +6,7 @@ // Copyright © 2019 Nick Lockwood. All rights reserved. // -public enum PlayerState { +public enum PlayerState: Int, Codable { case idle case firing } diff --git a/Source/Engine/Sounds.swift b/Source/Engine/Sounds.swift index 35ed47f..4056cdf 100644 --- a/Source/Engine/Sounds.swift +++ b/Source/Engine/Sounds.swift @@ -6,7 +6,7 @@ // Copyright © 2019 Nick Lockwood. All rights reserved. // -public enum SoundName: String, CaseIterable { +public enum SoundName: String, CaseIterable, Codable { case pistolFire case shotgunFire case shotgunPickup @@ -25,7 +25,7 @@ public enum SoundName: String, CaseIterable { case medkit } -public struct Sound { +public struct Sound: Codable { public let name: SoundName? public let channel: Int? public let volume: Double diff --git a/Source/Engine/Switch.swift b/Source/Engine/Switch.swift index fd98774..048b30b 100644 --- a/Source/Engine/Switch.swift +++ b/Source/Engine/Switch.swift @@ -6,12 +6,12 @@ // Copyright © 2019 Nick Lockwood. All rights reserved. // -public enum SwitchState { +public enum SwitchState: Int, Codable { case off case on } -public struct Switch { +public struct Switch: Codable { public let position: Vector public var state: SwitchState = .off public var animation: Animation = .switchOff diff --git a/Source/Engine/Texture.swift b/Source/Engine/Texture.swift index a04114f..95157fa 100644 --- a/Source/Engine/Texture.swift +++ b/Source/Engine/Texture.swift @@ -6,7 +6,7 @@ // Copyright © 2019 Nick Lockwood. All rights reserved. // -public enum Texture: String, CaseIterable, Decodable { +public enum Texture: String, CaseIterable, Codable { case wall, wall2 case crackWall, crackWall2 case slimeWall, slimeWall2 diff --git a/Source/Engine/Thing.swift b/Source/Engine/Thing.swift index fb3908c..741ccb8 100644 --- a/Source/Engine/Thing.swift +++ b/Source/Engine/Thing.swift @@ -6,7 +6,7 @@ // Copyright © 2019 Nick Lockwood. All rights reserved. // -public enum Thing: Int, Decodable { +public enum Thing: Int, Codable { case nothing case player case monster diff --git a/Source/Engine/Tile.swift b/Source/Engine/Tile.swift index 23a04f2..6fe86c5 100644 --- a/Source/Engine/Tile.swift +++ b/Source/Engine/Tile.swift @@ -6,7 +6,7 @@ // Copyright © 2019 Nick Lockwood. All rights reserved. // -public enum Tile: Int, Decodable { +public enum Tile: Int, Codable { case floor case wall case crackWall diff --git a/Source/Engine/Tilemap.swift b/Source/Engine/Tilemap.swift index c50cf46..030e310 100644 --- a/Source/Engine/Tilemap.swift +++ b/Source/Engine/Tilemap.swift @@ -12,7 +12,7 @@ public struct MapData: Decodable { fileprivate let width: Int } -public struct Tilemap { +public struct Tilemap: Codable { private(set) var tiles: [Tile] public let things: [Thing] public let width: Int diff --git a/Source/Engine/Vector.swift b/Source/Engine/Vector.swift index f9494b7..deee451 100644 --- a/Source/Engine/Vector.swift +++ b/Source/Engine/Vector.swift @@ -6,7 +6,7 @@ // Copyright © 2019 Nick Lockwood. All rights reserved. // -public struct Vector: Hashable { +public struct Vector: Hashable, Codable { public var x, y: Double public init(x: Double, y: Double) { diff --git a/Source/Engine/Weapon.swift b/Source/Engine/Weapon.swift index 878e7fe..814c87b 100644 --- a/Source/Engine/Weapon.swift +++ b/Source/Engine/Weapon.swift @@ -6,7 +6,7 @@ // Copyright © 2020 Nick Lockwood. All rights reserved. // -public enum Weapon: Int { +public enum Weapon: Int, Codable { case pistol case shotgun } diff --git a/Source/Engine/World.swift b/Source/Engine/World.swift index cfcc6d6..569c387 100644 --- a/Source/Engine/World.swift +++ b/Source/Engine/World.swift @@ -11,7 +11,7 @@ public enum WorldAction { case playSounds([Sound]) } -public struct World { +public struct World: Codable { public private(set) var map: Tilemap public private(set) var doors: [Door] public private(set) var pushwalls: [Pushwall] diff --git a/Source/Rampage/ViewController.swift b/Source/Rampage/ViewController.swift index 232d38f..04e02fc 100644 --- a/Source/Rampage/ViewController.swift +++ b/Source/Rampage/ViewController.swift @@ -14,6 +14,11 @@ private let joystickRadius: Double = 40 private let maximumTimeStep: Double = 1 / 20 private let worldTimeStep: Double = 1 / 120 +private let savedGameURL: URL = { + let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] + return documentsURL.appendingPathComponent("quicksave.plist") +}() + public func loadLevels() -> [Tilemap] { let jsonURL = Bundle.main.url(forResource: "Levels", withExtension: "json")! let jsonData = try! Data(contentsOf: jsonURL) @@ -77,6 +82,15 @@ class ViewController: UIViewController { tapGesture.delegate = self game.delegate = self + + try? restoreState() + NotificationCenter.default.addObserver( + forName: UIApplication.willResignActiveNotification, + object: nil, + queue: .main + ) { _ in + try? self.saveState() + } } override var prefersStatusBarHidden: Bool { @@ -148,6 +162,18 @@ class ViewController: UIViewController { imageView.backgroundColor = .black imageView.layer.magnificationFilter = .nearest } + + func saveState() throws { + let savedGame = game.save() + let data = try PropertyListEncoder().encode(savedGame) + try data.write(to: savedGameURL, options: .atomic) + } + + func restoreState() throws { + let data = try Data(contentsOf: savedGameURL) + let savedGame = try PropertyListDecoder().decode(SavedGame.self, from: data) + game.load(savedGame) + } } extension ViewController: UIGestureRecognizerDelegate {