在 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
你应该阅读这篇文章
并观看名为 "Whats New in SpriteKit" 的 2016 年苹果主题演讲,他们在中途谈论它。
希望对您有所帮助
由于我在 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
你应该阅读这篇文章
并观看名为 "Whats New in SpriteKit" 的 2016 年苹果主题演讲,他们在中途谈论它。
希望对您有所帮助