Swift Spritekit Adding Button Programmatically

Swift Spritekit Adding Button programmatically

Adding a button in SpriteKit and responding to taps on it is not quite as easy as it is in UIKit. You basically need to create an SKNode of some sort which will draw your button and then check to see if touches registered in your scene are within that node's bounds.

A really simple scene with just a single red rectangle in the center acting as a button would look something like this:

import UIKit
import SpriteKit
class ButtonTestScene: SKScene {
var button: SKNode! = nil
override func didMove(to view: SKView) {
// Create a simple red rectangle that's 100x44
button = SKSpriteNode(color: .red, size: CGSize(width: 100, height: 44))
// Put it in the center of the scene
button.position = CGPoint(x:self.frame.midX, y:self.frame.midY);
self.addChild(button)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// Loop over all the touches in this event
for touch in touches {
// Get the location of the touch in this scene
let location = touch.location(in: self)
// Check if the location of the touch is within the button's bounds
if button.contains(location) {
print("tapped!")
}
}
}
}

If you need a button that looks and animates like the ones in UIKit, you'll need to implement that yourself; there's nothing built in to SpriteKit.

How to add a button to sprite-kit programmatically with swift?

The button isn't displayed, because of its position.

e.g, write

button.position = CGPoint(x: size.width / 2, y: size.height / 2)

and the button appears at the center of your SKScene.

I need to add a button to a sprite kit game

every touches in spritekit is handle by SpriteNodes.
so if you need a button to be clicked and do something you have to add a spriteNode on the scene and in touches began method handle the touch event.
there is a complete answer for your question in this thread

Adding Button programmatically

You can use a SPSprintNode as your button and activate it in the touches function. Or you can use a button class to do the work for you. If your using ObjectiveC, there are some great button class examples on Github. If your using Swift they are a little harder to find.
The third and last option is you can use a label and then tell touches to call the button function. Here is an example:

     var button = SKSpriteNode(imageNamed: "button.png")
button.position = CGPoint(x: self.size.width * 0.5, y: self.size.height * 0.5)//center
button.alpha = 1.0//optional
addChild(button)

Then in your Touches Begin put this:

        for touch in touches {
let touchLocation = touch.locationInNode(self)
if (CGRectContainsPoint(button.frame, touchLocation)) {
button.alpha = 0.5//optional
//call function to perform something here.

}

}

Spritekit: passing from UIButtons to buttons as SKSpriteNode

Use SKAction to do this.

In touchesBegan remove setScale(0.9) and self.alpha = 0.5, use :

        let scaleAction = SKAction.scale(to: 0.5, duration: 1)
self.run(scaleAction)

let fadeAction = SKAction.fadeAlpha(to: 0.5, duration: 1)
self.run(fadeAction)

in touchEnded do the same and add:

    self.removeAllActions()
let scaleAction = SKAction.scale(to: 1, duration: 1)
self.run(scaleAction)

let fadeAction = SKAction.fadeAlpha(to: 1, duration: 1)
self.run(fadeAction)

EDIT:

Here a test into a Playground:

Sample Image

Adding Button programmatically

You can use a SPSprintNode as your button and activate it in the touches function. Or you can use a button class to do the work for you. If your using ObjectiveC, there are some great button class examples on Github. If your using Swift they are a little harder to find.
The third and last option is you can use a label and then tell touches to call the button function. Here is an example:

     var button = SKSpriteNode(imageNamed: "button.png")
button.position = CGPoint(x: self.size.width * 0.5, y: self.size.height * 0.5)//center
button.alpha = 1.0//optional
addChild(button)

Then in your Touches Begin put this:

        for touch in touches {
let touchLocation = touch.locationInNode(self)
if (CGRectContainsPoint(button.frame, touchLocation)) {
button.alpha = 0.5//optional
//call function to perform something here.

}

}

How to make text appear on button? -SpriteKit

You always need to add zPosition to your sprites and labels. Otherwise sometimes they will appear and other times they may appear behind the background

