diff --git a/App/Core/Nodes/AeonCameraBodyNode.swift b/App/Core/Nodes/AeonCameraBodyNode.swift index a713f65..f39f96b 100644 --- a/App/Core/Nodes/AeonCameraBodyNode.swift +++ b/App/Core/Nodes/AeonCameraBodyNode.swift @@ -50,7 +50,7 @@ class AeonCameraBodyNode: SKNode, Updatable { @objc func pickRandomTarget() { if let scene = scene as? AeonTankScene { if let randomNode = scene.creatureNodes.randomElement() { - Log.debug("Picked new target for camera body: \(randomNode.position)") + Log.debug("🤳 Picked new target for camera body: \(randomNode.position)") currentTarget = randomNode.position targetingTimer?.invalidate() diff --git a/App/Core/Nodes/AeonCameraNode.swift b/App/Core/Nodes/AeonCameraNode.swift index 5c21245..f9a6e15 100644 --- a/App/Core/Nodes/AeonCameraNode.swift +++ b/App/Core/Nodes/AeonCameraNode.swift @@ -19,7 +19,6 @@ protocol AeonCameraDelegate: AnyObject { class AeonCameraNode: SKCameraNode, Updatable, AeonCameraDelegate { var body: AeonCameraBodyNode = AeonCameraBodyNode() var selectedNode: SKNode? - var autoCameraIsEnabled: Bool = false let cameraMoveDuration: TimeInterval = 0.25 var lastUpdateTime: TimeInterval = 0 var zoomTimer: Timer? @@ -38,6 +37,8 @@ class AeonCameraNode: SKCameraNode, Updatable, AeonCameraDelegate { func resetCamera() { Log.debug("📷 Camera resetting.") + disableAutoCamera() + selectedNode = nil zoom(.zoomOut) } @@ -54,10 +55,12 @@ class AeonCameraNode: SKCameraNode, Updatable, AeonCameraDelegate { selectedNode(body) body.pickRandomTarget() + changeCameraZoomLevel() } func disableAutoCamera() { Log.debug("📷 Auto camera stopped.") + zoomTimer?.invalidate() } func creatureSelected(_ creature: AeonCreatureNode) { @@ -78,8 +81,6 @@ class AeonCameraNode: SKCameraNode, Updatable, AeonCameraDelegate { selectedNode = node if selectedNode is AeonCreatureNode { zoom(.fullZoom, speed: 1) - } else { - changeCameraZoomLevel() } } } @@ -120,7 +121,7 @@ class AeonCameraNode: SKCameraNode, Updatable, AeonCameraDelegate { } @objc func changeCameraZoomLevel() { - Log.debug("📷 Camera auto-zoom updated.") + Log.debug("🤳 Camera auto-zoom updated.") zoomTimer?.invalidate() diff --git a/App/Core/Scenes/AeonTankScene.swift b/App/Core/Scenes/AeonTankScene.swift index 347aff5..48ca08e 100644 --- a/App/Core/Scenes/AeonTankScene.swift +++ b/App/Core/Scenes/AeonTankScene.swift @@ -115,7 +115,7 @@ class AeonTankScene: SKScene { if let creature = node as? AeonCreatureNode { creatureNodes.remove(object: creature) if let selectedCreature = cameraNode.selectedNode as? AeonCreatureNode, selectedCreature == creature { - cameraNode.deselectNode() + interfaceDelegate?.creatureDeselected() } } else if let food = node as? AeonFoodNode { foodNodes.remove(object: food) @@ -140,9 +140,9 @@ class AeonTankScene: SKScene { lastBubbleTime = currentTime } - // Log.debug("Food Spawner: Last Spawn \(currentTime - lastFoodTime) - Current Food: \(foodNodes.count) - Max Food: \(foodMaxAmount)") if (currentTime - lastFoodTime) >= 2, foodNodes.count < foodMaxAmount { + Log.debug("🍞 Food Spawner: Last Spawn \(Int(currentTime - lastFoodTime))s ago - Current: \(foodNodes.count) - Max: \(foodMaxAmount)") addFoodPelletToScene() lastFoodTime = currentTime } diff --git a/App/Core/Utilities/Logging.swift b/App/Core/Utilities/Logging.swift index 1de7329..279cd18 100644 --- a/App/Core/Utilities/Logging.swift +++ b/App/Core/Utilities/Logging.swift @@ -79,7 +79,7 @@ open class Log { let components: [String] = fileName.components(separatedBy: "/") let objectName = components.last ?? "Unknown Object" let levelString = Log.useEmoji ? level.emoji : "|" + level.name.uppercased() + "|" - let logString = "\(levelString) [\(date)] \(objectName) line \(line): \(object())" + let logString = "\(levelString) [\(date)]: \(object()) [\(objectName): \(line)]" print(logString) handler?(level, logString) } diff --git a/App/Core/Views/AeonViewController.swift b/App/Core/Views/AeonViewController.swift index 8b835c0..ec09155 100644 --- a/App/Core/Views/AeonViewController.swift +++ b/App/Core/Views/AeonViewController.swift @@ -90,7 +90,7 @@ class AeonViewController: UIViewController, AeonTankInterfaceDelegate { override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) guard let scene = self.scene else { return } - viewModel?.saveTank(scene) + viewModel?.saveTank(scene, userInitated: false) } #if os(iOS) @@ -112,13 +112,11 @@ class AeonViewController: UIViewController, AeonTankInterfaceDelegate { @objc func newTank() { scene = viewModel?.createNewTank(size: view.bounds.size, device: deviceType) skView?.presentScene(scene) - viewModel?.activityOccurred() } @objc func saveTank() { guard let scene = scene else { return } - viewModel?.saveTank(scene) - viewModel?.activityOccurred() + viewModel?.saveTank(scene, userInitated: true) } @objc func loadTank() { @@ -126,7 +124,6 @@ class AeonViewController: UIViewController, AeonTankInterfaceDelegate { self.scene = scene self.skView!.presentScene(scene) }) - viewModel?.activityOccurred() } @objc func toggleFavoriteForSelectedCreature() { @@ -138,7 +135,6 @@ class AeonViewController: UIViewController, AeonTankInterfaceDelegate { viewModel?.deleteCreature(creature) } updateFavoriteButtonLabel() - viewModel?.activityOccurred() } } @@ -172,7 +168,6 @@ class AeonViewController: UIViewController, AeonTankInterfaceDelegate { self.viewModel?.renameCreature(creature, firstName: firstName, lastName: lastName) Log.info("Renamed creature to \(firstName) \(lastName).") - self.viewModel?.activityOccurred() } actionSheet.addAction(okButton) @@ -213,7 +208,6 @@ class AeonViewController: UIViewController, AeonTankInterfaceDelegate { let selected = mateArray.randomElement()! viewModel?.creatureSelected(selected) } - viewModel?.activityOccurred() } @objc func deselectCreatureOrResetCamera() { @@ -222,7 +216,6 @@ class AeonViewController: UIViewController, AeonTankInterfaceDelegate { } else { viewModel?.resetCamera() } - viewModel?.activityOccurred() } #endif @@ -253,11 +246,6 @@ class AeonViewController: UIViewController, AeonTankInterfaceDelegate { DispatchQueue.main.async { self.updateSelectedCreatureDetails(creature) self.showDetailsIfNeeded() - #if os(iOS) - // Since iOS touch events occur in the scene, - // we need to tell the view model activity occurred here. - self.viewModel?.activityOccurred() - #endif } } @@ -265,11 +253,6 @@ class AeonViewController: UIViewController, AeonTankInterfaceDelegate { selectedCreature = nil DispatchQueue.main.async { self.hideDetailsIfNeeded() - #if os(iOS) - // Since iOS touch events occur in the scene, - // we need to tell the view model activity occurred here. - self.viewModel?.activityOccurred() - #endif } } @@ -313,7 +296,7 @@ class AeonViewController: UIViewController, AeonTankInterfaceDelegate { private func animateTransitionIfNeeded(to state: UIState, duration: TimeInterval) { guard runningAnimators.isEmpty else { return } - Log.debug("Animating UI to state \(state)") + Log.debug("🖥 Animating UI to state \(state)") let transitionAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1) { switch state { diff --git a/App/Core/Views/AeonViewModel.swift b/App/Core/Views/AeonViewModel.swift index d2839fa..e459709 100644 --- a/App/Core/Views/AeonViewModel.swift +++ b/App/Core/Views/AeonViewModel.swift @@ -21,11 +21,7 @@ class AeonViewModel { weak var camera: AeonCameraNode? weak var selectedCreature: AeonCreatureNode? - var autoCameraRunning: Bool = false { - didSet { - Log.debug("Auto Camera Running Toggled to \(autoCameraRunning)") - } - } + var autoCameraRunning: Bool = false var autosaveTimer: Timer? var lastUserActivityTimeout: TimeInterval = 10 // default should be 120? @@ -47,39 +43,29 @@ class AeonViewModel { @objc private func autosave() { guard let scene = scene else { return } - Log.info("Running auto-save...") + Log.info("💽 Running auto-save...") DispatchQueue.main.async { - self.saveTank(scene) + self.saveTank(scene, userInitated: false) } } func activityOccurred() { - Log.info("User activity occurred.") + Log.info("⏰ User activity occurred.") if let idleTimer = idleTimer { idleTimer.invalidate() } idleTimer = Timer.scheduledTimer(timeInterval: lastUserActivityTimeout, target: self, selector: #selector(startAutoCamera), userInfo: nil, repeats: false) - - if autoCameraRunning { - stopAutoCamera() - } } @objc private func startAutoCamera() { if let currentState = view?.currentState, currentState != .details { view?.hideAllMenusIfNeeded() - camera?.enableAutoCamera() - autoCameraRunning = true + self.enableAutoCamera() } } - private func stopAutoCamera() { - autoCameraRunning = false - camera?.disableAutoCamera() - } - private func createScene(size: CGSize, device: DeviceType) -> AeonTankScene { let newScene = AeonTankScene(size: size) newScene.tankSettings = getTankSettings(for: device) @@ -89,6 +75,7 @@ class AeonViewModel { } func createNewTank(size: CGSize, device: DeviceType) -> AeonTankScene { + activityOccurred() let newScene = createScene(size: size, device: device) CoreDataStore.standard.getCreatures { creatures in newScene.loadCreaturesIntoScene(creatures) @@ -100,8 +87,9 @@ class AeonViewModel { } func loadTank(size: CGSize, device: DeviceType, completion: @escaping (AeonTankScene) -> Void) { + activityOccurred() Tank.getAll { tanks in - Log.info("Number of tanks in storage: \(tanks.count)") + Log.info("💽 Number of tanks in storage: \(tanks.count)") if let tank = tanks.last { let newScene = self.createScene(size: size, device: device) tank.restore(to: newScene) @@ -113,22 +101,29 @@ class AeonViewModel { } } - func saveTank(_ scene: AeonTankScene) { + func saveTank(_ scene: AeonTankScene, userInitated: Bool) { + let tankStruct = Tank.from(scene) tankStruct.save() + if userInitated { + activityOccurred() + } } func saveCreature(_ creature: AeonCreatureNode) { + activityOccurred() let creatureStruct = Creature.from(creature) creatureStruct.save() } func deleteCreature(_ creature: AeonCreatureNode) { + activityOccurred() let creatureStruct = Creature.from(creature) creatureStruct.delete() } func renameCreature(_ creature: AeonCreatureNode, firstName: String, lastName: String) { + activityOccurred() creature.firstName = firstName creature.lastName = lastName creature.fullName = "\(firstName) \(lastName)" @@ -166,11 +161,11 @@ class AeonViewModel { ) default: tankSettings = TankSettings( - foodMaxAmount: 15, + foodMaxAmount: 10, foodHealthRestorationBaseValue: 120, foodSpawnRate: 2, - creatureInitialAmount: 20, - creatureMinimumAmount: 10, + creatureInitialAmount: 15, + creatureMinimumAmount: 5, creatureSpawnRate: 5, creatureBirthSuccessRate: 0.10, backgroundParticleBirthrate: 40, @@ -189,26 +184,27 @@ extension AeonViewModel: AeonTankInterfaceDelegate { func enableAutoCamera() { view?.enableAutoCamera() camera?.enableAutoCamera() + autoCameraRunning = true } func disableAutoCamera() { view?.disableAutoCamera() camera?.disableAutoCamera() + autoCameraRunning = false } func creatureDeselected() { - if selectedCreature != nil { - Log.debug("Creature De-Selected") - view?.creatureDeselected() - camera?.creatureDeselected() - selectedCreature?.hideSelectionRing() - selectedCreature = nil - } + Log.debug("👾 Creature De-Selected") + view?.creatureDeselected() + camera?.creatureDeselected() + selectedCreature?.hideSelectionRing() + selectedCreature = nil + activityOccurred() } func creatureSelected(_ creature: AeonCreatureNode) { if selectedCreature != creature { - Log.debug("Creature Selected") + Log.debug("👾 Creature Selected") if selectedCreature != creature { selectedCreature?.hideSelectionRing() } @@ -216,17 +212,20 @@ extension AeonViewModel: AeonTankInterfaceDelegate { creature.displaySelectionRing(withColor: .aeonBrightYellow) view?.creatureSelected(creature) camera?.creatureSelected(creature) + activityOccurred() } } func resetCamera() { - Log.debug("Reset Camera") + Log.debug("📷 Reset Camera") view?.resetCamera() camera?.resetCamera() + autoCameraRunning = false if selectedCreature != nil { selectedCreature?.hideSelectionRing() selectedCreature = nil } + activityOccurred() } func updatePopulation(_ population: Int) {