2016-08-20 7 views
0

В настоящее время я разрабатываю игру с использованием Swift 3, SpriteKit и Xcode 8 beta. Я пытаюсь реализовать статические 3D Touch Quick Actions с главного экрана через info.plist. В настоящее время действия отображаются на главном экране, но не идут в нужное место SKScene - переход на начальную сцену или последнюю открытую сцену (если приложение все еще открыто), что означает, что сцена не изменяется. Я пробовал различные способы настройки сцены внутри оператора switch, но ни один из них не работает должным образом для представления SKScene, поскольку строка window!.rootViewController?.present(gameViewController, animated: true, completion: nil) работает только с UIViewController.3D Touch Быстрые действия не работают должным образом с помощью SpriteKit

Различные части этого кода взяты из различных учебных пособий, но я уверен, что через мое исследование, что сломанная часть представляет собой сцену (если я ошибаюсь), потому что она не должна даже загружать сцену, если часть сломана.

Есть ли способы представить SKScene из AppDelegate или установить начальную сцену на основе инструкции switch?

AppDelegate

import UIKit 
import SpriteKit 

@UIApplicationMain 
class AppDelegate: UIResponder, UIApplicationDelegate { 

    var window: UIWindow? 


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 
     // Override point for customization after application launch. 

     guard !handledShortcutItemPress(forLaunchOptions: launchOptions) else { return false } // ADD THIS LINE 

     return true 
    } 
} 

extension AppDelegate: ShortcutItem { 

    /// Perform action for shortcut item. This gets called when app is active 
    func application(_ application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) { 
     completionHandler(handledShortcutItemPress(forItem: shortcutItem)) 

    } 
} 

extension AppDelegate: ShortcutItemDelegate { 

    func shortcutItem1Pressed() { 

     Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(loadShopScene), userInfo: nil, repeats: false) 
    } 

    @objc private func loadShopScene() { 
     let scene = ShopScene(size: CGSize(width: 768, height: 1024)) 
     loadScene(scene: scene, view: window?.rootViewController?.view) 
    } 

    func shortcutItem2Pressed() { 
     Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(loadGameScene), userInfo: nil, repeats: false) 
    } 

    @objc private func loadGameScene() { 
     let scene = GameScene(size: CGSize(width: 768, height: 1024)) 
     loadScene(scene: scene, view: window?.rootViewController?.view) 
    } 

    func shortcutItem3Pressed() { 
     // do something else 
    } 

    func shortcutItem4Pressed() { 
     // do something else 
    } 

    func loadScene(scene: SKScene?, view: UIView?, scaleMode: SKSceneScaleMode = .aspectFill) { 
     guard let scene = scene else { return } 
     guard let skView = view as? SKView else { return } 

     skView.ignoresSiblingOrder = true 
     #if os(iOS) 
      skView.isMultipleTouchEnabled = true 
     #endif 
     scene.scaleMode = scaleMode 
     skView.presentScene(scene) 
    } 
} 

3DTouchQuickActions.swift

import Foundation 
import UIKit 

/// Shortcut item delegate 
protocol ShortcutItemDelegate: class { 
    func shortcutItem1Pressed() 
    func shortcutItem2Pressed() 
    func shortcutItem3Pressed() 
    func shortcutItem4Pressed() 
} 

/// Shortcut item identifier 
enum ShortcutItemIdentifier: String { 
    case first // I use swift 3 small letters so you have to change your spelling in the info.plist 
    case second 
    case third 
    case fourth 

    init?(fullType: String) { 
     guard let last = fullType.components(separatedBy: ".").last else { return nil } 
     self.init(rawValue: last) 
    } 

    public var type: String { 
     return Bundle.main.bundleIdentifier! + ".\(self.rawValue)" 
    } 
} 

/// Shortcut item protocol 
protocol ShortcutItem { } 
extension ShortcutItem { 

    // MARK: - Properties 

    /// Delegate 
    private weak var delegate: ShortcutItemDelegate? { 
     return self as? ShortcutItemDelegate 
    } 

    // MARK: - Methods 

    /// Handled shortcut item press first app launch (needed to avoid double presses on first launch) 
    /// Call this in app Delegate did launch with options and exit early (return false) in app delegate if this method returns true 
    /// 
    /// - parameter forLaunchOptions: The [NSObject: AnyObject]? launch options to pass in 
    /// - returns: Bool 
    func handledShortcutItemPress(forLaunchOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 

     guard let launchOptions = launchOptions, let shortcutItem = launchOptions[UIApplicationLaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem else { return false } 

     handledShortcutItemPress(forItem: shortcutItem) 
     return true 
    } 

    /// Handle shortcut item press 
    /// Call this in the completion handler in AppDelegate perform action for shortcut item method 
    /// 
    /// - parameter forItem: The UIApplicationShortcutItem the press was handled for. 
    /// - returns: Bool 
    func handledShortcutItemPress(forItem shortcutItem: UIApplicationShortcutItem) -> Bool { 
     guard let _ = ShortcutItemIdentifier(fullType: shortcutItem.type) else { return false } 
     guard let shortcutType = shortcutItem.type as String? else { return false } 

     switch shortcutType { 

     case ShortcutItemIdentifier.first.type: 
      delegate?.shortcutItem1Pressed() 

     case ShortcutItemIdentifier.second.type: 
      delegate?.shortcutItem2Pressed() 

     case ShortcutItemIdentifier.third.type: 
      delegate?.shortcutItem3Pressed() 

     case ShortcutItemIdentifier.fourth.type: 
      delegate?.shortcutItem4Pressed() 

     default: 
      return false 
     } 

     return true 
    } 
} 

ответ

1

Ваш код не работает, потому что в вашем приложении делегатом создать новый экземпляр GameViewController вместо ссылки на текущий

let gameViewController = GameViewController() // creates new instance 

Я делаю именно то, что вы пытаетесь сделать с помощью 3d touch быстрых действий в двух моих играх. Я непосредственно загружаю сцену из приложения appDelegate, не пытайтесь изменить сцену gameViewController для этого.

Для этого я использую многоразовый помощник. Предполагая, что вы настроили все правильно в своем info.plist. (Я использую маленькие буквы в перечислении, чтобы заканчивать ваши элементы с помощью .first, .second и т. Д. В info.plist), удалите весь код делегирования вашего приложения, который вы ранее использовали для быстрых действий с 3D-касанием. . Создайте новый .swift-файл в своем проекте и добавьте этот код.

Это быстрый код.

import UIKit 

/// Shortcut item delegate 
protocol ShortcutItemDelegate: class { 
    func shortcutItemDidPress(_ identifier: ShortcutItemIdentifier) 
} 

/// Shortcut item identifier 
enum ShortcutItemIdentifier: String { 
    case first // I use swift 3 small letters so you have to change your spelling in the info.plist 
    case second 
    case third 
    case fourth 

