在 SKSpriteNode 上设置 TVOS 中的首选焦点?

Setting preferred focus in TVOS on an SKSpriteNode?

由于我在 SpriteKit 中工作,我的按钮是 SKSpriteNodes...但是我发现自己处于需要通过覆盖 [=13= 来设置 viewController 中的焦点的情况].有没有办法将 SKSpriteNode 向下转换为 UIView?如果是这样,我还没有弄清楚……还有其他选择吗?

        let playButton = SKSpriteNode(imageNamed: "PlayButton")
        playButton.position = CGPoint(x: scene.size.width * 0.25, y: scene.size.height * 0.25)
        playButton.zPosition = Layer.UI.rawValue
        scene.worldNode.addChild(playButton)

override var preferredFocusedView: UIView? {
    get {
        return //playButton how? 
    }
}

现在仅 tvOS 10 和 SpriteKit 支持焦点导航,在此之前,您必须使用自己的焦点系统手动完成。出于这个原因,首选焦点视图已被弃用,因为它仅支持 UIViews。您现在应该改用首选焦点环境。

您要做的第一件事是在 GameViewController 中将首选焦点环境设置为当前呈现的 SKScene。这实质上意味着您的 SKScenes 将处理首选焦点而不是 GameViewController。在 SpriteKit 游戏中,SKScenes 应该处理 UI,例如使用 SpriteKit API 的按钮,例如 SKLabelNodes、SKSpriteNodes 等。因此您需要将首选焦点传递给 SKScene。

class GameViewController: UIViewController {

      override func viewDidLoad() {
           super.viewDidLoad()

           // default code to present your 1st SKScene.
      }
}

#if os(tvOS)
extension GameViewController {

      /// Tell GameViewController that the currently presented SKScene should always be the preferred focus environment
      override var preferredFocusEnvironments: [UIFocusEnvironment] {
           if let scene = (view as? SKView)?.scene {
               return [scene]
           } 
           return []
      }
 }
 #endif

您的 playButton 应该是 SKSpriteNode 的子类,您将在游戏中使用它作为所有按钮。使用枚举并给它们不同的名称/标识符以在它们被按下时区分它们(查看 Apple 示例游戏 DemoBots)。

 class Button: SKSpriteNode {

      var isFocusable = true // easy way to later turn off focus for your buttons e.g. when overlaying menus etc.

      /// Can become focused
      override var canBecomeFocused: Bool {
          return isFocusable
      }

      /// Did update focus
      override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {

          if context.previouslyFocusedItem === self {
              // SKAction to reset focus animation for unfocused button
          }

          if context.nextFocusedItem === self {
               // SKAction to run focus animation for focused button
          }
      }
 }

在您的 SKScenes 中,您可以将焦点环境设置为您的播放按钮或其他 UI。

例如开始场景

class StartScene: SKScene {
   ....
}

#if os(tvOS)
extension StartScene {
      override var preferredFocusEnvironments: [UIFocusEnvironment] {
          return [playButton]
     }
}
#endif

例如 GameScene(例如在需要时将焦点转移到游戏菜单)

class GameScene: SKScene {
   ....
}

#if os(tvOS)
extension GameScene {

      override var preferredFocusEnvironments: [UIFocusEnvironment] {
         if isGameMenuShowing { // add some check like this
             return [gameMenuNode]
         }
         return []
     }    
}
#endif

当您在 SKScenes 之间转换时(例如 StartScene -> GameScene),您还必须告诉您的 GameViewController 更新其焦点环境。如果您使用 SKTransitions,这一点尤其重要,我花了一段时间才弄明白。如果你使用 SKTransitions 而不是新旧场景在转换期间处于活动状态,那么 GameViewController 将使用旧场景首选焦点环境而不是新场景,这意味着新场景将无法正确聚焦。

每次在场景之间转换时,我都会这样做。您必须稍微延迟一下,否则将无法正常工作。

 ...
 view?.presentScene(newScene, transition: ...)

 #if os(tvOS)
    newScene.run(SKAction.wait(forDuration: 0.1)) { // wont work without delay
               newScene.view?.window?.rootViewController?.setNeedsFocusUpdate()
            newScene.view?.window?.rootViewController?.updateFocusIfNeeded()
        }
    #endif

你应该阅读这篇文章

https://medium.com/folded-plane/tvos-10-getting-started-with-spritekit-and-focus-engine-53d8ef3b34f3#.x5zty39pc

并观看名为 "Whats New in SpriteKit" 的 2016 年苹果主题演讲,他们在中途谈论它。

希望对您有所帮助