我在main.storyboard上创建了一个UI元素,我需要将其隐藏起来,直到游戏结束,玩家点击屏幕才能解散。 Main.storyboard链接到GameViewController,因为我的所有IBOutlets和IBActions都在那里,我的所有游戏代码都在GameScene中。如何将视图控制器链接到场景,以便弹出图像和按钮仅在游戏结束时出现。非常感谢一些帮助,我已经坚持了很长一段时间了。
答案 0 :(得分:5)
这似乎是人们对SpriteKit游戏的一个常见问题,所以让我们来看看SpriteKit游戏和UIKit应用程序之间的区别。
制作常规UIKit应用时,例如YouTube,Facebook,您可以为您看到的每个屏幕/菜单使用ViewControllers,CollectionViews,Views等(主屏幕,频道屏幕,订阅频道屏幕等)。所以你可以使用UIKit API,如UIButtons,UIImageViews,UILabels,UIViews,UICollectionViews等。为了做到这一点,我们会使用故事板。
另一方面,在SpriteKit游戏中它的工作方式不同。您可以使用SKScenes查看您看到的每个屏幕(MenuScene,SettingsScene,GameScene,GameOverScene等),并且只有1个ViewController(GameViewController)。 GameViewController中有一个SKView,它将呈现你所有的SKScenes。
因此,我们应该使用SpriteKit API(例如SKLabelNodes,SKSpriteNodes,SKNodes等)直接在相关的SKScenes中添加我们的UI。为了实现这一点,我们将使用SpriteKit场景级别编辑器而不是故事板。
因此,一般的逻辑是从GameViewController中照常装载你的第一个SKScene,而不是从相关的SKScenes中完成其余的。除了默认代码之外,你的GameViewController基本上应该没有代码。您也可以非常轻松地从1个场景转换到另一个场景(GameScene - > GameOverScene)。
如果您的UI使用GameViewController,如果您有多个SKScenes,它会很快变得混乱,因为UI将被添加到GameViewController,因此将添加到所有SKScenes。所以你必须在场景之间转换时删除/显示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)
希望这有帮助
答案 1 :(得分: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