【问题标题】:Create Button in SpriteKit: Swift在 SpriteKit 中创建按钮:Swift
【发布时间】:2016-11-06 15:04:13
【问题描述】:

我想在SpriteKitSKScene 中创建一个按钮,将视图发送到另一个视图控制器。

我尝试使用“performSegue with identifier”,但显然SKScene 不支持这一点。 如何使用SpriteKit 创建一个将视图发送到另一个视图的按钮?

这是我尝试用来执行此操作的代码。

带有“HomeButton.prepareForSegueWithIdentifier()”的行只是一个例子。它实际上不会让我添加“prepareForSegue”部分,它不支持它

class GameOverScene: SKScene {

     var HomeButton: SKNode! = nil


    init(size: CGSize, won: Bool) {
        super.init(size: size)

        backgroundColor = SKColor.whiteColor()

        HomeButton = SKSpriteNode(color: SKColor.blueColor(), size: CGSize(width: 100, height: 100))
        HomeButton.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
        HomeButton.userInteractionEnabled = true
        self.addChild(HomeButton)

        let message = won ? "You Won!" : "You Lose!"





        let label = SKLabelNode(fontNamed: "Title 1")
        label.text = message
        label.fontSize = 40
        label.fontColor = SKColor.blackColor()
        label.position = CGPoint(x: size.width/2, y: size.height/2)
        addChild(label)

        runAction(SKAction.sequence([SKAction.waitForDuration(3.0), SKAction.runBlock() {
            let reveal = SKTransition.flipHorizontalWithDuration(0.5)
            let scene = GameScene(size: size)
            self.view?.presentScene(scene, transition: reveal)
        }
        ]))


    }

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        for touch: AnyObject in touches {
            let location = touch.locationInNode(self)

            if HomeButton.containsPoint(location) {

                HomeButton.prepareForSegueWithIdentifier()

            }
        }
    }

注意:我尝试过使用按钮,但它们在 SKScene 中不起作用。

如有任何疑问,我会及时回复。

【问题讨论】:

  • 对我来说照常工作,所以我不知道您对此有何问题?
  • 你能解释一下你试图做什么
  • 嘿,如果您能发布一个您尝试过的示例并且有人可以帮助您找出哪些不起作用,那就太好了。

标签: ios swift sprite-kit skscene


【解决方案1】:

我已经翻译了 Alessandro Ornano 对 Swift 3.1 的回答:

import SpriteKit

class FTButtonNode: SKSpriteNode {

enum FTButtonActionType: Int {
    case TouchUpInside = 1,
    TouchDown, TouchUp
}

var isEnabled: Bool = true {
    didSet {
        if (disabledTexture != nil) {
            texture = isEnabled ? defaultTexture : disabledTexture
        }
    }
}
var isSelected: Bool = false {
    didSet {
        texture = isSelected ? selectedTexture : defaultTexture
    }
}

var defaultTexture: SKTexture
var selectedTexture: SKTexture
var label: SKLabelNode

required init(coder: NSCoder) {
    fatalError("NSCoding not supported")
}

init(normalTexture defaultTexture: SKTexture!, selectedTexture:SKTexture!, disabledTexture: SKTexture?) {
    
    self.defaultTexture = defaultTexture
    self.selectedTexture = selectedTexture
    self.disabledTexture = disabledTexture
    self.label = SKLabelNode(fontNamed: "Helvetica");
    
    super.init(texture: defaultTexture, color: UIColor.white, size: defaultTexture.size())
    isUserInteractionEnabled = true
    
    //Creating and adding a blank label, centered on the button
    self.label.verticalAlignmentMode = SKLabelVerticalAlignmentMode.center;
    self.label.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.center;
    addChild(self.label)
    
    // Adding this node as an empty layer. Without it the touch functions are not being called
    // The reason for this is unknown when this was implemented...?
    let bugFixLayerNode = SKSpriteNode(texture: nil, color: UIColor.clear, size: defaultTexture.size())
    bugFixLayerNode.position = self.position
    addChild(bugFixLayerNode)
    
}

/**
 * Taking a target object and adding an action that is triggered by a button event.
 */
func setButtonAction(target: AnyObject, triggerEvent event:FTButtonActionType, action:Selector) {
    
    switch (event) {
    case .TouchUpInside:
        targetTouchUpInside = target
        actionTouchUpInside = action
    case .TouchDown:
        targetTouchDown = target
        actionTouchDown = action
    case .TouchUp:
        targetTouchUp = target
        actionTouchUp = action
    }
    
}

/*
 New function for setting text. Calling function multiple times does
 not create a ton of new labels, just updates existing label.
 You can set the title, font type and font size with this function
 */

func setButtonLabel(title: NSString, font: String, fontSize: CGFloat) {
    self.label.text = title as String
    self.label.fontSize = fontSize
    self.label.fontName = font
}

var disabledTexture: SKTexture?
var actionTouchUpInside: Selector?
var actionTouchUp: Selector?
var actionTouchDown: Selector?
weak var targetTouchUpInside: AnyObject?
weak var targetTouchUp: AnyObject?
weak var targetTouchDown: AnyObject?

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if (!isEnabled) {
        return
    }
    isSelected = true
    if (targetTouchDown != nil && targetTouchDown!.responds(to: actionTouchDown)) {
        UIApplication.shared.sendAction(actionTouchDown!, to: targetTouchDown, from: self, for: nil)
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    
    if (!isEnabled) {
        return
    }
    
    let touch: AnyObject! = touches.first
    let touchLocation = touch.location(in: parent!)
    
    if (frame.contains(touchLocation)) {
        isSelected = true
    } else {
        isSelected = false
    }
    
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    if (!isEnabled) {
        return
    }
    
    isSelected = false
    
    if (targetTouchUpInside != nil && targetTouchUpInside!.responds(to: actionTouchUpInside!)) {
        let touch: AnyObject! = touches.first
        let touchLocation = touch.location(in: parent!)
        
        if (frame.contains(touchLocation) ) {
            UIApplication.shared.sendAction(actionTouchUpInside!, to: targetTouchUpInside, from: self, for: nil)
        }
        
    }
    
    if (targetTouchUp != nil && targetTouchUp!.responds(to: actionTouchUp!)) {
        UIApplication.shared.sendAction(actionTouchUp!, to: targetTouchUp, from: self, for: nil)
    }
}

}

