将 GameViewController.swift 链接到 GameScene.swift
Posted
技术标签:
【中文标题】将 GameViewController.swift 链接到 GameScene.swift【英文标题】:linking GameViewController.swift to GameScene.swift 【发布时间】:2016-11-18 01:14:44 【问题描述】:我在 main.storyboard 上创建了一个 UI 元素,我需要隐藏它,直到游戏结束并且一旦玩家点击屏幕即可关闭。 Main.storyboard 链接到 GameViewController,因此我所有的 IBOutlets 和 IBAction 都在其中,我所有的游戏代码都在 GameScene 中。我如何将视图控制器链接到场景,因为弹出图像和按钮仅在游戏结束时出现。非常感谢一些帮助,我已经坚持了很长一段时间了。
【问题讨论】:
这是 Apple 宣传的 SpriteKit 所认为的“易用性”的一个基本问题。使用起来并不容易,需要深刻理解的东西有几十个。我希望我能提供帮助,但我仍在努力探索在游戏世界中的场景、视图、视图控制器以及方法和实例之间拥有/查看/交谈的所有方式。所以不要惊慌,这似乎并不立即显而易见,并花时间阅读 CrashOverRide 和这里的其他一些人,因为他们知道很多,甚至不知道他们知道多少。对他们来说很容易。不知何故 @Confused 谢谢你,我很沮丧,失去了希望。我希望它会点击! CrashOverRides 方法似乎是最好的方法。我已经设法让按钮在屏幕上显示为 SKSprite 节点,同时我的游戏弹出,只是努力让共享功能工作以允许用户在社交媒体上发帖。 @Confused 检查我对这个问题的回答,尤其是前几段。希望这可以帮助您在基本层面上了解 ViewController、SKScene 之间的区别以及何时使用它们。 【参考方案1】:这似乎是人们在使用 SpriteKit 游戏时经常遇到的问题,所以让我们来看看 SpriteKit 游戏和 UIKit 应用程序之间的区别。
当你制作一个常规的 UIKit 应用程序时,例如YouTube、Facebook,您将为您看到的每个屏幕/菜单(主屏幕、频道屏幕、订阅频道屏幕等)使用 ViewControllers、CollectionViews、Views 等。因此,您可以为此使用 UIKit API,例如 UIButtons、UIImageViews、UILabels、UIViews、UICollectionViews 等。为了直观地做到这一点,我们将使用故事板。
另一方面,在 SpriteKit 游戏中,它的工作方式有所不同。您为您看到的每个屏幕(MenuScene、SettingsScene、GameScene、GameOverScene 等)使用 SKScene,并且只有 1 个 ViewController (GameViewController)。包含 SKView 的 GameViewController 将呈现您的所有 SKScene。
因此,我们应该使用 SpriteKit API(例如 SKLabelNodes、SKSpriteNodes、SKNodes 等)直接将我们的 UI 添加到相关的 SKScene 中。要直观地做到这一点,我们将使用 SpriteKit 场景关卡编辑器而不是故事板。
所以一般逻辑是像往常一样从 GameViewController 加载您的第一个 SKScene,而不是从相关的 SKScene 中加载其余部分。除了默认代码之外,您的 GameViewController 基本上应该没有代码。您还可以非常轻松地从一个场景过渡到另一个场景(GameScene -> GameOverScene)。
如果您将 GameViewController 用于您的 UI,如果您有多个 SKScene,它会很快变得混乱,因为 UI 将被添加到 GameViewController 并因此添加到所有 SKScene。因此,当您在场景之间转换时,您将不得不删除/显示 UI,这将是疯狂的。
要在 SpriteKit 中添加标签,应该是这样的
class GameScene: SKScene
lazy var scoreLabel: SKLabelNode =
let label = SKLabelNode(fontNamed: "HelveticaNeue")
label.text = "SomeText"
label.fontSize = 22
label.fontColor = .yellow
label.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
return label
()
override func didMove(to view: SKView)
addChild(scoreLabel)
要制作按钮,您实际上是创建一个 SKSpriteNode 并为其命名,然后在 touchesBegan 或 touchesEnded 中查找它,并在其上运行 SKAction 以获取动画和一些代码。
enum ButtonName: String
case play
case share
class GameScene: SKScene
lazy var shareButton: SKSpriteNode =
let button = SKSpriteNode(imageNamed: "ShareButton")
button.name = ButtonName.share.rawValue
button.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
return button
()
override func didMove(to view: SKView)
addChild(shareButton)
/// Touches began
override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
for touch in touches
let location = touch.location(in: self)
let node = atPoint(location)
if let nodeName = node.name
switch nodeName
case ButtonName.play.rawValue:
// run some SKAction animation and some code
case ButtonName.share.rawValue:
let action1 = SKAction.scale(to: 0.9, duration: 0.2)
let action2 = SKAction.scale(to: 1, duration: 0.2)
let action3 = SKAction.run [weak self] in
self?.openShareMenu(value: "\(self!.score)", image: nil) // image is nil in this example, if you use a image just create a UIImage and pass it into the method
let sequence = SKAction.sequence([action1, action2, action3])
node.run(sequence)
default:
break
为了让这更容易,我会创建一个按钮帮助类,一个简单的例子看看这个 https://nathandemick.com/2014/09/buttons-sprite-kit-using-swift/
您还可以查看 Apple 的示例游戏 DemoBots,了解功能更丰富的示例。
这样您就可以在帮助类中包含动画等内容,而不必为每个按钮重复代码。
为了分享,我实际上会使用 UIActivityController 而不是那些可能很快就会被弃用的旧社交 API。这也允许您通过 1 个 UI 共享到多个服务,并且您的应用中也只需要 1 个共享按钮。在您调用它的 SKScene 中,它可能是一个像这样的简单函数。
func openShareMenu(value: String, image: UIImage?)
guard let view = view else return
// Activity items
var activityItems = [AnyObject]()
// Text
let text = "Can you beat my score " + value
activityItems.append(text as AnyObject)
// Add image if valid
if let image = image
activityItems.append(image)
// Activity controller
let activityController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
// iPad settings
if Device.isPad
activityController.popoverPresentationController?.sourceView = view
activityController.popoverPresentationController?.sourceRect = CGRect(x: view.bounds.midX, y: view.bounds.midY, width: 0, height: 0)
activityController.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.init(rawValue: 0)
// Excluded activity types
activityController.excludedActivityTypes = [
UIActivityType.airDrop,
UIActivityType.print,
UIActivityType.assignToContact,
UIActivityType.addToReadingList,
]
// Present
view.window?.rootViewController?.present(activityController, animated: true)
然后在按下正确的按钮时调用它(参见上面的示例)
openShareMenu(value: "\(self.score)", image: SOMEUIIMAGE)
希望对你有帮助
【讨论】:
如果我将 gameOverPopUp 创建为 SKSpriteNode,我可以让它出现并以我想要的方式消失,但是如何在按下按钮时添加一个动作?就像按下 a 按钮时 IBAction 运行一样,我如何使用 SpriteNodes 实现相同的效果? 是的,你应该为你的 gameOver 弹出菜单使用 SKNodes/SKSpriteNodes。要添加按钮,您只需将精灵添加到 gameOverMenu 并在 touches 中查找它们开始查看按钮是否被按下,然后运行 SKAction 对其进行动画处理。更好的是创建一个按钮帮助类来为你管理这个,一个简单的例子是nathandemick.com/2014/09/buttons-sprite-kit-using-swift 对于一个功能更丰富的例子,你应该看看苹果游戏 DemoBots。 我可以运行 SKAction 在 facebook 和 twitter 上发帖吗?这就是我在 ViewController 中创建 IBAction 的原因,因为在社交网络上发布使用帖子更容易 我实际上不会使用这些 API,它们比较老。对于共享,您现在应该使用 UIActivityController,您可以在其中使用 1 个 UI 共享到多个服务,并且您也只需要 1 个按钮。所以一般的想法是运行 SKAction 以在按下按钮时为您的按钮设置动画,而不是在动画完成时运行代码以呈现 UIActivityController。有很多关于 UIActivityController 的教程,只需 google 即可。要在 SpriteKit 场景中呈现诸如 UIActivityController 之类的 ViewController,您可以说 this view?.window?.rootViewController.present(...)。 我已经用更多细节更新了我的答案,包括 UIActivityController 示例。告诉我进展如何【参考方案2】:像这样在 GameScene 类中创建 GameViewController 的引用
class GameScene: SKScene, SKPhysicsContactDelegate
var referenceOfGameViewController : GameViewController!
在 GameViewController 中这样传递引用
class GameViewController: UIViewController
override func viewDidLoad()
super.viewDidLoad()
if let view = self.view as! SKView?
// Load the SKScene from 'GameScene.sks'
if let scene = GameScene(fileNamed: "GameScene")
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
scene.referenceOfGameViewController = self
// Present the scene
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
通过使用这一行,您可以传递对 GameScene 类的引用
scene.referenceOfGameViewController = self
现在在 GameScene 类中,您可以像这样访问 GameViewController 的所有变量
referenceOfGameViewController.fbButton.hidden = false
referenceOfGameViewController.gameOverPopUP.hidden = false
【讨论】:
当我添加:var referenceOfGameViewController = GameViewController!错误说:类型名称后的预期成员名称或构造函数调用。对于这一行:scene.referenceOfGameViewController = self 我得到错误 SKScene 类型的值没有成员'referenceOfGameViewController' 添加 var referenceOfGameViewController : GameViewController! 不要写 var referenceOfGameViewController = GameViewController!写 var referenceOfGameViewController : GameViewController! 在 GameViewController.swift 中我仍然收到一条错误消息,提示“SKScene”类型的值没有成员“referenceGameViewController”以上是关于将 GameViewController.swift 链接到 GameScene.swift的主要内容,如果未能解决你的问题,请参考以下文章
Javascript 将正则表达式 \\n 替换为 \n,将 \\t 替换为 \t,将 \\r 替换为 \r 等等