web-dev-qa-db-ja.com

SpriteKitでボタンを作成:Swift

SpriteKitまたはSKSceneに、ビューを別のビューコントローラーに送信するボタンを作成します。

「識別子付きのパフォーマンスセグエ」を使用してみましたが、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では機能しません。

混乱があった場合は対応させていただきます。

11
Nick Griffith

SpriteKitにボタンを作成する必要がある場合、このボタンには、(UIButtonとまったく同じように)必要なすべての操作を実行できる必要があると思います。

ここに、FTButtonNodeと呼ばれる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.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)
}
8

Swift 3.1へのAlessandro Ornanoの回答を翻訳しました:

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)
    }
}

}

使用法:

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)
}

2つの.pngを作成しました。

button.pngbuttonSelected

10
laserman

最も単純な解決策ですが、おそらく最高の品質ではありませんが、画像を含む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」を次のシーンの実際の名前に置き換えることを忘れないでください。

5
hb22