    private init?(fullType: String) { 
      guard let last = fullType.componentsSeparatedByString(".").last else { return nil } 
      self.init(rawValue: last) 
     } 

     public var type: String { 
      return (Bundle.main.bundleIdentifier ?? "NoBundleIDFound") + ".\(rawValue)" 
     } 
    } 

    /// Shortcut item protocol 
    protocol ShortcutItem { } 
    extension ShortcutItem { 

    // MARK: - Properties 

    /// Delegate 
    private weak var delegate: ShortcutItemDelegate? { 
     return self as? ShortcutItemDelegate 
    } 

    // MARK: - Methods 

func didPressShortcutItem(withOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 
    guard let shortcutItem = launchOptions?[.shortcutItem] as? UIApplicationShortcutItem else { return false } 
    didPressShortcutItem(shortcutItem) 
    return true 
} 


/// Handle item press 
@discardableResult 
func didPressShortcutItem(_ shortcutItem: UIApplicationShortcutItem) -> Bool { 
    guard let _ = ShortcutItemIdentifier(fullType: shortcutItem.type) else { return false } 

    switch shortcutItem.type { 

    case ShortcutItemIdentifier.first.type: 
     delegate?.shortcutItemDidPress(.first) 

    case ShortcutItemIdentifier.second.type: 
     delegate?.shortcutItemDidPress(.second) 

    case ShortcutItemIdentifier.third.type: 
     delegate?.shortcutItemDidPress(.third) 

    case ShortcutItemIdentifier.fourth.type: 
     delegate?.shortcutItemDidPress(.fourth) 

    default: 
     return false 
    } 

    return true 
    } 
} 

чем в делегат своего приложения создать расширение с помощью этого метода (вы пропустили это в коде)

extension AppDelegate: ShortcutItem { 

    /// Perform action for shortcut item. This gets called when app is active 
    func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) { 
     completionHandler(didPressShortcutItem(shortcutItem)) 
    } 

Чем вам нужно настроить метод didFinishLaunchingWithOptions в вашем AppDelegate, чтобы выглядеть следующим образом

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 
    // Override point for customization after application launch. 

    ... 

    return !didPressShortcutItem(withOptions: launchOptions) 
} 

И чем, наконец, создать еще одно продление, подтверждающее на ShortcutItem делегат

extension AppDelegate: ShortcutItemDelegate { 

    func shortcutItemDidPress(_ identifier: ShortcutItemIdentifier) { 

    switch identifier { 
    case .first: 
     let scene = GameScene(size: CGSize(width: 1024, height: 768)) 
     loadScene(scene, view: window?.rootViewController?.view) 
    case .second: 
     // 
    case .third: 
     // 
    case .fourth: 
     // 
    } 
} 

func loadScene(scene: SKScene?, view: UIView?, scaleMode: SKSceneScaleMode = .aspectFill) { 
    guard let scene = scene else { return } 
    guard let skView = view as? SKView else { return } 

    skView.ignoresSiblingOrder = true 
    #if os(iOS) 
     skView.isMultipleTouchEnabled = true 
    #endif 
    scene.scaleMode = scaleMode 
    skView.presentScene(scene) 
    } 
} 

Метод сцены загрузки, который у меня обычно есть в другом помощнике, поэтому я передаю представление в func.

Надеюсь, это поможет.

+0

Awesome. Извините за беспокойство, это была всего лишь синтаксис 3. Пожалуйста, вы можете отметить мой ответ. Я не могу вспомнить, почему я использую таймер. Если вам не нравится задержка, попробуйте сократить время или вообще не использовать один. – crashoverride777

+0

Я бы переделал ваши другие сцены, чтобы использовать AspectFill, даже если это означает, что вам придется переделать много работы. Поверьте мне, мои 2 игры, о которых я говорил, действительно использовали ResizeFill, прежде чем я его изменил. Это был кошмар, чтобы сделать его последовательным на всех устройствах. – crashoverride777

+1

Добро пожаловать. Просто, чтобы вернуться к сценарию масштабирования, вы поблагодарите мою связку в будущем, если вы не используете ResizeFill. Вы можете проверить это очень просто. Создайте новый шаблон Xcode Game. Используя настройки по умолчанию, если вы запустите проект, ярлык HelloWorld отлично масштабируется на всех iPhone (5, 6, 6Plus). Теперь перейдите в GameViewController и измените режим масштабирования на ResizeFill и запустите на всех устройствах. Вы заметите, что на всех устройствах он не выглядит одинаково. Я использовал помощника, чтобы сделать это вручную, помните, что это также включает такие вещи, как физические импульсы. Это было безумие – crashoverride777