用法:

@objc func buttonTap() {
    print("Button pressed")
}

override func didMove(to view: SKView)
{
    backgroundColor = SKColor.white
    let buttonTexture: SKTexture! = SKTexture(imageNamed: "button")
    let buttonTextureSelected: SKTexture! = SKTexture(imageNamed: "buttonSelected.png")
    let button = FTButtonNode(normalTexture: buttonTexture, selectedTexture: buttonTextureSelected, disabledTexture: buttonTexture)
    button.setButtonAction(target: self, triggerEvent: .TouchUpInside, action: #selector(GameScene.buttonTap))
    button.setButtonLabel(title: "Button", font: "Arial", fontSize: 12)
    button.position = CGPoint(x: self.frame.midX,y: self.frame.midY)
    button.zPosition = 1
    button.name = "Button"
    self.addChild(button)
}

我创建了两个.png:

【讨论】:

    【解决方案2】:

    最简单但质量可能不是最高的解决方案是使用包含图像的 SpriteNode 并为其命名。稍后,使用该场景,您可以轻松对其进行编程,以便在点击时将用户转移到下一个场景:

    class GameScene: SKScene {
       let button = SKSpriteNode(imageNamed: "yourImgName")
    
       override func didMoveToView(view: SKView) {
          button.name = "btn"
          button.size.height = 100
          button.size.width = 100
          button.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) + 50)
          self.addChild(button)
    
          //Adjust button properties (above) as needed
          }
    
       override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
          let touch = touches.first
          let positionInScene = touch!.locationInNode(self)
          let touchedNode = self.nodeAtPoint(positionInScene)
    
        if let name = touchedNode.name {
            if name == "btn" {
    
                let yourNextScene = YourNextScene(fileNamed: "YourNextScene")
                self.view?.presentScene(yourNextScene!)
    
              }
          }
       }
    }
    

    不要忘记将“YourNextScene”替换为下一个场景的实际名称。

    【讨论】:

      【解决方案3】:

      如果你需要在SpriteKit中创建一个按钮,我认为这个按钮必须有全部或部分可用的动作来做任何你想做的事情(就像UIButton所做的那样)

      在这里你可以找到一个简单的类来构建一个 SpriteKit 按钮,叫做 FTButtonNode:

      class FTButtonNode: SKSpriteNode {
      
          enum FTButtonActionType: Int {
              case TouchUpInside = 1,
              TouchDown, TouchUp
          }
      
          var isEnabled: Bool = true {
              didSet {
                  if (disabledTexture != nil) {
                      texture = isEnabled ? defaultTexture : disabledTexture
                  }
              }
          }
          var isSelected: Bool = false {
              didSet {
                  texture = isSelected ? selectedTexture : defaultTexture
              }
          }
      
          var defaultTexture: SKTexture
          var selectedTexture: SKTexture
          var label: SKLabelNode
      
          required init(coder: NSCoder) {
              fatalError("NSCoding not supported")
          }
      
          init(normalTexture defaultTexture: SKTexture!, selectedTexture:SKTexture!, disabledTexture: SKTexture?) {
      
              self.defaultTexture = defaultTexture
              self.selectedTexture = selectedTexture
              self.disabledTexture = disabledTexture
              self.label = SKLabelNode(fontNamed: "Helvetica");
      
              super.init(texture: defaultTexture, color: UIColor.whiteColor(), size: defaultTexture.size())
              userInteractionEnabled = true
      
              //Creating and adding a blank label, centered on the button
              self.label.verticalAlignmentMode = SKLabelVerticalAlignmentMode.Center;
              self.label.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Center;
              addChild(self.label)
      
              // Adding this node as an empty layer. Without it the touch functions are not being called
              // The reason for this is unknown when this was implemented...?
              let bugFixLayerNode = SKSpriteNode(texture: nil, color: UIColor.clearColor(), size: defaultTexture.size())
              bugFixLayerNode.position = self.position
              addChild(bugFixLayerNode)
      
          }
      
          /**
           * Taking a target object and adding an action that is triggered by a button event.
           */
          func setButtonAction(target: AnyObject, triggerEvent event:FTButtonActionType, action:Selector) {
      
              switch (event) {
              case .TouchUpInside:
                  targetTouchUpInside = target
                  actionTouchUpInside = action
              case .TouchDown:
                  targetTouchDown = target
                  actionTouchDown = action
              case .TouchUp:
                  targetTouchUp = target
                  actionTouchUp = action
              }
      
          }
      
          /*
          New function for setting text. Calling function multiple times does
          not create a ton of new labels, just updates existing label.
          You can set the title, font type and font size with this function
          */
      
          func setButtonLabel(title: NSString, font: String, fontSize: CGFloat) {
              self.label.text = title as String
              self.label.fontSize = fontSize
              self.label.fontName = font
          }
      
          var disabledTexture: SKTexture?
          var actionTouchUpInside: Selector?
          var actionTouchUp: Selector?
          var actionTouchDown: Selector?
          weak var targetTouchUpInside: AnyObject?
          weak var targetTouchUp: AnyObject?
          weak var targetTouchDown: AnyObject?
      
          override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
              if (!isEnabled) {
                  return
              }
              isSelected = true
              if (targetTouchDown != nil && targetTouchDown!.respondsToSelector(actionTouchDown!)) {
                  UIApplication.sharedApplication().sendAction(actionTouchDown!, to: targetTouchDown, from: self, forEvent: nil)
              }
          }
      
          override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
      
              if (!isEnabled) {
                  return
              }
      
              let touch: AnyObject! = touches.first
              let touchLocation = touch.locationInNode(parent!)
      
              if (CGRectContainsPoint(frame, touchLocation)) {
                  isSelected = true
              } else {
                  isSelected = false
              }
      
          }
      
          override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
              if (!isEnabled) {
                  return
              }
      
              isSelected = false
      
              if (targetTouchUpInside != nil && targetTouchUpInside!.respondsToSelector(actionTouchUpInside!)) {
                  let touch: AnyObject! = touches.first
                  let touchLocation = touch.locationInNode(parent!)
      
                  if (CGRectContainsPoint(frame, touchLocation) ) {
                      UIApplication.sharedApplication().sendAction(actionTouchUpInside!, to: targetTouchUpInside, from: self, forEvent: nil)
                  }
      
              }
      
              if (targetTouchUp != nil && targetTouchUp!.respondsToSelector(actionTouchUp!)) {
                  UIApplication.sharedApplication().sendAction(actionTouchUp!, to: targetTouchUp, from: self, forEvent: nil)
              }
          }
      
      }
      

      来源在this Gist

      用法

      let backTexture: SKTexture! = SKTexture(image:"backBtn.png")
      let backTextureSelected: SKTexture! = SKTexture(image:"backSelBtn.png")  
      let backBtn = FTButtonNode(normalTexture: backTexture, selectedTexture: backTextureSelected, disabledTexture: backTexture,size:backTexture.size())
      backBtn.setButtonAction(self, triggerEvent: .TouchUpInside, action: #selector(GameScene.backBtnTap))
      backBtn.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame))
      backBtn.zPosition = 1
      backBtn.name = "backBtn"
      self.addChild(backBtn)
      
      func backBtnTap() {
          print("backBtnTap tapped")
          // Here for example you can do:
          let transition = SKTransition.fadeWithDuration(0.5)
          let nextScene = MenuScene(size: self.scene!.size)
          nextScene.scaleMode = .ResizeFill
          self.scene?.view?.presentScene(nextScene, transition: transition)
      }
      

      【讨论】:

      • 我可以将它发送到 viewController,而不是另一个 SKScene 吗?
      • 当然,我的回答只是一个例子,如果你不知道怎么看这个链接stackoverflow.com/a/30041939/1894067
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      • 2016-08-01
      • 2015-03-31
      • 1970-01-01
      • 2017-06-01
      相关资源
      最近更新 更多