Adds ability to select and use custom controller skins
This commit is contained in:
parent
2b0fe3ef20
commit
8cd3577cdc
@ -1 +1 @@
|
|||||||
Subproject commit b2af08a2db9e371b4fcfd8aa52b5106407af7c09
|
Subproject commit 35d634fdeec4f89da7dfecacb90188d688caa177
|
||||||
@ -46,6 +46,8 @@ class GameViewController: DeltaCore.GameViewController
|
|||||||
|
|
||||||
let game = self.game as? Game
|
let game = self.game as? Game
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.managedObjectContextDidChange(with:)), name: .NSManagedObjectContextObjectsDidChange, object: game?.managedObjectContext)
|
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.managedObjectContextDidChange(with:)), name: .NSManagedObjectContextObjectsDidChange, object: game?.managedObjectContext)
|
||||||
|
|
||||||
|
self.updateControllerSkin()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +112,7 @@ class GameViewController: DeltaCore.GameViewController
|
|||||||
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.updateControllers), name: .externalControllerDidConnect, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.updateControllers), name: .externalControllerDidConnect, object: nil)
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.updateControllers), name: .externalControllerDidDisconnect, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.updateControllers), name: .externalControllerDidDisconnect, object: nil)
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.didEnterBackground(with:)), name: .UIApplicationDidEnterBackground, object: UIApplication.shared)
|
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.didEnterBackground(with:)), name: .UIApplicationDidEnterBackground, object: UIApplication.shared)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.preferredControllerSkinDidUpdate(with:)), name: .preferredControllerSkinDidUpdate, object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit
|
deinit
|
||||||
@ -186,9 +189,26 @@ extension GameViewController
|
|||||||
self.sustainButtonsContentView.topAnchor.constraint(equalTo: self.gameView.topAnchor).isActive = true
|
self.sustainButtonsContentView.topAnchor.constraint(equalTo: self.gameView.topAnchor).isActive = true
|
||||||
self.sustainButtonsContentView.bottomAnchor.constraint(equalTo: self.gameView.bottomAnchor).isActive = true
|
self.sustainButtonsContentView.bottomAnchor.constraint(equalTo: self.gameView.bottomAnchor).isActive = true
|
||||||
|
|
||||||
|
self.updateControllerSkin()
|
||||||
self.updateControllers()
|
self.updateControllers()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
|
||||||
|
{
|
||||||
|
super.viewWillTransition(to: size, with: coordinator)
|
||||||
|
|
||||||
|
guard let game = self.game else { return }
|
||||||
|
|
||||||
|
var traits = DeltaCore.ControllerSkin.Traits.defaults(for: self.view)
|
||||||
|
traits.orientation = (size.width > size.height) ? .landscape : .portrait
|
||||||
|
|
||||||
|
let controllerSkin = Settings.preferredControllerSkin(for: game.type, traits: traits)
|
||||||
|
|
||||||
|
coordinator.animate(alongsideTransition: { (context) in
|
||||||
|
self.controllerView.controllerSkin = controllerSkin
|
||||||
|
}, completion: nil)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Segues
|
// MARK: - Segues
|
||||||
/// KVO
|
/// KVO
|
||||||
|
|
||||||
@ -360,6 +380,16 @@ private extension GameViewController
|
|||||||
|
|
||||||
self.view.setNeedsLayout()
|
self.view.setNeedsLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateControllerSkin()
|
||||||
|
{
|
||||||
|
guard let game = self.game else { return }
|
||||||
|
|
||||||
|
let traits = DeltaCore.ControllerSkin.Traits.defaults(for: self.view)
|
||||||
|
|
||||||
|
let controllerSkin = Settings.preferredControllerSkin(for: game.type, traits: traits)
|
||||||
|
self.controllerView.controllerSkin = controllerSkin
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//MARK: - Save States -
|
//MARK: - Save States -
|
||||||
@ -731,4 +761,18 @@ private extension GameViewController
|
|||||||
self.game = nil
|
self.game = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc func preferredControllerSkinDidUpdate(with notification: Notification)
|
||||||
|
{
|
||||||
|
guard
|
||||||
|
let gameType = notification.userInfo?[Settings.NotificationUserInfoKey.gameType.rawValue] as? GameType,
|
||||||
|
let traits = notification.userInfo?[Settings.NotificationUserInfoKey.traits.rawValue] as? DeltaCore.ControllerSkin.Traits
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
let currentTraits = DeltaCore.ControllerSkin.Traits.defaults(for: self.view)
|
||||||
|
if gameType == self.game?.type && traits == currentTraits
|
||||||
|
{
|
||||||
|
self.updateControllerSkin()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -178,6 +178,14 @@ extension ControllerSkinsViewController: UITableViewDataSourcePrefetching
|
|||||||
|
|
||||||
extension ControllerSkinsViewController
|
extension ControllerSkinsViewController
|
||||||
{
|
{
|
||||||
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
|
||||||
|
{
|
||||||
|
let controllerSkin = self.dataSource.fetchedResultsController.object(at: indexPath)
|
||||||
|
Settings.setPreferredControllerSkin(controllerSkin, for: self.gameType, traits: self.traits)
|
||||||
|
|
||||||
|
_ = self.navigationController?.popViewController(animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
|
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
|
||||||
{
|
{
|
||||||
let controllerSkin = self.dataSource.fetchedResultsController.object(at: indexPath)
|
let controllerSkin = self.dataSource.fetchedResultsController.object(at: indexPath)
|
||||||
|
|||||||
@ -102,12 +102,13 @@ private extension GameTypeControllerSkinsViewController
|
|||||||
{
|
{
|
||||||
func updateControllerSkins()
|
func updateControllerSkins()
|
||||||
{
|
{
|
||||||
let controllerSkin = DeltaCore.ControllerSkin.standardControllerSkin(for: self.gameType)
|
|
||||||
|
|
||||||
let portraitTraits = DeltaCore.ControllerSkin.Traits(deviceType: .iphone, displayMode: DeltaCore.ControllerSkin.DisplayMode.fullScreen, orientation: .portrait)
|
let portraitTraits = DeltaCore.ControllerSkin.Traits(deviceType: .iphone, displayMode: DeltaCore.ControllerSkin.DisplayMode.fullScreen, orientation: .portrait)
|
||||||
self.portraitImageView.image = controllerSkin?.image(for: portraitTraits, preferredSize: UIScreen.main.defaultControllerSkinSize)
|
|
||||||
|
|
||||||
let landscapeTraits = DeltaCore.ControllerSkin.Traits(deviceType: .iphone, displayMode: DeltaCore.ControllerSkin.DisplayMode.fullScreen, orientation: .landscape)
|
let landscapeTraits = DeltaCore.ControllerSkin.Traits(deviceType: .iphone, displayMode: DeltaCore.ControllerSkin.DisplayMode.fullScreen, orientation: .landscape)
|
||||||
self.landscapeImageView.image = controllerSkin?.image(for: landscapeTraits, preferredSize: UIScreen.main.defaultControllerSkinSize)
|
|
||||||
|
let portraitControllerSkin = Settings.preferredControllerSkin(for: self.gameType, traits: portraitTraits)
|
||||||
|
let landscapeControllerSkin = Settings.preferredControllerSkin(for: self.gameType, traits: landscapeTraits)
|
||||||
|
|
||||||
|
self.portraitImageView.image = portraitControllerSkin?.image(for: portraitTraits, preferredSize: UIScreen.main.defaultControllerSkinSize)
|
||||||
|
self.landscapeImageView.image = landscapeControllerSkin?.image(for: landscapeTraits, preferredSize: UIScreen.main.defaultControllerSkinSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,110 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import DeltaCore
|
||||||
|
import SNESDeltaCore
|
||||||
|
import GBADeltaCore
|
||||||
|
|
||||||
|
import Roxas
|
||||||
|
|
||||||
|
extension Notification.Name
|
||||||
|
{
|
||||||
|
static let preferredControllerSkinDidUpdate = Notification.Name("PreferredControllerSkinDidUpdateNotification")
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Settings
|
||||||
|
{
|
||||||
|
enum NotificationUserInfoKey: String
|
||||||
|
{
|
||||||
|
case gameType
|
||||||
|
case traits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Settings
|
struct Settings
|
||||||
{
|
{
|
||||||
/// Controllers
|
/// Controllers
|
||||||
static var localControllerPlayerIndex: Int? = 0
|
static var localControllerPlayerIndex: Int? = 0
|
||||||
|
|
||||||
|
static func preferredControllerSkin(for gameType: GameType, traits: DeltaCore.ControllerSkin.Traits) -> ControllerSkin?
|
||||||
|
{
|
||||||
|
guard let userDefaultsKey = self.preferredControllerSkinKey(for: gameType, traits: traits) else { return nil }
|
||||||
|
|
||||||
|
let identifier = UserDefaults.standard.string(forKey: userDefaultsKey)
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Attempt to load preferred controller skin if it exists
|
||||||
|
|
||||||
|
let fetchRequest: NSFetchRequest<ControllerSkin> = ControllerSkin.fetchRequest()
|
||||||
|
|
||||||
|
if let identifier = identifier
|
||||||
|
{
|
||||||
|
fetchRequest.predicate = NSPredicate(format: "%K == %@ AND %K == %@", #keyPath(ControllerSkin.gameType), gameType.rawValue, #keyPath(ControllerSkin.identifier), identifier)
|
||||||
|
|
||||||
|
if let controllerSkin = try DatabaseManager.shared.viewContext.fetch(fetchRequest).first
|
||||||
|
{
|
||||||
|
return controllerSkin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Controller skin doesn't exist, so fall back to standard controller skin
|
||||||
|
|
||||||
|
fetchRequest.predicate = NSPredicate(format: "%K == %@ AND %K == YES", #keyPath(ControllerSkin.gameType), gameType.rawValue, #keyPath(ControllerSkin.isStandard))
|
||||||
|
|
||||||
|
if let controllerSkin = try DatabaseManager.shared.viewContext.fetch(fetchRequest).first
|
||||||
|
{
|
||||||
|
Settings.setPreferredControllerSkin(controllerSkin, for: gameType, traits: traits)
|
||||||
|
return controllerSkin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
static func setPreferredControllerSkin(_ controllerSkin: ControllerSkin, for gameType: GameType, traits: DeltaCore.ControllerSkin.Traits)
|
||||||
|
{
|
||||||
|
guard let userDefaultKey = self.preferredControllerSkinKey(for: gameType, traits: traits) else { return }
|
||||||
|
UserDefaults.standard.set(controllerSkin.identifier, forKey: userDefaultKey)
|
||||||
|
|
||||||
|
NotificationCenter.default.post(name: .preferredControllerSkinDidUpdate, object: controllerSkin, userInfo: [NotificationUserInfoKey.gameType.rawValue: gameType, NotificationUserInfoKey.traits.rawValue: traits])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension Settings
|
||||||
|
{
|
||||||
|
static func preferredControllerSkinKey(for gameType: GameType, traits: DeltaCore.ControllerSkin.Traits) -> String?
|
||||||
|
{
|
||||||
|
let systemName: String
|
||||||
|
|
||||||
|
switch gameType
|
||||||
|
{
|
||||||
|
case GameType.snes: systemName = "snes"
|
||||||
|
case GameType.gba: systemName = "gba"
|
||||||
|
default: return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let orientation: String
|
||||||
|
|
||||||
|
switch traits.orientation
|
||||||
|
{
|
||||||
|
case .portrait: orientation = "portrait"
|
||||||
|
case .landscape: orientation = "landscape"
|
||||||
|
}
|
||||||
|
|
||||||
|
let displayMode: String
|
||||||
|
|
||||||
|
switch traits.displayMode
|
||||||
|
{
|
||||||
|
case .fullScreen: displayMode = "fullscreen"
|
||||||
|
case .splitView: displayMode = "splitview"
|
||||||
|
}
|
||||||
|
|
||||||
|
let key = systemName + "-" + orientation + "-" + displayMode + "-controller"
|
||||||
|
return key
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user