//creating the start game programmatically. 
let dw_startButton = SKSpriteNode()
dw_startButton.zPosition = 1
dw_startButton.name = "dw_startbutton"
dw_startButton.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
self.addChild(dw_startButton)

//Instructions Button
let dw_selector = SKSpriteNode()
dw_selector.name = "dw_selector"
dw_selector.zPosition = 1
dw_selector.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
self.addChild(dw_selector)

//Starting text
let startText = SKLabelNode(text: "Play!")
startText.fontColor = UIColor.white
startText.position = CGPoint(x: 50, y: 50)
startText.fontSize = 45
startText.fontName = "Helvetica-Bold"
startText.verticalAlignmentMode = SKLabelVerticalAlignmentMode(rawValue: 1)!
startText.name = "dw_startbutton"
startText.zPosition = 2
dw_startButton.addChild(startText)

//instructions text
let startTexts = SKLabelNode(text: "Insturctions")
startTexts.fontColor = UIColor.white
startTexts.position = CGPoint(x: 0, y: 0)
startTexts.fontSize = 20
startTexts.fontName = "Helvetica-Bold"
startTexts.verticalAlignmentMode = SKLabelVerticalAlignmentMode(rawValue: 1)!
startTexts.name = "dw_selector"
startTexts.zPosition = 2
dw_selector.addChild(startTexts)

//new button
let newButton = SKSpriteNode(imageNamed: "button_back")
newButton.zPosition = 1
newButton.name = "button1"
newButton.position = CGPoint(x: 100, y: 100)
self.addChild(newButton)

let buttonText = SKLabelNode(text: "Play")
buttonText.fontColor = .white
buttonText.fontSize = 20
buttonText.fontName = "Helvetica-Bold"
buttonText.verticalAlignmentMode = .center
buttonText.horizontalAlignmentMode = .center
buttonText.name = "dw_selector"
buttonText.zPosition = 2
newButton.addChild(buttonText)

Creating a button using SKLabelNode as a parent in Swift SpriteKit

I have an alternative solution that would work the same way.
Change the following code

if myButton.containsPoint(location) {

To this and it should compile and have the same functionality

if self.position == location {

Swift 3.0: SKSpriteNode as Button does not work when given a non-SKView parent?

I don't think what you're saying is true. You can detect a touch from a child node. To demonstrate, I just ran a little test code within one of my SpriteKit projects where I detected touch on my camera node

var cameraNode = SKCameraNode()

Then in didMove(to:):

addChild(cameraNode)
camera = cameraNode
camera?.position = CGPoint(x: size.width/2, y: size.height/2)

Detect touch on cameraNode using touchesEnded:

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }

let location = touch.location(in: cameraNode)

print("LocationX: \(location.x), LocationY: \(location.y)")
}

Here was my print out:

LocationX: -13.9129028320312, LocationY: 134.493041992188

To further explain, if you added a button as a child of your cameraNode, you would then do something like this:

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }

let location = touch.location(in: cameraNode)

// Check if tap was within button frame (assuming your buttonNode is named button and a child of cameraNode)
if button.frame.contains(location) {
// Tap was within the frame of the button
// Do whatever is necessary
}
}

Further Edit -

Your problem stems from the node in which you are requesting the touch location. As I mentioned in my answer you need to extrapolate the touch location based on the node within which you're check the sprite's frame. In your edit you are detecting touch only on self, which will then give you coordinates relative to your scene. If you want to detect touch on a subview like the camera node, you need to request the touch location within the camera node. Here is what I'm talking about based on the code you added:

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }

// This will give you touch location from the camera node 'cam' NOT 'self'
let cameraLocation = touch.location(in: cam)

// This will give you touch location from the scene itself
let sceneLocation = touch.location(in: self)

if sprite.contains(sceneLocation) {
print("You tapped the blue sprite")
}

if sprite2.contains(cameraLocation) {
print("You tapped the purple sprite")
}

}

I just tried this and it worked fine for me.



Related Topics



Leave a reply



Submit